Commit ce223ff13d7 for woocommerce
commit ce223ff13d77a2e0332d3c17cb87afd02731caad
Author: Vlad Olaru <vlad.olaru@automattic.com>
Date: Thu Sep 24 17:59:05 2026 +0300
Revert "[tests] Reduce Local Pickup settings E2E tests from 7 to 2" (#69052)
revert: Revert "[tests] Reduce Local Pickup settings E2E tests from 7 to 2" (#68596)
This reverts commit 0a85984882597ff3e1181dd17b9a653dde7ee82f.
Rubik asked for the E2E migration's test changes in its areas to be
reverted until the team can review them. #68596 is one of the 11 PRs on
the revert list Rubik agreed on 2026-09-24.
The revert brings back the browser tests the PR removed or cut down and
removes the lower-layer tests it added in their place. Only test code
and changelog entries change; nothing ships.
Refs TESTOPS-234
Refs #68596
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
diff --git a/plugins/woocommerce/changelog/testops-234-local-pickup-settings b/plugins/woocommerce/changelog/testops-234-local-pickup-settings
deleted file mode 100644
index 8f333268a3a..00000000000
--- a/plugins/woocommerce/changelog/testops-234-local-pickup-settings
+++ /dev/null
@@ -1,4 +0,0 @@
-Significance: patch
-Type: dev
-Comment: Reduce Local Pickup settings E2E tests from 7 to 2; three Jest suites own the settings screen's logic.
-
diff --git a/plugins/woocommerce/client/blocks/assets/js/extensions/shipping-methods/pickup-location/test/general-settings.tsx b/plugins/woocommerce/client/blocks/assets/js/extensions/shipping-methods/pickup-location/test/general-settings.tsx
deleted file mode 100644
index cc33282b836..00000000000
--- a/plugins/woocommerce/client/blocks/assets/js/extensions/shipping-methods/pickup-location/test/general-settings.tsx
+++ /dev/null
@@ -1,231 +0,0 @@
-/**
- * External dependencies
- */
-import type { ReactNode } from 'react';
-import { act, render, screen } from '@testing-library/react';
-import userEvent from '@testing-library/user-event';
-import { useId as mockUseId } from '@wordpress/element';
-
-/**
- * Internal dependencies
- */
-import GeneralSettings from '../general-settings';
-import { useSettingsContext } from '../settings-context';
-import type { SettingsContextType } from '../types';
-
-jest.mock( '@wordpress/components', () => ( {
- Button: ( { children }: { children: ReactNode } ) => (
- <button type="button">{ children }</button>
- ),
- Card: ( { children }: { children: ReactNode } ) => <div>{ children }</div>,
- CardBody: ( { children }: { children: ReactNode } ) => (
- <div>{ children }</div>
- ),
- CheckboxControl: ( {
- checked,
- label,
- onChange,
- }: {
- checked: boolean;
- label: string;
- onChange: ( checked: boolean ) => void;
- } ) => {
- const id = mockUseId();
- return (
- <>
- <label htmlFor={ id }>{ label }</label>
- <input
- id={ id }
- type="checkbox"
- checked={ checked }
- onChange={ ( event ) => onChange( event.target.checked ) }
- />
- </>
- );
- },
- ExternalLink: ( {
- children,
- href,
- }: {
- children: ReactNode;
- href: string;
- } ) => <a href={ href }>{ children }</a>,
- Notice: ( { children }: { children: ReactNode } ) => (
- <div>{ children }</div>
- ),
- Modal: ( { children }: { children: ReactNode } ) => <div>{ children }</div>,
- SelectControl: ( {
- label,
- onChange,
- options,
- value,
- }: {
- label: string;
- onChange: ( value: string ) => void;
- options: { label: string; value: string }[];
- value: string;
- } ) => {
- const id = mockUseId();
- return (
- <>
- <label htmlFor={ id }>{ label }</label>
- <select
- id={ id }
- value={ value }
- onChange={ ( event ) => onChange( event.target.value ) }
- >
- { options.map( ( option ) => (
- <option key={ option.value } value={ option.value }>
- { option.label }
- </option>
- ) ) }
- </select>
- </>
- );
- },
- TextControl: ( {
- label,
- onChange,
- placeholder,
- type = 'text',
- value,
- }: {
- label: string;
- onChange: ( value: string ) => void;
- placeholder?: string;
- type?: string;
- value: string;
- } ) => {
- const id = mockUseId();
- return (
- <>
- <label htmlFor={ id }>{ label }</label>
- <input
- id={ id }
- type={ type }
- placeholder={ placeholder }
- value={ value }
- onChange={ ( event ) => onChange( event.target.value ) }
- />
- </>
- );
- },
- ToggleControl: () => <input type="checkbox" readOnly />,
-} ) );
-
-jest.mock( '../settings-context', () => ( {
- useSettingsContext: jest.fn(),
-} ) );
-
-const mockUseSettingsContext = useSettingsContext as jest.MockedFunction<
- typeof useSettingsContext
->;
-
-const getContext = (
- overrides: Partial< SettingsContextType > = {}
-): SettingsContextType => ( {
- settings: {
- enabled: true,
- title: '',
- tax_status: 'taxable',
- cost: '',
- },
- readOnlySettings: {
- hasLegacyPickup: false,
- storeCountry: 'US',
- storeState: 'CA',
- },
- setSettingField: jest.fn( () => jest.fn() ),
- pickupLocations: [],
- setPickupLocations: jest.fn(),
- toggleLocation: jest.fn(),
- updateLocation: jest.fn(),
- isSaving: false,
- save: jest.fn(),
- isDirty: false,
- ...overrides,
-} );
-
-describe( 'GeneralSettings', () => {
- it( 'delegates enablement and title changes to their setting fields', async () => {
- const user = userEvent.setup();
- const enabledChanged = jest.fn();
- const titleChanged = jest.fn();
- const setSettingField = jest.fn( ( field ) => {
- return field === 'enabled' ? enabledChanged : titleChanged;
- } );
- mockUseSettingsContext.mockReturnValue(
- getContext( { setSettingField } )
- );
-
- render( <GeneralSettings /> );
-
- await user.click(
- screen.getByRole( 'checkbox', { name: 'Enable local pickup' } )
- );
- const title = screen.getByRole( 'textbox', { name: 'Title' } );
- await user.type( title, 'C' );
-
- expect( setSettingField ).toHaveBeenCalledWith( 'enabled' );
- expect( setSettingField ).toHaveBeenCalledWith( 'title' );
- expect( enabledChanged ).toHaveBeenCalledWith( false );
- expect( titleChanged ).toHaveBeenLastCalledWith( 'C' );
- } );
-
- it( 'shows price controls and clears cost whenever price visibility changes', async () => {
- const user = userEvent.setup();
- const costChanged = jest.fn();
- const taxStatusChanged = jest.fn();
- const setSettingField = jest.fn( ( field ) => {
- if ( field === 'cost' ) {
- return costChanged;
- }
- if ( field === 'tax_status' ) {
- return taxStatusChanged;
- }
- return jest.fn();
- } );
- mockUseSettingsContext.mockReturnValue(
- getContext( { setSettingField } )
- );
-
- render( <GeneralSettings /> );
-
- const showPrice = screen.getByRole( 'checkbox', {
- name: 'Add a price for customers who choose local pickup',
- } );
- expect(
- screen.queryByRole( 'spinbutton', { name: 'Cost' } )
- ).not.toBeInTheDocument();
- expect(
- screen.queryByRole( 'combobox', { name: 'Taxes' } )
- ).not.toBeInTheDocument();
-
- await act( async () => {
- await user.click( showPrice );
- } );
-
- const cost = screen.getByRole( 'spinbutton', { name: 'Cost' } );
- const taxes = screen.getByRole( 'combobox', { name: 'Taxes' } );
- await user.type( cost, '7' );
- await user.selectOptions( taxes, 'none' );
-
- expect( setSettingField ).toHaveBeenCalledWith( 'cost' );
- expect( setSettingField ).toHaveBeenCalledWith( 'tax_status' );
- expect( costChanged ).toHaveBeenCalledWith( '' );
- expect( costChanged ).toHaveBeenLastCalledWith( '7' );
- expect( taxStatusChanged ).toHaveBeenCalledWith( 'none' );
-
- await act( async () => {
- await user.click( showPrice );
- } );
-
- expect( costChanged ).toHaveBeenLastCalledWith( '' );
- expect(
- screen.queryByRole( 'spinbutton', { name: 'Cost' } )
- ).not.toBeInTheDocument();
- expect(
- screen.queryByRole( 'combobox', { name: 'Taxes' } )
- ).not.toBeInTheDocument();
- } );
-} );
diff --git a/plugins/woocommerce/client/blocks/assets/js/extensions/shipping-methods/pickup-location/test/location-settings.tsx b/plugins/woocommerce/client/blocks/assets/js/extensions/shipping-methods/pickup-location/test/location-settings.tsx
deleted file mode 100644
index a43b77c56df..00000000000
--- a/plugins/woocommerce/client/blocks/assets/js/extensions/shipping-methods/pickup-location/test/location-settings.tsx
+++ /dev/null
@@ -1,328 +0,0 @@
-/**
- * External dependencies
- */
-import { act, render, screen } from '@testing-library/react';
-import userEvent from '@testing-library/user-event';
-import { useId as mockUseId } from '@wordpress/element';
-import type { ReactNode } from 'react';
-
-/**
- * Internal dependencies
- */
-import LocationSettings from '../location-settings';
-import { useSettingsContext } from '../settings-context';
-import type { SettingsContextType, SortablePickupLocation } from '../types';
-
-jest.mock( '@wordpress/components', () => ( {
- Button: ( {
- children,
- onClick,
- }: {
- children: ReactNode;
- onClick: () => void;
- } ) => (
- <button type="button" onClick={ onClick }>
- { children }
- </button>
- ),
- Card: ( { children }: { children: ReactNode } ) => <div>{ children }</div>,
- CardBody: ( { children }: { children: ReactNode } ) => (
- <div>{ children }</div>
- ),
- ExternalLink: ( {
- children,
- href,
- }: {
- children: ReactNode;
- href: string;
- } ) => <a href={ href }>{ children }</a>,
- Modal: ( { children, title }: { children: ReactNode; title: string } ) => (
- <div role="dialog" aria-label={ title }>
- { children }
- </div>
- ),
- SelectControl: ( {
- children,
- label,
- onChange,
- value,
- }: {
- children: ReactNode;
- label: string;
- onChange: ( value: string ) => void;
- value: string;
- } ) => {
- const id = mockUseId();
- return (
- <>
- <label htmlFor={ id }>{ label }</label>
- <select
- id={ id }
- value={ value }
- onChange={ ( event ) => onChange( event.target.value ) }
- >
- { children }
- </select>
- </>
- );
- },
- TextControl: ( {
- label,
- onChange,
- placeholder,
- required,
- value,
- }: {
- label?: string;
- onChange: ( value: string ) => void;
- placeholder?: string;
- required?: boolean;
- value: string;
- } ) => {
- const accessibleLabel = label || placeholder || 'Text field';
- const id = mockUseId();
- return (
- <>
- <label htmlFor={ id }>{ accessibleLabel }</label>
- <input
- id={ id }
- required={ required }
- value={ value }
- onChange={ ( event ) => onChange( event.target.value ) }
- />
- </>
- );
- },
- ToggleControl: ( {
- checked,
- onChange,
- }: {
- checked: boolean;
- onChange: () => void;
- } ) => (
- <>
- <label htmlFor="toggle-location">Toggle location</label>
- <input
- id="toggle-location"
- type="checkbox"
- checked={ checked }
- onChange={ onChange }
- />
- </>
- ),
-} ) );
-
-jest.mock( '../settings-context', () => ( {
- useSettingsContext: jest.fn(),
-} ) );
-
-jest.mock( '../utils', () => ( {
- getUserFriendlyAddress: jest.fn( ( address: Record< string, string > ) =>
- Object.values( address ).filter( Boolean ).join( ', ' )
- ),
- states: {
- US: { CA: 'California' },
- GB: {},
- },
- countryStateOptions: {
- options: [
- {
- label: 'United States',
- options: [
- { value: 'US:CA', label: 'United States — California' },
- ],
- },
- {
- options: [ { value: 'GB', label: 'United Kingdom' } ],
- },
- ],
- },
-} ) );
-
-const mockUseSettingsContext = useSettingsContext as jest.MockedFunction<
- typeof useSettingsContext
->;
-
-const location: SortablePickupLocation = {
- id: 'warehouse-0',
- name: 'Warehouse',
- details: 'Rear entrance',
- enabled: true,
- address: {
- address_1: '60 29th Street',
- city: 'San Francisco',
- state: 'CA',
- postcode: '94110',
- country: 'US',
- },
-};
-
-const getContext = (
- overrides: Partial< SettingsContextType > = {}
-): SettingsContextType => ( {
- settings: {
- enabled: true,
- title: 'Pickup',
- tax_status: 'taxable',
- cost: '',
- },
- readOnlySettings: {
- hasLegacyPickup: false,
- storeCountry: 'US',
- storeState: 'CA',
- },
- setSettingField: jest.fn( () => jest.fn() ),
- pickupLocations: [ location ],
- setPickupLocations: jest.fn(),
- toggleLocation: jest.fn(),
- updateLocation: jest.fn(),
- isSaving: false,
- save: jest.fn(),
- isDirty: false,
- ...overrides,
-} );
-
-describe( 'LocationSettings', () => {
- it( 'adds a location with the dialog field values', async () => {
- const user = userEvent.setup();
- const updateLocation = jest.fn();
- mockUseSettingsContext.mockReturnValue(
- getContext( { pickupLocations: [], updateLocation } )
- );
- render( <LocationSettings /> );
-
- await act( async () => {
- await user.click(
- screen.getByRole( 'button', { name: 'Add pickup location' } )
- );
- } );
- await act( async () => {
- await user.type(
- screen.getByRole( 'textbox', { name: /Location name/ } ),
- 'Downtown'
- );
- } );
- await act( async () => {
- await user.type(
- screen.getByRole( 'textbox', { name: 'Address' } ),
- '10 Market Street'
- );
- } );
- await act( async () => {
- await user.type(
- screen.getByRole( 'textbox', { name: 'City' } ),
- 'San Francisco'
- );
- } );
- await act( async () => {
- await user.type(
- screen.getByRole( 'textbox', { name: 'Postcode / ZIP' } ),
- '94105'
- );
- } );
- await act( async () => {
- await user.selectOptions(
- screen.getByRole( 'combobox', { name: 'Country / State' } ),
- 'US:CA'
- );
- } );
- await act( async () => {
- await user.type(
- screen.getByRole( 'textbox', { name: 'Pickup details' } ),
- 'Ask at reception'
- );
- } );
- await act( async () => {
- await user.click( screen.getByRole( 'button', { name: 'Done' } ) );
- } );
-
- expect( updateLocation ).toHaveBeenCalledWith( 'new', {
- name: 'Downtown',
- details: 'Ask at reception',
- enabled: true,
- address: {
- address_1: '10 Market Street',
- city: 'San Francisco',
- state: 'CA',
- postcode: '94105',
- country: 'US',
- },
- } );
- } );
-
- it( 'edits a location using its existing ID and dialog payload', async () => {
- const user = userEvent.setup();
- const updateLocation = jest.fn();
- mockUseSettingsContext.mockReturnValue(
- getContext( { updateLocation } )
- );
- render( <LocationSettings /> );
-
- await act( async () => {
- await user.click( screen.getByRole( 'button', { name: 'Edit' } ) );
- } );
- const name = screen.getByRole( 'textbox', {
- name: /Location name/,
- } );
- await act( async () => {
- await user.clear( name );
- } );
- await act( async () => {
- await user.type( name, 'London office' );
- } );
- await act( async () => {
- await user.selectOptions(
- screen.getByRole( 'combobox', { name: 'Country / State' } ),
- 'GB'
- );
- } );
- await act( async () => {
- await user.click( screen.getByRole( 'button', { name: 'Done' } ) );
- } );
-
- expect( updateLocation ).toHaveBeenCalledWith( 'warehouse-0', {
- ...location,
- name: 'London office',
- address: {
- ...location.address,
- state: '',
- country: 'GB',
- },
- } );
- } );
-
- it( 'deletes a location using its existing ID', async () => {
- const user = userEvent.setup();
- const updateLocation = jest.fn();
- mockUseSettingsContext.mockReturnValue(
- getContext( { updateLocation } )
- );
- render( <LocationSettings /> );
-
- await act( async () => {
- await user.click( screen.getByRole( 'button', { name: 'Edit' } ) );
- } );
- await act( async () => {
- await user.click(
- screen.getByRole( 'button', { name: 'Delete location' } )
- );
- } );
-
- expect( updateLocation ).toHaveBeenCalledWith( 'warehouse-0', null );
- } );
-
- it( 'toggles a location using its existing ID', async () => {
- const user = userEvent.setup();
- const toggleLocation = jest.fn();
- mockUseSettingsContext.mockReturnValue(
- getContext( { toggleLocation } )
- );
- render( <LocationSettings /> );
-
- await user.click(
- screen.getByRole( 'checkbox', { name: 'Toggle location' } )
- );
-
- expect( toggleLocation ).toHaveBeenCalledWith( 'warehouse-0' );
- } );
-} );
diff --git a/plugins/woocommerce/client/blocks/assets/js/extensions/shipping-methods/pickup-location/test/settings-context.tsx b/plugins/woocommerce/client/blocks/assets/js/extensions/shipping-methods/pickup-location/test/settings-context.tsx
deleted file mode 100644
index 4fa3f6e71e4..00000000000
--- a/plugins/woocommerce/client/blocks/assets/js/extensions/shipping-methods/pickup-location/test/settings-context.tsx
+++ /dev/null
@@ -1,362 +0,0 @@
-/**
- * External dependencies
- */
-import apiFetch from '@wordpress/api-fetch';
-import { dispatch } from '@wordpress/data';
-import { store as noticesStore } from '@wordpress/notices';
-import { act, render, screen, waitFor } from '@testing-library/react';
-import userEvent from '@testing-library/user-event';
-
-/**
- * Internal dependencies
- */
-import { SettingsProvider, useSettingsContext } from '../settings-context';
-import type { SortablePickupLocation } from '../types';
-
-jest.mock( '@wordpress/api-fetch', () => jest.fn() );
-
-jest.mock( '@wordpress/data', () => ( {
- ...jest.requireActual( '@wordpress/data' ),
- dispatch: jest.fn(),
-} ) );
-
-jest.mock( '../utils', () => ( {
- defaultSettings: {
- enabled: false,
- title: 'Pickup',
- tax_status: 'taxable',
- cost: '',
- },
- defaultReadyOnlySettings: {
- hasLegacyPickup: false,
- storeCountry: 'US',
- storeState: 'CA',
- },
- readOnlySettings: {
- hasLegacyPickup: false,
- storeCountry: 'US',
- storeState: 'CA',
- },
- getInitialSettings: jest.fn( () => ( {
- enabled: false,
- title: 'Pickup',
- tax_status: 'none',
- cost: '',
- } ) ),
- getInitialPickupLocations: jest.fn( () => [
- {
- id: 'warehouse-0',
- name: 'Warehouse',
- details: 'Rear entrance',
- enabled: true,
- address: {
- address_1: '60 29th Street',
- city: 'San Francisco',
- state: 'CA',
- postcode: '94110',
- country: 'US',
- },
- },
- ] ),
-} ) );
-
-const mockApiFetch = apiFetch as jest.Mock;
-const mockDispatch = dispatch as jest.Mock;
-const createSuccessNotice = jest.fn();
-const createErrorNotice = jest.fn();
-
-const annex: SortablePickupLocation = {
- id: '',
- name: 'Annex',
- details: 'Front desk',
- enabled: true,
- address: {
- address_1: '10 Market Street',
- city: 'San Francisco',
- state: 'CA',
- postcode: '94105',
- country: 'US',
- },
-};
-
-const replacement: SortablePickupLocation = {
- id: 'warehouse-0',
- name: 'Main warehouse',
- details: 'Loading bay',
- enabled: false,
- address: {
- address_1: '100 New Bridge Street',
- city: 'London',
- state: '',
- postcode: 'EC4V 6JA',
- country: 'GB',
- },
-};
-
-const initialWarehouse: SortablePickupLocation = {
- id: 'warehouse-0',
- name: 'Warehouse',
- details: 'Rear entrance',
- enabled: true,
- address: {
- address_1: '60 29th Street',
- city: 'San Francisco',
- state: 'CA',
- postcode: '94110',
- country: 'US',
- },
-};
-
-const addedAnnex: SortablePickupLocation = {
- ...annex,
- id: 'annex-1',
-};
-
-const ContextConsumer = () => {
- const context = useSettingsContext();
- return (
- <>
- <output aria-label="Settings state">
- { JSON.stringify( context.settings ) }
- </output>
- <output aria-label="Pickup locations state">
- { JSON.stringify( context.pickupLocations ) }
- </output>
- <output aria-label="Dirty state">
- { String( context.isDirty ) }
- </output>
- <output aria-label="Saving state">
- { String( context.isSaving ) }
- </output>
- <button
- type="button"
- onClick={ () => context.updateLocation( 'new', annex ) }
- >
- Add annex
- </button>
- <button
- type="button"
- onClick={ () =>
- context.updateLocation( 'warehouse-0', replacement )
- }
- >
- Replace warehouse
- </button>
- <button
- type="button"
- onClick={ () => context.toggleLocation( 'warehouse-0' ) }
- >
- Toggle warehouse
- </button>
- <button
- type="button"
- onClick={ () => context.updateLocation( 'annex-1', null ) }
- >
- Delete annex
- </button>
- <button
- type="button"
- onClick={ () => {
- context.setSettingField( 'enabled' )( true );
- context.setSettingField( 'title' )( 'Curbside pickup' );
- context.setSettingField( 'tax_status' )( 'unsupported' );
- context.setSettingField( 'cost' )( '7.50' );
- } }
- >
- Change settings
- </button>
- <button type="button" onClick={ context.save }>
- Save
- </button>
- </>
- );
-};
-
-const getOutput = ( name: string ) => screen.getByRole( 'status', { name } );
-
-const getPickupLocations = (): SortablePickupLocation[] =>
- JSON.parse(
- getOutput( 'Pickup locations state' ).textContent ?? '[]'
- ) as SortablePickupLocation[];
-
-describe( 'SettingsProvider', () => {
- beforeEach( () => {
- mockApiFetch.mockReset();
- mockDispatch.mockReset();
- createSuccessNotice.mockReset();
- createErrorNotice.mockReset();
- mockDispatch.mockReturnValue( {
- createSuccessNotice,
- createErrorNotice,
- } );
- } );
-
- it( 'adds, replaces, toggles, and deletes locations while marking changes dirty', async () => {
- const user = userEvent.setup();
- render(
- <SettingsProvider>
- <ContextConsumer />
- </SettingsProvider>
- );
-
- expect( getOutput( 'Dirty state' ) ).toHaveTextContent( 'false' );
-
- await act( async () => {
- await user.click(
- screen.getByRole( 'button', { name: 'Add annex' } )
- );
- } );
- expect( getPickupLocations() ).toEqual( [
- initialWarehouse,
- addedAnnex,
- ] );
- expect( getOutput( 'Dirty state' ) ).toHaveTextContent( 'true' );
-
- await act( async () => {
- await user.click(
- screen.getByRole( 'button', { name: 'Replace warehouse' } )
- );
- } );
- expect( getPickupLocations() ).toEqual( [ replacement, addedAnnex ] );
-
- await act( async () => {
- await user.click(
- screen.getByRole( 'button', { name: 'Toggle warehouse' } )
- );
- } );
- const enabledReplacement = { ...replacement, enabled: true };
- expect( getPickupLocations() ).toEqual( [
- enabledReplacement,
- addedAnnex,
- ] );
-
- await act( async () => {
- await user.click(
- screen.getByRole( 'button', { name: 'Delete annex' } )
- );
- } );
- expect( getPickupLocations() ).toEqual( [ enabledReplacement ] );
- } );
-
- it( 'normalizes settings and locations in a successful save request', async () => {
- const user = userEvent.setup();
- let resolveRequest: () => void;
- mockApiFetch.mockImplementation(
- () =>
- new Promise( ( resolve ) => {
- resolveRequest = () => resolve( {} );
- } )
- );
- render(
- <SettingsProvider>
- <ContextConsumer />
- </SettingsProvider>
- );
-
- await act( async () => {
- await user.click(
- screen.getByRole( 'button', { name: 'Change settings' } )
- );
- } );
- await act( async () => {
- await user.click(
- screen.getByRole( 'button', { name: 'Add annex' } )
- );
- } );
- expect( getOutput( 'Dirty state' ) ).toHaveTextContent( 'true' );
-
- await act( async () => {
- await user.click( screen.getByRole( 'button', { name: 'Save' } ) );
- } );
-
- expect( mockApiFetch ).toHaveBeenCalledWith( {
- path: '/wc/v3/pickup-locations',
- method: 'POST',
- data: {
- pickup_location_settings: {
- enabled: 'yes',
- title: 'Curbside pickup',
- tax_status: 'taxable',
- cost: '7.50',
- },
- pickup_locations: [
- {
- name: 'Warehouse',
- address: {
- address_1: '60 29th Street',
- city: 'San Francisco',
- state: 'CA',
- postcode: '94110',
- country: 'US',
- },
- details: 'Rear entrance',
- enabled: true,
- },
- {
- name: 'Annex',
- address: annex.address,
- details: 'Front desk',
- enabled: true,
- },
- ],
- },
- } );
- expect( getOutput( 'Saving state' ) ).toHaveTextContent( 'true' );
- expect( getOutput( 'Dirty state' ) ).toHaveTextContent( 'false' );
-
- await act( async () => {
- resolveRequest();
- } );
-
- await waitFor( () => {
- expect( getOutput( 'Saving state' ) ).toHaveTextContent( 'false' );
- } );
- expect( createSuccessNotice ).toHaveBeenCalledWith(
- 'Local Pickup settings have been saved.'
- );
- expect( createErrorNotice ).not.toHaveBeenCalled();
- expect( mockDispatch ).toHaveBeenCalledWith( noticesStore );
- } );
-
- it( 'restores dirty state and reports a rejected save', async () => {
- const user = userEvent.setup();
- let rejectRequest: ( reason: Error ) => void;
- mockApiFetch.mockImplementation(
- () =>
- new Promise( ( resolve, reject ) => {
- void resolve;
- rejectRequest = reject;
- } )
- );
- render(
- <SettingsProvider>
- <ContextConsumer />
- </SettingsProvider>
- );
-
- await act( async () => {
- await user.click(
- screen.getByRole( 'button', { name: 'Change settings' } )
- );
- } );
- await act( async () => {
- await user.click( screen.getByRole( 'button', { name: 'Save' } ) );
- } );
- expect( getOutput( 'Saving state' ) ).toHaveTextContent( 'true' );
- expect( getOutput( 'Dirty state' ) ).toHaveTextContent( 'false' );
-
- await act( async () => {
- rejectRequest( new Error( 'Request failed' ) );
- } );
-
- await waitFor( () => {
- expect( getOutput( 'Saving state' ) ).toHaveTextContent( 'false' );
- } );
- expect( getOutput( 'Dirty state' ) ).toHaveTextContent( 'true' );
- expect( createErrorNotice ).toHaveBeenCalledWith(
- 'There was an error saving your Local Pickup settings. Please try again.'
- );
- expect( createSuccessNotice ).not.toHaveBeenCalled();
- expect( mockDispatch ).toHaveBeenCalledWith( noticesStore );
- } );
-} );
diff --git a/plugins/woocommerce/client/blocks/changelog/testops-234-local-pickup-settings b/plugins/woocommerce/client/blocks/changelog/testops-234-local-pickup-settings
deleted file mode 100644
index 8f333268a3a..00000000000
--- a/plugins/woocommerce/client/blocks/changelog/testops-234-local-pickup-settings
+++ /dev/null
@@ -1,4 +0,0 @@
-Significance: patch
-Type: dev
-Comment: Reduce Local Pickup settings E2E tests from 7 to 2; three Jest suites own the settings screen's logic.
-
diff --git a/plugins/woocommerce/tests/e2e/tests/blocks/local-pickup/local-pickup.merchant.block_theme.spec.ts b/plugins/woocommerce/tests/e2e/tests/blocks/local-pickup/local-pickup.merchant.block_theme.spec.ts
index bcee358ca66..2f1b1156879 100644
--- a/plugins/woocommerce/tests/e2e/tests/blocks/local-pickup/local-pickup.merchant.block_theme.spec.ts
+++ b/plugins/woocommerce/tests/e2e/tests/blocks/local-pickup/local-pickup.merchant.block_theme.spec.ts
@@ -2,171 +2,180 @@
* External dependencies
*/
import { test, expect } from '@woocommerce/e2e-utils';
-import type { Page } from '@playwright/test';
-
-const saveLocalPickupSettings = async ( page: Page ) => {
- const saveButton = page.getByRole( 'button', { name: 'Save changes' } );
- const [ response ] = await Promise.all( [
- page.waitForResponse(
- ( candidate ) =>
- candidate.request().method() === 'POST' &&
- candidate.url().includes( '/wc/v3/pickup-locations' )
- ),
- saveButton.click(),
- ] );
-
- expect( response.ok() ).toBeTruthy();
- await expect( saveButton ).toBeDisabled();
-};
test.describe( 'Merchant → Local Pickup Settings', () => {
- test.beforeEach( async ( { page, localPickupUtils } ) => {
+ test.beforeEach( async ( { localPickupUtils } ) => {
await localPickupUtils.disableLocalPickupCosts();
await localPickupUtils.enableLocalPickup();
- if (
- ( await page
- .getByRole( 'textbox', { name: 'Title' } )
- .inputValue() ) !== 'Pickup'
- ) {
- await localPickupUtils.setLocalPickupTitle( 'Pickup' );
- }
} );
- test( 'Merchant can configure Local Pickup general settings', async ( {
+ test( 'user can toggle the enabled state', async ( {
page,
+ localPickupUtils,
} ) => {
- await test.step( 'Configure and save the general settings', async () => {
- const enabled = page.getByRole( 'checkbox', {
- name: 'Enable local pickup',
- } );
- const title = page.getByRole( 'textbox', { name: 'Title' } );
- const showPrice = page.getByRole( 'checkbox', {
- name: 'Add a price for customers who choose local pickup',
- } );
-
- await expect( enabled ).toBeChecked();
- await expect( title ).toHaveValue( 'Pickup' );
- await expect( showPrice ).not.toBeChecked();
- await expect(
- page.getByRole( 'spinbutton', { name: 'Cost' } )
- ).toBeHidden();
-
- await enabled.uncheck();
- await title.fill( 'Curbside pickup' );
- await showPrice.check();
-
- const cost = page.getByRole( 'spinbutton', { name: 'Cost' } );
- const taxes = page.getByRole( 'combobox', { name: 'Taxes' } );
- await expect( cost ).toBeVisible();
- await expect( taxes ).toBeVisible();
- await cost.fill( '20' );
- await taxes.selectOption( 'none' );
-
- await saveLocalPickupSettings( page );
- } );
+ await expect( page.getByLabel( 'Enable local pickup' ) ).toBeChecked();
- await test.step( 'Reload and confirm the settings persisted', async () => {
- await page.reload();
-
- await expect(
- page.getByRole( 'checkbox', { name: 'Enable local pickup' } )
- ).not.toBeChecked();
- await expect(
- page.getByRole( 'textbox', { name: 'Title' } )
- ).toHaveValue( 'Curbside pickup' );
- await expect(
- page.getByRole( 'checkbox', {
- name: 'Add a price for customers who choose local pickup',
- } )
- ).toBeChecked();
- await expect(
- page.getByRole( 'spinbutton', { name: 'Cost' } )
- ).toHaveValue( '20' );
- await expect(
- page.getByRole( 'combobox', { name: 'Taxes' } )
- ).toHaveValue( 'none' );
- } );
+ await localPickupUtils.disableLocalPickup();
+
+ await expect(
+ page.getByLabel( 'Enable local pickup' )
+ ).not.toBeChecked();
+ } );
+
+ test( 'user can change the title', async ( { page, localPickupUtils } ) => {
+ await page.getByPlaceholder( 'Pickup' ).fill( 'Local Pickup Test #1' );
+
+ await localPickupUtils.saveLocalPickupSettings();
+
+ await expect( page.getByPlaceholder( 'Pickup' ) ).toHaveValue(
+ 'Local Pickup Test #1'
+ );
+
+ await page.getByPlaceholder( 'Pickup' ).fill( 'Local Pickup Test #2' );
+
+ await localPickupUtils.saveLocalPickupSettings();
+
+ await expect( page.getByPlaceholder( 'Pickup' ) ).toHaveValue(
+ 'Local Pickup Test #2'
+ );
} );
- test( 'Merchant can manage a Local Pickup location lifecycle', async ( {
+ test( 'user can toggle the price field state', async ( {
page,
+ localPickupUtils,
} ) => {
- const sanFranciscoLocation = page.getByRole( 'cell', {
- name: 'Automattic, Inc.60 29th Street, Suite 343, San Francisco, California, 94110, United States (US)',
- } );
- const londonLocation = page.getByRole( 'cell', {
- name: 'Ministry of Automattic Limited100 New Bridge Street, London, EC4V 6JA, United Kingdom (UK)',
- } );
- const emptyLocations = page.getByRole( 'cell', {
- name: 'When you add a pickup location, it will appear here.',
+ await localPickupUtils.enableLocalPickupCosts();
+
+ await expect(
+ page.getByLabel(
+ 'Add a price for customers who choose local pickup'
+ )
+ ).toBeChecked();
+
+ await localPickupUtils.disableLocalPickupCosts();
+
+ await expect(
+ page.getByLabel(
+ 'Add a price for customers who choose local pickup'
+ )
+ ).not.toBeChecked();
+ } );
+
+ test( 'user can edit costs and tax status', async ( {
+ page,
+ localPickupUtils,
+ } ) => {
+ await localPickupUtils.enableLocalPickupCosts();
+
+ await expect(
+ page.getByLabel(
+ 'Add a price for customers who choose local pickup'
+ )
+ ).toBeChecked();
+
+ await page.getByPlaceholder( 'Free' ).fill( '20' );
+ await page.getByLabel( 'Taxes' ).selectOption( 'none' );
+
+ await localPickupUtils.saveLocalPickupSettings();
+
+ await expect( page.getByPlaceholder( 'Free' ) ).toHaveValue( '20' );
+ await expect( page.getByLabel( 'Taxes' ) ).toHaveValue( 'none' );
+
+ await page.getByPlaceholder( 'Free' ).fill( '' );
+ await page.getByLabel( 'Taxes' ).selectOption( 'taxable' );
+
+ await localPickupUtils.saveLocalPickupSettings();
+
+ await expect( page.getByPlaceholder( 'Free' ) ).toHaveValue( '' );
+ await expect( page.getByLabel( 'Taxes' ) ).toHaveValue( 'taxable' );
+ } );
+
+ test( 'user can add a new location', async ( {
+ page,
+ localPickupUtils,
+ } ) => {
+ await localPickupUtils.addPickupLocation( {
+ location: {
+ name: 'Automattic, Inc.',
+ address: '60 29th Street, Suite 343',
+ city: 'San Francisco',
+ postcode: '94110',
+ state: 'US:CA',
+ details: 'American entity',
+ },
} );
- await test.step( 'Add, save, and reload a pickup location', async () => {
- await expect( emptyLocations ).toBeVisible();
- await page
- .getByRole( 'button', { name: 'Add pickup location' } )
- .click();
- await page.getByLabel( 'Location name' ).fill( 'Automattic, Inc.' );
- await page
- .getByRole( 'textbox', { name: 'Address' } )
- .fill( '60 29th Street, Suite 343' );
- await page
- .getByRole( 'textbox', { name: 'City' } )
- .fill( 'San Francisco' );
- await page
- .getByRole( 'textbox', { name: 'Postcode / ZIP' } )
- .fill( '94110' );
- await page
- .getByRole( 'combobox', { name: 'Country / State' } )
- .selectOption( 'US:CA' );
- await page
- .getByRole( 'textbox', { name: 'Pickup details' } )
- .fill( 'American entity' );
- await page.getByRole( 'button', { name: 'Done' } ).click();
-
- await saveLocalPickupSettings( page );
- await page.reload();
- await expect( sanFranciscoLocation ).toBeVisible();
+ await expect(
+ page.getByRole( 'cell', {
+ name: 'Automattic, Inc.60 29th Street, Suite 343, San Francisco, California, 94110, United States (US)',
+ } )
+ ).toBeVisible();
+ } );
+
+ test( 'user can edit a location', async ( { page, localPickupUtils } ) => {
+ await localPickupUtils.addPickupLocation( {
+ location: {
+ name: 'Automattic, Inc.',
+ address: '60 29th Street, Suite 343',
+ city: 'San Francisco',
+ postcode: '94110',
+ state: 'US:CA',
+ details: 'American entity',
+ },
} );
- await test.step( 'Edit, save, and reload the pickup location', async () => {
- await page.getByRole( 'button', { name: 'Edit' } ).click();
- await page
- .getByLabel( 'Location name' )
- .fill( 'Ministry of Automattic Limited' );
- await page
- .getByRole( 'textbox', { name: 'Address' } )
- .fill( '100 New Bridge Street' );
- await page
- .getByRole( 'textbox', { name: 'City' } )
- .fill( 'London' );
- await page
- .getByRole( 'textbox', { name: 'Postcode / ZIP' } )
- .fill( 'EC4V 6JA' );
- await page
- .getByRole( 'combobox', { name: 'Country / State' } )
- .selectOption( 'GB' );
- await page
- .getByRole( 'textbox', { name: 'Pickup details' } )
- .fill( 'British entity' );
- await page.getByRole( 'button', { name: 'Done' } ).click();
-
- await saveLocalPickupSettings( page );
- await page.reload();
- await expect( londonLocation ).toBeVisible();
- await expect( sanFranciscoLocation ).toBeHidden();
+ await expect(
+ page.getByRole( 'cell', {
+ name: 'Automattic, Inc.60 29th Street, Suite 343, San Francisco, California, 94110, United States (US)',
+ } )
+ ).toBeVisible();
+
+ await localPickupUtils.editPickupLocation( {
+ location: {
+ name: 'Ministry of Automattic Limited',
+ address: '100 New Bridge Street',
+ city: 'London',
+ postcode: 'EC4V 6JA',
+ state: 'GB',
+ details: 'British entity',
+ },
} );
- await test.step( 'Delete, save, and reload the pickup location', async () => {
- await page.getByRole( 'button', { name: 'Edit' } ).click();
- await page
- .getByRole( 'button', { name: 'Delete location' } )
- .click();
+ await expect(
+ page.getByRole( 'cell', {
+ name: 'Ministry of Automattic Limited100 New Bridge Street, London, EC4V 6JA, United Kingdom (UK)',
+ } )
+ ).toBeVisible();
+ } );
- await saveLocalPickupSettings( page );
- await page.reload();
- await expect( emptyLocations ).toBeVisible();
- await expect( londonLocation ).toBeHidden();
+ test( 'user can delete a location', async ( {
+ page,
+ localPickupUtils,
+ } ) => {
+ await localPickupUtils.addPickupLocation( {
+ location: {
+ name: 'Ausomattic Pty Ltd',
+ address:
+ 'c/o Baker And Mckenzie Level 19 Cbw, 181 William Street',
+ city: 'Melbourne',
+ postcode: '300',
+ state: 'AU:VIC',
+ details: 'Australian entity',
+ },
} );
+
+ await expect(
+ page.getByRole( 'cell', {
+ name: 'Ausomattic Pty Ltdc/o Baker And Mckenzie Level 19 Cbw, 181 William Street, Melbourne, Victoria, 300, Australia',
+ } )
+ ).toBeVisible();
+
+ await localPickupUtils.deletePickupLocation();
+
+ await expect(
+ page.getByRole( 'cell', {
+ name: 'When you add a pickup location, it will appear here.',
+ } )
+ ).toBeVisible();
} );
} );
diff --git a/plugins/woocommerce/tests/php/src/Blocks/Shipping/PickupLocationsRestControllerTest.php b/plugins/woocommerce/tests/php/src/Blocks/Shipping/PickupLocationsRestControllerTest.php
index 257e8f655d2..fa682edda2d 100644
--- a/plugins/woocommerce/tests/php/src/Blocks/Shipping/PickupLocationsRestControllerTest.php
+++ b/plugins/woocommerce/tests/php/src/Blocks/Shipping/PickupLocationsRestControllerTest.php
@@ -140,87 +140,6 @@ class PickupLocationsRestControllerTest extends WC_Unit_Test_Case {
$this->assertSame( $locations, get_option( 'pickup_location_pickup_locations' ), 'Locations should be persisted to the database.' );
}
- /**
- * Tax statuses the endpoint accepts.
- *
- * @return array<string, array{string}>
- */
- public function provider_tax_status(): array {
- return array(
- 'taxable' => array( 'taxable' ),
- 'none' => array( 'none' ),
- );
- }
-
- /**
- * @testdox Should round-trip every accepted tax status rather than coercing it.
- * @dataProvider provider_tax_status
- *
- * @param string $tax_status Tax status to save.
- */
- public function test_update_settings_round_trips_tax_status( string $tax_status ): void {
- wp_set_current_user( $this->shop_manager_id );
-
- $request = new \WP_REST_Request( 'POST', '/wc/v3/pickup-locations' );
- $request->set_param(
- 'pickup_location_settings',
- array(
- 'enabled' => 'yes',
- 'title' => 'Local Pickup',
- 'tax_status' => $tax_status,
- 'cost' => '',
- )
- );
-
- $response = $this->sut->update_settings( $request );
- $data = $response->get_data();
-
- // `none` is both an accepted value and the fallback for a rejected one, so
- // it only proves anything next to `taxable`: together they separate "the
- // status was kept" from "everything collapses to one status".
- $this->assertSame( $tax_status, $data['pickup_location_settings']['tax_status'], 'The response should echo back the tax status that was saved.' );
- $this->assertSame( $tax_status, get_option( 'woocommerce_pickup_location_settings' )['tax_status'], 'The saved tax status should be persisted unchanged.' );
- }
-
- /**
- * @testdox Should store an empty pickup locations list rather than ignoring it.
- */
- public function test_update_settings_stores_an_empty_pickup_locations_list(): void {
- wp_set_current_user( $this->shop_manager_id );
-
- $locations = array(
- array(
- 'name' => 'Main Store',
- 'address' => array(
- 'address_1' => '123 Main St',
- 'city' => 'Anytown',
- 'state' => 'CA',
- 'postcode' => '90210',
- 'country' => 'US',
- ),
- 'details' => '',
- 'enabled' => true,
- ),
- );
-
- $request = new \WP_REST_Request( 'POST', '/wc/v3/pickup-locations' );
- $request->set_param( 'pickup_locations', $locations );
- $this->sut->update_settings( $request );
-
- $this->assertCount( 1, get_option( 'pickup_location_pickup_locations' ), 'The starting list should hold the location that was saved.' );
-
- // Removing the last location sends an empty array. Treating that as "nothing
- // to do" would leave the merchant with a location they deleted.
- $request = new \WP_REST_Request( 'POST', '/wc/v3/pickup-locations' );
- $request->set_param( 'pickup_locations', array() );
-
- $response = $this->sut->update_settings( $request );
- $data = $response->get_data();
-
- $this->assertSame( array(), $data['pickup_locations'], 'The response should echo back the empty list.' );
- $this->assertSame( array(), get_option( 'pickup_location_pickup_locations' ), 'Saving an empty list should clear the stored locations.' );
- }
-
/**
* @testdox Should drop incomplete locations and default missing keys so admin hydration never hits undefined indexes.
*/