Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Significance: patch
Type: changed

Search dashboard: hide the Off row of the new feature-selector on WordPress.com, matching the legacy module control's behaviour.
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { useSelect, useDispatch } from '@wordpress/data';
import { __ } from '@wordpress/i18n';
import { Button, Stack } from '@wordpress/ui';
import { STORE_ID } from 'store';
import { EXPERIENCE_ORDER } from './constants';
import { EXPERIENCE, EXPERIENCE_ORDER } from './constants';
import ExperienceOption from './experience-option';
import './style.scss';

Expand All @@ -25,8 +25,16 @@ export default function FeatureSelector() {
select => select( STORE_ID ).supportsOnlyClassicSearch(),
[]
);
// On WordPress.com, search activation is managed from the .com side, so we
// hide the Off row here to mirror the legacy `<ModuleControl>`'s
// `! isWpcom` gate around the "Enable Jetpack Search" toggle.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Small wording suggestion — and to be clear this isn't your invention, the same loose phrasing lives in the legacy <ModuleControl> comment already. But while we're here:

Helper::is_wpcom() only checks the IS_WPCOM constant, which is defined on Simple sites and not on Atomic/WoA. So in practice an Atomic admin will still see the Off row here. That's actually correct behavior — the legacy <ModuleControl> gate has the same Simple-only meaning, so we're at parity — but a future reader scanning the comment might assume "WordPress.com" includes Atomic and get confused. Mind tightening to something like "On WordPress.com Simple sites" or "where IS_WPCOM is defined"? Just so the Atomic case isn't ambiguous.

const isWpcom = useSelect( select => select( STORE_ID ).isWpcom(), [] );
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tiny style musing, totally take or leave: this brings the component to five useSelect calls. Could batch them into a single call that returns an object — experience-option.jsx:34-40 already does that for two values and reads nicely. Pre-existing pattern in this file though, so happy to leave it for a follow-up if you'd rather keep this PR tight.

const { saveExperience } = useDispatch( STORE_ID );

const visibleExperiences = isWpcom
? EXPERIENCE_ORDER.filter( experience => experience !== EXPERIENCE.OFF )
: EXPERIENCE_ORDER;

const isExperienceDisabled = experience =>
supportsOnlyClassicSearch && ( experience === 'embedded' || experience === 'overlay' );

Expand All @@ -51,7 +59,7 @@ export default function FeatureSelector() {
aria-labelledby="jp-search-feature-selector-heading"
>
<Stack direction="column" gap="sm">
{ EXPERIENCE_ORDER.map( experience => (
{ visibleExperiences.map( experience => (
<ExperienceOption
key={ experience }
experience={ experience }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,4 +91,28 @@ describe( '<FeatureSelector>', () => {
expect( screen.getByRole( 'radio', { name: /theme search/i } ) ).toBeEnabled();
expect( screen.getByRole( 'radio', { name: /off/i } ) ).toBeEnabled();
} );

test( 'hides the Off row on WordPress.com (parity with legacy ModuleControl)', () => {
const registry = createRegistry();
const store = createReduxStore( STORE_ID, {
...storeConfig,
initialState: {
...( storeConfig.initialState || {} ),
jetpackSettings: baseSettings,
siteData: { isWpcom: true },
},
} );
registry.register( store );
render(
<RegistryProvider value={ registry }>
<FeatureSelector />
</RegistryProvider>
);
const radios = screen.getAllByRole( 'radio' );
expect( radios ).toHaveLength( 3 );
expect( screen.getByRole( 'radio', { name: /embedded search/i } ) ).toBeInTheDocument();
expect( screen.getByRole( 'radio', { name: /overlay search/i } ) ).toBeInTheDocument();
expect( screen.getByRole( 'radio', { name: /theme search/i } ) ).toBeInTheDocument();
expect( screen.queryByRole( 'radio', { name: /^off$/i } ) ).not.toBeInTheDocument();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One tiny thing on this assertion — the Off radio's accessible name is computed from the whole <label>, so it actually ends up looking like "Off WordPress default search." (see how <ExperienceOption> lays out the title plus description inside the label, around experience-option.jsx:86-97). That means /^off$/i (anchored, exact-match) won't match even when the row is rendered, so this line would pass regardless of whether the Off row is gone.

The good news: the expect( radios ).toHaveLength( 3 ) above is what's actually proving the row is hidden, so the test is sound. Just this last line ends up being a tautology. If you want the negative assertion to pull its weight, maybe drop the anchors to /off/i (matches the substring form used in the existing tests on lines 37 and 92), or just delete it since the length check has us covered.

} );
} );
Loading