Commit da60e62c4e8 for woocommerce
commit da60e62c4e82d445a104e2baa6bb11e66fa1c7c9
Author: Vlad Olaru <vlad.olaru@automattic.com>
Date: Thu Sep 24 17:52:58 2026 +0300
Revert "[tests] Move 5 Checkout block editor control E2E tests to Jest" (#69048)
revert: Revert "[tests] Move 5 Checkout block editor control E2E tests to Jest" (#68586)
This reverts commit 9cd4e9812429b1aa067baa037356520047648b32.
Rubik asked for the E2E migration's test changes in its areas to be
reverted until the team can review them. #68586 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 #68586
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
diff --git a/plugins/woocommerce/changelog/testops-234-checkout-block-editor-controls b/plugins/woocommerce/changelog/testops-234-checkout-block-editor-controls
deleted file mode 100644
index 58c19024dd3..00000000000
--- a/plugins/woocommerce/changelog/testops-234-checkout-block-editor-controls
+++ /dev/null
@@ -1,4 +0,0 @@
-Significance: patch
-Type: dev
-Comment: Move 5 Checkout block editor control E2E tests to Jest; the Checkout block merchant spec keeps 3 browser titles.
-
diff --git a/plugins/woocommerce/client/blocks/assets/js/blocks/cart-checkout-shared/block-settings/test/index.tsx b/plugins/woocommerce/client/blocks/assets/js/blocks/cart-checkout-shared/block-settings/test/index.tsx
deleted file mode 100644
index b3cb3e75c49..00000000000
--- a/plugins/woocommerce/client/blocks/assets/js/blocks/cart-checkout-shared/block-settings/test/index.tsx
+++ /dev/null
@@ -1,50 +0,0 @@
-/**
- * External dependencies
- */
-import { render, screen } from '@testing-library/react';
-import userEvent from '@testing-library/user-event';
-
-/**
- * Internal dependencies
- */
-import { BlockSettings } from '../index';
-
-jest.mock( '@wordpress/block-editor', () => ( {
- ...jest.requireActual( '@wordpress/block-editor' ),
- InspectorControls: jest.fn( ( { children } ) => <div>{ children }</div> ),
-} ) );
-
-describe( 'Cart and Checkout block settings', () => {
- it.each( [
- { initialValue: false, expectedValue: true },
- { initialValue: true, expectedValue: false },
- ] )(
- 'maps hasDarkControls=$initialValue to $expectedValue',
- async ( { initialValue, expectedValue } ) => {
- const user = userEvent.setup();
- const setAttributes = jest.fn();
-
- render(
- <BlockSettings
- attributes={ {
- hasDarkControls: initialValue,
- showFormStepNumbers: false,
- } }
- setAttributes={ setAttributes }
- />
- );
-
- const darkModeToggle = screen.getByRole( 'checkbox', {
- name: 'Dark mode inputs',
- } );
- expect( darkModeToggle ).toHaveProperty( 'checked', initialValue );
-
- await user.click( darkModeToggle );
-
- expect( setAttributes ).toHaveBeenCalledTimes( 1 );
- expect( setAttributes ).toHaveBeenCalledWith( {
- hasDarkControls: expectedValue,
- } );
- }
- );
-} );
diff --git a/plugins/woocommerce/client/blocks/assets/js/blocks/checkout/inner-blocks/checkout-actions-block/tests/edit.test.tsx b/plugins/woocommerce/client/blocks/assets/js/blocks/checkout/inner-blocks/checkout-actions-block/tests/edit.test.tsx
deleted file mode 100644
index 7b15a51b509..00000000000
--- a/plugins/woocommerce/client/blocks/assets/js/blocks/checkout/inner-blocks/checkout-actions-block/tests/edit.test.tsx
+++ /dev/null
@@ -1,95 +0,0 @@
-/**
- * External dependencies
- */
-import { render, screen } from '@testing-library/react';
-import userEvent from '@testing-library/user-event';
-
-/**
- * Internal dependencies
- */
-import { Edit } from '../edit';
-
-jest.mock( '@wordpress/block-editor', () => ( {
- InspectorControls: jest.fn( ( { children } ) => <div>{ children }</div> ),
- RichText: jest.fn( ( { value, placeholder } ) => (
- <span>{ value || placeholder }</span>
- ) ),
- useBlockProps: Object.assign(
- jest.fn( () => ( { className: '' } ) ),
- {
- save: jest.fn( () => ( {} ) ),
- }
- ),
-} ) );
-
-jest.mock( '@wordpress/data', () => ( {
- ...jest.requireActual( '@wordpress/data' ),
- useSelect: jest.fn( () => 2 ),
-} ) );
-
-jest.mock( '@woocommerce/editor-components/page-selector', () => () => null );
-
-jest.mock( '@woocommerce/base-components/cart-checkout', () => ( {
- PlaceOrderButton: jest.fn( ( { label } ) => <button>{ label }</button> ),
- ReturnToCartButton: jest.fn( ( { children } ) => (
- <span>{ children }</span>
- ) ),
-} ) );
-
-jest.mock( '@woocommerce/block-settings', () => ( {
- CHECKOUT_PAGE_ID: 1,
-} ) );
-
-const expectReturnToCartVisible = () => {
- expect( screen.getByText( 'Return to Cart' ) ).toBeVisible();
-};
-
-const expectReturnToCartHidden = () => {
- expect( screen.queryByText( 'Return to Cart' ) ).not.toBeInTheDocument();
-};
-
-describe( 'Checkout Actions editor', () => {
- it.each( [
- { initialValue: false, expectedValue: true },
- { initialValue: true, expectedValue: false },
- ] )(
- 'maps showReturnToCart=$initialValue to $expectedValue and previews the current state',
- async ( { initialValue, expectedValue } ) => {
- const user = userEvent.setup();
- const setAttributes = jest.fn();
-
- render(
- <Edit
- attributes={ {
- cartPageId: 1,
- showReturnToCart: initialValue,
- placeOrderButtonLabel: 'Place Order',
- priceSeparator: '·',
- returnToCartButtonLabel: 'Return to Cart',
- } }
- setAttributes={ setAttributes }
- />
- );
-
- const returnToCartToggle = screen.getByRole( 'checkbox', {
- name: 'Show a "Return to Cart" link',
- } );
- expect( returnToCartToggle ).toHaveProperty(
- 'checked',
- initialValue
- );
- if ( initialValue ) {
- expectReturnToCartVisible();
- } else {
- expectReturnToCartHidden();
- }
-
- await user.click( returnToCartToggle );
-
- expect( setAttributes ).toHaveBeenCalledTimes( 1 );
- expect( setAttributes ).toHaveBeenCalledWith( {
- showReturnToCart: expectedValue,
- } );
- }
- );
-} );
diff --git a/plugins/woocommerce/client/blocks/assets/js/blocks/checkout/inner-blocks/checkout-terms-block/test/frontend.js b/plugins/woocommerce/client/blocks/assets/js/blocks/checkout/inner-blocks/checkout-terms-block/test/frontend.js
index 23c0b676035..4d75e7f082d 100644
--- a/plugins/woocommerce/client/blocks/assets/js/blocks/checkout/inner-blocks/checkout-terms-block/test/frontend.js
+++ b/plugins/woocommerce/client/blocks/assets/js/blocks/checkout/inner-blocks/checkout-terms-block/test/frontend.js
@@ -20,12 +20,6 @@ import { validationStore } from '@woocommerce/block-data';
import * as actionCreators from '@woocommerce/block-data/validation/actions';
import FrontendBlock from '../frontend';
-jest.mock( '@woocommerce/block-settings', () => ( {
- ...jest.requireActual( '@woocommerce/block-settings' ),
- TERMS_URL: 'https://example.com/terms/',
- PRIVACY_URL: 'https://example.com/privacy/',
-} ) );
-
jest.mock( '@woocommerce/block-data/validation/actions', () => {
const actions = jest.requireActual(
'@woocommerce/block-data/validation/actions'
@@ -39,35 +33,7 @@ jest.mock( '@woocommerce/block-data/validation/actions', () => {
} );
describe( 'FrontendBlock', () => {
- it( 'Renders the default Terms and Privacy links without a checkbox', () => {
- render(
- <SlotFillProvider>
- <FrontendBlock
- checkbox={ false }
- text=""
- showSeparator={ false }
- />
- </SlotFillProvider>
- );
-
- expect(
- screen.getByText(
- ( _, element ) =>
- element?.tagName === 'SPAN' &&
- element.textContent ===
- 'By proceeding with your purchase you agree to our Terms and Conditions and Privacy Policy'
- )
- ).toBeVisible();
- expect(
- screen.getByRole( 'link', { name: 'Terms and Conditions' } )
- ).toHaveAttribute( 'href', 'https://example.com/terms/' );
- expect(
- screen.getByRole( 'link', { name: 'Privacy Policy' } )
- ).toHaveAttribute( 'href', 'https://example.com/privacy/' );
- expect( screen.queryByRole( 'checkbox' ) ).not.toBeInTheDocument();
- } );
-
- it( 'Renders a checkbox if the checkbox prop is true', () => {
+ it( 'Renders a checkbox if the checkbox prop is true', async () => {
const { container } = render(
<SlotFillProvider>
<FrontendBlock
@@ -78,7 +44,7 @@ describe( 'FrontendBlock', () => {
</SlotFillProvider>
);
- const checkbox = queryByLabelText(
+ const checkbox = await findByLabelText(
container,
'I agree to the terms and conditions'
);
@@ -107,7 +73,6 @@ describe( 'FrontendBlock', () => {
it( 'Clears any validation errors when the checkbox is checked', async () => {
const user = userEvent.setup();
- actionCreators.clearValidationError.mockClear();
const { container } = render(
<SlotFillProvider>
<FrontendBlock
@@ -124,19 +89,9 @@ describe( 'FrontendBlock', () => {
await act( async () => {
await user.click( checkbox );
} );
- expect( actionCreators.clearValidationError ).toHaveBeenCalledTimes(
- 2
+ expect( actionCreators.clearValidationError ).toHaveBeenLastCalledWith(
+ expect.stringMatching( /terms-and-conditions-\d/ )
);
-
- const [ [ cleanupId ], [ checkedId ] ] =
- actionCreators.clearValidationError.mock.calls;
-
- // The component derives one `validationErrorId` and hands it to both
- // the effect cleanup and the checked branch. Matching each call
- // against the pattern separately would pass even if the two ids
- // diverged, so assert the shape once and then that both calls agree.
- expect( cleanupId ).toMatch( /^terms-and-conditions-\d+$/ );
- expect( checkedId ).toBe( cleanupId );
} );
it( 'Renders and describes the validation error when the checkbox is required and unchecked', async () => {
diff --git a/plugins/woocommerce/client/blocks/assets/js/blocks/checkout/test/address-field-controls.tsx b/plugins/woocommerce/client/blocks/assets/js/blocks/checkout/test/address-field-controls.tsx
deleted file mode 100644
index 78df232c75a..00000000000
--- a/plugins/woocommerce/client/blocks/assets/js/blocks/checkout/test/address-field-controls.tsx
+++ /dev/null
@@ -1,147 +0,0 @@
-/**
- * External dependencies
- */
-import { render, screen } from '@testing-library/react';
-import userEvent from '@testing-library/user-event';
-
-/**
- * Internal dependencies
- */
-import { AddressFieldControls } from '../address-field-controls';
-
-const mockEditEntityRecord = jest.fn();
-const mockDispatch = jest.fn( () => ( {
- editEntityRecord: mockEditEntityRecord,
-} ) );
-const mockUseCheckoutBlockContext = jest.fn();
-
-jest.mock( '@wordpress/block-editor', () => ( {
- InspectorControls: jest.fn( ( { children } ) => <div>{ children }</div> ),
-} ) );
-
-jest.mock( '@wordpress/data', () => ( {
- ...jest.requireActual( '@wordpress/data' ),
- dispatch: ( store: string ) => mockDispatch( store ),
-} ) );
-
-jest.mock( '@wordpress/core-data', () => ( {
- store: 'core',
-} ) );
-
-jest.mock( '../context', () => ( {
- useCheckoutBlockContext: () => mockUseCheckoutBlockContext(),
-} ) );
-
-type FieldName = 'company' | 'address_2' | 'phone';
-type FieldState = 'hidden' | 'optional' | 'required';
-
-const fields: Array< {
- label: string;
- name: FieldName;
- option: string;
-} > = [
- {
- label: 'Company',
- name: 'company',
- option: 'woocommerce_checkout_company_field',
- },
- {
- label: 'Address line 2',
- name: 'address_2',
- option: 'woocommerce_checkout_address_2_field',
- },
- {
- label: 'Phone',
- name: 'phone',
- option: 'woocommerce_checkout_phone_field',
- },
-];
-
-const getField = ( state: FieldState ) => ( {
- hidden: state === 'hidden',
- required: state === 'required',
-} );
-
-const renderControls = ( field: FieldName, state: FieldState ) => {
- mockUseCheckoutBlockContext.mockReturnValue( {
- defaultFields: {
- company: getField( field === 'company' ? state : 'hidden' ),
- address_2: getField( field === 'address_2' ? state : 'hidden' ),
- phone: getField( field === 'phone' ? state : 'hidden' ),
- },
- } );
-
- render( <AddressFieldControls /> );
-};
-
-const expectUpdate = ( option: string, value: FieldState ) => {
- expect( mockDispatch ).toHaveBeenCalledWith( 'core' );
- expect( mockEditEntityRecord ).toHaveBeenCalledTimes( 1 );
- expect( mockEditEntityRecord ).toHaveBeenCalledWith(
- 'root',
- 'site',
- undefined,
- { [ option ]: value }
- );
-};
-
-describe.each( fields )( '$label address field control', ( field ) => {
- beforeEach( () => {
- jest.clearAllMocks();
- } );
-
- it( 'shows a hidden field as optional', async () => {
- const user = userEvent.setup();
- renderControls( field.name, 'hidden' );
-
- const visibilityToggle = screen.getByRole( 'checkbox', {
- name: field.label,
- } );
- expect( visibilityToggle ).not.toBeChecked();
-
- await user.click( visibilityToggle );
-
- expectUpdate( field.option, 'optional' );
- } );
-
- it( 'hides an optional field', async () => {
- const user = userEvent.setup();
- renderControls( field.name, 'optional' );
-
- const visibilityToggle = screen.getByRole( 'checkbox', {
- name: field.label,
- } );
- expect( visibilityToggle ).toBeChecked();
- expect(
- screen.getByRole( 'radio', { name: 'Optional' } )
- ).toBeChecked();
-
- await user.click( visibilityToggle );
-
- expectUpdate( field.option, 'hidden' );
- } );
-
- it( 'makes an optional field required', async () => {
- const user = userEvent.setup();
- renderControls( field.name, 'optional' );
-
- expect(
- screen.getByRole( 'radio', { name: 'Optional' } )
- ).toBeChecked();
- await user.click( screen.getByRole( 'radio', { name: 'Required' } ) );
-
- expectUpdate( field.option, 'required' );
- } );
-
- it( 'makes a required field optional', async () => {
- const user = userEvent.setup();
- renderControls( field.name, 'required' );
-
- expect(
- screen.getByRole( 'radio', { name: 'Required' } )
- ).toBeChecked();
- await user.click( screen.getByRole( 'radio', { name: 'Optional' } ) );
-
- expectUpdate( field.option, 'optional' );
- } );
-} );
diff --git a/plugins/woocommerce/client/blocks/assets/js/blocks/checkout/test/edit.tsx b/plugins/woocommerce/client/blocks/assets/js/blocks/checkout/test/edit.tsx
deleted file mode 100644
index a67905b3428..00000000000
--- a/plugins/woocommerce/client/blocks/assets/js/blocks/checkout/test/edit.tsx
+++ /dev/null
@@ -1,276 +0,0 @@
-/**
- * External dependencies
- */
-import { render, screen } from '@testing-library/react';
-import { Form } from '@woocommerce/base-components/cart-checkout';
-import type { FormFields, ShippingAddress } from '@woocommerce/settings';
-
-/**
- * Internal dependencies
- */
-import { Edit } from '../edit';
-import type { Attributes } from '../types';
-
-let mockFieldSettings: Record< string, string > = {};
-let mockCapturedDefaultFields: FormFields | undefined;
-let mockRenderingCheckoutEdit = false;
-
-jest.mock( '@wordpress/data', () => {
- const data = jest.requireActual( '@wordpress/data' );
- return {
- ...data,
- useSelect: (
- mapSelect: ( select: ( store: unknown ) => unknown ) => unknown,
- dependencies?: unknown[]
- ) => {
- if ( mockRenderingCheckoutEdit ) {
- return mapSelect( () => ( {
- getEditedEntityRecord: () => mockFieldSettings,
- } ) );
- }
-
- return data.useSelect( mapSelect, dependencies );
- },
- };
-} );
-
-jest.mock( '@wordpress/block-editor', () => {
- const InnerBlocks = Object.assign(
- jest.fn( () => null ),
- {
- Content: jest.fn( () => null ),
- }
- );
- const useBlockProps = Object.assign(
- jest.fn( () => ( {} ) ),
- {
- save: jest.fn( () => ( {} ) ),
- }
- );
-
- return {
- InnerBlocks,
- InspectorControls: jest.fn( ( { children } ) => <>{ children }</> ),
- useBlockProps,
- };
-} );
-
-jest.mock( '@woocommerce/base-context', () => ( {
- ...jest.requireActual( '@woocommerce/base-context' ),
- CheckoutProvider: jest.fn( ( { children } ) => <>{ children }</> ),
- EditorProvider: jest.fn( ( { children, previewData } ) => {
- mockCapturedDefaultFields = previewData.defaultFields;
- return <>{ children }</>;
- } ),
- useCheckoutAddress: jest.fn( () => ( {
- defaultFields: mockCapturedDefaultFields,
- } ) ),
-} ) );
-
-jest.mock( '@woocommerce/base-components/sidebar-layout', () => ( {
- SidebarLayout: jest.fn( ( { children, className } ) => (
- <div className={ className }>{ children }</div>
- ) ),
-} ) );
-
-jest.mock( '@woocommerce/blocks-checkout', () => ( {
- ...jest.requireActual( '@woocommerce/blocks-checkout' ),
- SlotFillProvider: jest.fn( ( { children } ) => <>{ children }</> ),
-} ) );
-
-jest.mock( '../../cart-checkout-shared', () => ( {
- addClassToBody: jest.fn(),
- BlockSettings: jest.fn( () => null ),
- useBlockPropsWithLocking: jest.fn( () => ( {} ) ),
-} ) );
-
-jest.mock( '../inner-blocks', () => ( {} ) );
-
-const checkoutAttributes: Attributes = {
- hasDarkControls: false,
- showFormStepNumbers: false,
- showOrderNotes: true,
- showPolicyLinks: true,
- showReturnToCart: false,
- showRateAfterTaxName: false,
- cartPageId: 1,
- showCompanyField: false,
- requireCompanyField: false,
- showApartmentField: false,
- requireApartmentField: false,
- showPhoneField: false,
- requirePhoneField: false,
-};
-
-const emptyShippingAddress: ShippingAddress = {
- first_name: '',
- last_name: '',
- company: '',
- address_1: '',
- address_2: '',
- city: '',
- state: '',
- postcode: '',
- country: '',
- phone: '',
-};
-
-const renderCheckoutEdit = (
- fieldSettings: Record< string, string > = {},
- hasDarkControls = false
-) => {
- mockFieldSettings = fieldSettings;
- mockCapturedDefaultFields = undefined;
- mockRenderingCheckoutEdit = true;
- const result = render(
- <Edit
- clientId="checkout-client-id"
- attributes={ { ...checkoutAttributes, hasDarkControls } }
- setAttributes={ jest.fn() }
- />
- );
- mockRenderingCheckoutEdit = false;
-
- if ( ! mockCapturedDefaultFields ) {
- throw new Error( 'Checkout Edit did not provide default fields.' );
- }
-
- return result;
-};
-
-type FieldName = 'company' | 'address_2' | 'phone';
-type FieldState = 'hidden' | 'optional' | 'required';
-
-const fieldCases: Array< {
- field: FieldName;
- label: string;
- addLabel?: string;
-} > = [
- { field: 'company', label: 'Company' },
- {
- field: 'address_2',
- label: 'Apartment, suite, etc.',
- addLabel: '+ Add apartment, suite, etc.',
- },
- { field: 'phone', label: 'Phone' },
-];
-
-const stateCases: Array< {
- state: FieldState;
- hidden: boolean;
- required: boolean;
-} > = [
- { state: 'hidden', hidden: true, required: false },
- { state: 'optional', hidden: false, required: false },
- { state: 'required', hidden: false, required: true },
-];
-
-const expectHiddenField = ( label: string ) => {
- expect( screen.queryByLabelText( label ) ).not.toBeInTheDocument();
- expect(
- screen.queryByLabelText( `${ label } (optional)` )
- ).not.toBeInTheDocument();
-};
-
-const expectHiddenAddControl = ( addLabel: string ) => {
- expect(
- screen.queryByRole( 'button', { name: addLabel } )
- ).not.toBeInTheDocument();
-};
-
-const expectCollapsedOptionalAddressLine = (
- label: string,
- addLabel: string
-) => {
- expect( screen.getByRole( 'button', { name: addLabel } ) ).toBeVisible();
- expect( screen.getByLabelText( label ) ).toHaveAttribute(
- 'aria-hidden',
- 'true'
- );
-};
-
-const expectVisibleField = ( label: string, required: boolean ) => {
- const input = screen.getByLabelText(
- required ? label : `${ label } (optional)`
- );
- expect( input ).toBeVisible();
- expect( ( input as HTMLInputElement ).required ).toBe( required );
-};
-
-describe( 'Checkout editor consumers', () => {
- beforeEach( () => {
- mockFieldSettings = {};
- mockCapturedDefaultFields = undefined;
- mockRenderingCheckoutEdit = false;
- } );
-
- it( 'omits the dark controls class when hasDarkControls is false', () => {
- const { container } = renderCheckoutEdit();
- const checkoutLayout = container.querySelector( '.wc-block-checkout' );
-
- expect( checkoutLayout ).toBeInTheDocument();
- expect( checkoutLayout ).not.toHaveClass( 'has-dark-controls' );
- } );
-
- it( 'adds the dark controls class when hasDarkControls is true', () => {
- const { container } = renderCheckoutEdit( {}, true );
- const checkoutLayout = container.querySelector( '.wc-block-checkout' );
-
- expect( checkoutLayout ).toBeInTheDocument();
- expect( checkoutLayout ).toHaveClass( 'has-dark-controls' );
- } );
-
- it.each(
- fieldCases.flatMap( ( fieldCase ) =>
- stateCases.map( ( stateCase ) => ( {
- ...fieldCase,
- ...stateCase,
- } ) )
- )
- )(
- 'maps $field=$state from the root-site record into the real form',
- ( { field, label, addLabel, state, hidden, required } ) => {
- const optionName = `woocommerce_checkout_${ field }_field`;
- const { unmount } = renderCheckoutEdit( {
- [ optionName ]: state,
- } );
- const defaultFields = mockCapturedDefaultFields as FormFields;
-
- expect( defaultFields[ field ] ).toMatchObject( {
- hidden,
- required,
- } );
- unmount();
-
- const fields: ( keyof FormFields )[] =
- field === 'address_2'
- ? [ 'address_1', 'address_2' ]
- : [ field ];
- render(
- <Form< ShippingAddress >
- id="shipping"
- addressType="shipping"
- fields={ fields }
- isEditing
- onChange={ jest.fn() }
- values={ emptyShippingAddress }
- />
- );
-
- if ( hidden ) {
- expectHiddenField( label );
- if ( addLabel ) {
- expectHiddenAddControl( addLabel );
- }
- return;
- }
-
- if ( field === 'address_2' && ! required && addLabel ) {
- expectCollapsedOptionalAddressLine( label, addLabel );
- return;
- }
-
- expectVisibleField( label, required );
- }
- );
-} );
diff --git a/plugins/woocommerce/client/blocks/changelog/testops-234-checkout-block-editor-controls b/plugins/woocommerce/client/blocks/changelog/testops-234-checkout-block-editor-controls
deleted file mode 100644
index 58c19024dd3..00000000000
--- a/plugins/woocommerce/client/blocks/changelog/testops-234-checkout-block-editor-controls
+++ /dev/null
@@ -1,4 +0,0 @@
-Significance: patch
-Type: dev
-Comment: Move 5 Checkout block editor control E2E tests to Jest; the Checkout block merchant spec keeps 3 browser titles.
-
diff --git a/plugins/woocommerce/tests/e2e/tests/blocks/checkout/checkout-block.merchant.block_theme.spec.ts b/plugins/woocommerce/tests/e2e/tests/blocks/checkout/checkout-block.merchant.block_theme.spec.ts
index 71a987c4be6..dcb7aaee331 100644
--- a/plugins/woocommerce/tests/e2e/tests/blocks/checkout/checkout-block.merchant.block_theme.spec.ts
+++ b/plugins/woocommerce/tests/e2e/tests/blocks/checkout/checkout-block.merchant.block_theme.spec.ts
@@ -14,6 +14,16 @@ import {
import { CheckoutPage } from './checkout.page';
import { REGULAR_PRICED_PRODUCT_NAME } from './constants';
+declare global {
+ interface Window {
+ wcSettings: {
+ storePages: {
+ terms: { permalink: string };
+ privacy: { permalink: string };
+ };
+ };
+ }
+}
const blockData: BlockData = {
name: 'Checkout',
slug: 'woocommerce/checkout',
@@ -94,22 +104,80 @@ test.describe( 'Merchant → Checkout', () => {
);
} );
- test( 'Merchant must accept T&S before checkout', async ( {
+ test.describe( 'Can adjust T&S and Privacy Policy options', () => {
+ test( 'Merchant can see T&S and Privacy Policy links without checkbox', async ( {
+ page,
+ frontendUtils,
+ checkoutPageObject,
+ } ) => {
+ await frontendUtils.goToShop();
+ await frontendUtils.addToCart( REGULAR_PRICED_PRODUCT_NAME );
+ await frontendUtils.goToCheckout();
+ await expect(
+ frontendUtils.page.getByText(
+ 'By proceeding with your purchase you agree to our Terms and Conditions and Privacy Policy'
+ )
+ ).toBeVisible();
+
+ const termsAndConditions = frontendUtils.page
+ .getByRole( 'link' )
+ .getByText( 'Terms and Conditions' )
+ .first();
+ const privacyPolicy = frontendUtils.page
+ .getByRole( 'link' )
+ .getByText( 'Privacy Policy' )
+ .first();
+
+ const { termsPageUrl, privacyPageUrl } = await page.evaluate(
+ () => {
+ const { terms, privacy } = window.wcSettings.storePages;
+
+ return {
+ termsPageUrl: terms.permalink,
+ privacyPageUrl: privacy.permalink,
+ };
+ }
+ );
+ await expect( termsAndConditions ).toHaveAttribute(
+ 'href',
+ termsPageUrl
+ );
+ await expect( privacyPolicy ).toHaveAttribute(
+ 'href',
+ privacyPageUrl
+ );
+ await checkoutPageObject.fillInCheckoutWithTestData();
+ await checkoutPageObject.placeOrder();
+ await expect(
+ frontendUtils.page.getByText(
+ 'Thank you. Your order has been received.'
+ )
+ ).toBeVisible();
+ } );
+ } );
+
+ test( 'Merchant can see T&S and Privacy Policy links with checkbox', async ( {
frontendUtils,
checkoutPageObject,
+ admin,
editor,
} ) => {
+ await admin.visitSiteEditor( {
+ postId: `${ BLOCK_THEME_SLUG }//page-checkout`,
+ postType: 'wp_template',
+ canvas: 'edit',
+ } );
+ await editor.openDocumentSettingsSidebar();
await editor.selectBlocks(
blockSelectorInEditor +
' [data-type="woocommerce/checkout-terms-block"]'
);
- const requireTermsCheckbox = editor.page.getByRole( 'checkbox', {
+ let requireTermsCheckbox = editor.page.getByRole( 'checkbox', {
name: 'Require checkbox',
exact: true,
} );
await requireTermsCheckbox.check();
await editor.saveSiteEditorEntities();
-
await frontendUtils.goToShop();
await frontendUtils.addToCart( REGULAR_PRICED_PRODUCT_NAME );
await frontendUtils.goToCheckout();
@@ -123,7 +191,12 @@ test.describe( 'Merchant → Checkout', () => {
'aria-invalid',
'true'
);
- await checkboxWithError.check();
+
+ await frontendUtils.page
+ .getByLabel(
+ 'You must accept our Terms and Conditions and Privacy Policy to continue with your purchase.'
+ )
+ .check();
await checkoutPageObject.placeOrder();
await expect(
@@ -131,22 +204,6 @@ test.describe( 'Merchant → Checkout', () => {
'Thank you. Your order has been received'
)
).toBeVisible();
- } );
-
- test( 'Merchant can persist a required Company field', async ( {
- frontendUtils,
- admin,
- editor,
- requestUtils,
- } ) => {
- await requestUtils.rest( {
- method: 'POST',
- path: 'e2e-options/update',
- data: {
- option_name: 'woocommerce_checkout_company_field',
- option_value: 'hidden',
- },
- } );
await admin.visitSiteEditor( {
postId: `${ BLOCK_THEME_SLUG }//page-checkout`,
@@ -156,76 +213,359 @@ test.describe( 'Merchant → Checkout', () => {
await editor.openDocumentSettingsSidebar();
await editor.selectBlocks(
blockSelectorInEditor +
- ' [data-type="woocommerce/checkout-shipping-address-block"]'
- );
-
- const shippingAddressBlock = await editor.getBlockByName(
- 'woocommerce/checkout-shipping-address-block'
+ ' [data-type="woocommerce/checkout-terms-block"]'
);
- const shippingCompanyInput =
- shippingAddressBlock.getByLabel( 'Company' );
- const shippingCompanyToggle = editor.page.getByRole( 'checkbox', {
- name: 'Company',
+ requireTermsCheckbox = editor.page.getByRole( 'checkbox', {
+ name: 'Require checkbox',
exact: true,
} );
- const companyRequirement = editor.page.locator(
- '.wc-block-components-require-company-field'
- );
+ await requireTermsCheckbox.uncheck();
+ await editor.saveSiteEditorEntities();
+ } );
- await expect( shippingCompanyToggle ).not.toBeChecked();
- await expect( shippingCompanyInput ).toBeHidden();
- await expect( async () => {
- await shippingCompanyToggle.check();
- } ).toPass();
- await expect( shippingCompanyInput ).toBeVisible();
- await expect(
- companyRequirement.getByRole( 'radio', { name: 'Optional' } )
- ).toBeChecked();
- await expect( shippingCompanyInput ).not.toHaveAttribute( 'required' );
+ test.describe( 'Attributes', () => {
+ test.beforeEach( async ( { editor } ) => {
+ await editor.openDocumentSettingsSidebar();
+ await editor.selectBlocks( blockSelectorInEditor );
+ } );
+
+ test( 'can enable dark mode inputs', async ( { editor, page } ) => {
+ const toggleLabel = page.getByLabel( 'Dark mode inputs' );
+ await toggleLabel.check();
- const requiredCompany = companyRequirement.getByRole( 'radio', {
- name: 'Required',
+ const shippingAddressBlock = await editor.getBlockByName(
+ 'woocommerce/checkout'
+ );
+
+ const darkControls = shippingAddressBlock.locator(
+ '.wc-block-checkout.has-dark-controls'
+ );
+ await expect( darkControls ).toBeVisible();
+ await toggleLabel.uncheck();
+ await expect( darkControls ).toBeHidden();
} );
- await expect( async () => {
- await requiredCompany.check();
- } ).toPass();
- await expect( requiredCompany ).toBeChecked();
- await expect( shippingCompanyInput ).toHaveAttribute( 'required' );
- await editor.saveSiteEditorEntities();
- await admin.visitSiteEditor( {
- postId: `${ BLOCK_THEME_SLUG }//page-checkout`,
- postType: 'wp_template',
- canvas: 'edit',
+ test.describe( 'Shipping and billing addresses', () => {
+ test.beforeEach( async ( { editor } ) => {
+ await editor.openDocumentSettingsSidebar();
+ await editor.selectBlocks( blockSelectorInEditor );
+ } );
+
+ test( 'Company input visibility and optional and required can be toggled', async ( {
+ editor,
+ } ) => {
+ await editor.selectBlocks(
+ blockSelectorInEditor +
+ ' [data-type="woocommerce/checkout-shipping-address-block"]'
+ );
+
+ const shippingAddressBlock = await editor.getBlockByName(
+ 'woocommerce/checkout-shipping-address-block'
+ );
+
+ const shippingCompanyInput =
+ shippingAddressBlock.getByLabel( 'Company' );
+
+ const shippingCompanyToggle = editor.page.getByRole(
+ 'checkbox',
+ {
+ name: 'Company',
+ exact: true,
+ }
+ );
+
+ const shippingCompanyOptionalToggle = editor.page.locator(
+ '.wc-block-components-require-company-field >> text="Optional"'
+ );
+
+ const shippingCompanyRequiredToggle = editor.page.locator(
+ '.wc-block-components-require-company-field >> text="Required"'
+ );
+
+ // Verify that the company field is hidden by default.
+ await expect( shippingCompanyInput ).toBeHidden();
+
+ // Enable the company field.
+ await expect( async () => {
+ await shippingCompanyToggle.check();
+ } ).toPass();
+
+ // Verify that the company field is visible and the field is optional.
+ await expect( shippingCompanyInput ).toBeVisible();
+ await expect( shippingCompanyOptionalToggle ).toBeChecked();
+ await expect( shippingCompanyInput ).not.toHaveAttribute(
+ 'required'
+ );
+
+ // Make the company field required.
+ await expect( async () => {
+ await shippingCompanyRequiredToggle.check();
+ } ).toPass();
+
+ // Verify that the company field is required.
+ await expect( shippingCompanyRequiredToggle ).toBeChecked();
+
+ // Disable the company field.
+ await expect( async () => {
+ await shippingCompanyToggle.uncheck();
+ } ).toPass();
+
+ // Verify that the company field is hidden.
+ await expect( shippingCompanyInput ).toBeHidden();
+
+ // Display the billing address form.
+ await editor.canvas
+ .getByLabel( 'Use same address for billing' )
+ .uncheck();
+
+ await editor.selectBlocks(
+ blockSelectorInEditor +
+ ' [data-type="woocommerce/checkout-billing-address-block"]'
+ );
+
+ const billingAddressBlock = await editor.getBlockByName(
+ 'woocommerce/checkout-billing-address-block'
+ );
+
+ const billingCompanyInput =
+ billingAddressBlock.getByLabel( 'Company' );
+
+ const billingCompanyToggle = editor.page.getByRole(
+ 'checkbox',
+ {
+ name: 'Company',
+ exact: true,
+ }
+ );
+
+ // Verify the company field on the billing address has the correct state from the shipping address.
+ await expect( billingCompanyToggle ).not.toBeChecked();
+ await expect( billingCompanyInput ).toBeHidden();
+ } );
+
+ test( 'Apartment input visibility and optional and required can be toggled', async ( {
+ editor,
+ } ) => {
+ await editor.selectBlocks(
+ blockSelectorInEditor +
+ ' [data-type="woocommerce/checkout-shipping-address-block"]'
+ );
+
+ const shippingAddressBlock = await editor.getBlockByName(
+ 'woocommerce/checkout-shipping-address-block'
+ );
+
+ const shippingApartmentInput = shippingAddressBlock.getByLabel(
+ 'Apartment, suite, etc.'
+ );
+
+ const shippingApartmentLink = shippingAddressBlock.getByRole(
+ 'button',
+ {
+ name: '+ Add apartment, suite, etc.',
+ }
+ );
+
+ const shippingApartmentToggle = editor.page.getByRole(
+ 'checkbox',
+ {
+ name: 'Address line 2',
+ exact: true,
+ }
+ );
+
+ const shippingApartmentOptionalToggle = editor.page.locator(
+ '.wc-block-components-require-address_2-field >> text="Optional"'
+ );
+
+ const shippingApartmentRequiredToggle = editor.page.locator(
+ '.wc-block-components-require-address_2-field >> text="Required"'
+ );
+
+ // Verify that the apartment link is visible by default.
+ await expect( shippingApartmentLink ).toBeVisible();
+
+ // Verify that the apartment field is hidden by default and the field is optional.
+ await expect( shippingApartmentInput ).not.toBeInViewport();
+ await expect( shippingApartmentOptionalToggle ).toBeChecked();
+
+ // Make the apartment number required.
+ await expect( async () => {
+ await shippingApartmentRequiredToggle.check();
+ } ).toPass();
+
+ // Verify that the apartment field is required.
+ await expect( shippingApartmentRequiredToggle ).toBeChecked();
+ await expect( shippingApartmentInput ).toHaveAttribute(
+ 'required'
+ );
+
+ // Disable the apartment field.
+ await expect( async () => {
+ await shippingApartmentToggle.uncheck();
+ } ).toPass();
+
+ // Verify that the apartment link and the apartment field are hidden.
+ await expect( shippingApartmentLink ).toBeHidden();
+ await expect( shippingApartmentInput ).not.toBeInViewport();
+
+ // Display the billing address form.
+ await editor.canvas
+ .getByLabel( 'Use same address for billing' )
+ .uncheck();
+
+ await editor.selectBlocks(
+ blockSelectorInEditor +
+ ' [data-type="woocommerce/checkout-billing-address-block"]'
+ );
+
+ const billingAddressBlock = await editor.getBlockByName(
+ 'woocommerce/checkout-billing-address-block'
+ );
+
+ const billingApartmentInput = billingAddressBlock.getByLabel(
+ 'Apartment, suite, etc.'
+ );
+
+ const billingApartmentLink = billingAddressBlock.getByRole(
+ 'button',
+ {
+ name: '+ Add apartment, suite, etc.',
+ }
+ );
+
+ const billingApartmentToggle = editor.page.getByRole(
+ 'checkbox',
+ {
+ name: 'Address line 2',
+ exact: true,
+ }
+ );
+
+ // Verify the apartment field on the billing address has the correct state from the shipping address.
+ await expect( billingApartmentToggle ).not.toBeChecked();
+ await expect( billingApartmentLink ).toBeHidden();
+ await expect( billingApartmentInput ).not.toBeInViewport();
+ } );
+
+ test( 'Phone input visibility and optional and required can be toggled', async ( {
+ editor,
+ } ) => {
+ await editor.selectBlocks(
+ blockSelectorInEditor +
+ ' [data-type="woocommerce/checkout-shipping-address-block"]'
+ );
+
+ const shippingAddressBlock = await editor.getBlockByName(
+ 'woocommerce/checkout-shipping-address-block'
+ );
+
+ const shippingPhoneInput =
+ shippingAddressBlock.getByLabel( 'Phone' );
+
+ const shippingPhoneToggle = editor.page.getByRole( 'checkbox', {
+ name: 'Phone',
+ exact: true,
+ } );
+
+ const shippingPhoneOptionalToggle = editor.page.locator(
+ '.wc-block-components-require-phone-field >> text="Optional"'
+ );
+
+ const shippingPhoneRequiredToggle = editor.page.locator(
+ '.wc-block-components-require-phone-field >> text="Required"'
+ );
+
+ // Verify that the phone field is visible by default and the field is optional.
+ await expect( shippingPhoneInput ).toBeVisible();
+ await expect( shippingPhoneOptionalToggle ).toBeChecked();
+ await expect( shippingPhoneInput ).not.toHaveAttribute(
+ 'required'
+ );
+
+ // Make the phone number required.
+ await expect( async () => {
+ await shippingPhoneRequiredToggle.check();
+ } ).toPass();
+
+ // Verify that the phone field is required.
+ await expect( shippingPhoneRequiredToggle ).toBeChecked();
+ await expect( shippingPhoneInput ).toHaveAttribute(
+ 'required'
+ );
+
+ // Disable the phone field.
+ await expect( async () => {
+ await shippingPhoneToggle.uncheck();
+ } ).toPass();
+
+ // Verify that the phone field is hidden.
+ await expect( shippingPhoneInput ).toBeHidden();
+
+ // Display the billing address form.
+ await editor.canvas
+ .getByLabel( 'Use same address for billing' )
+ .uncheck();
+
+ await editor.selectBlocks(
+ blockSelectorInEditor +
+ ' [data-type="woocommerce/checkout-billing-address-block"]'
+ );
+
+ const billingAddressBlock = await editor.getBlockByName(
+ 'woocommerce/checkout-billing-address-block'
+ );
+
+ const billingPhoneInput =
+ billingAddressBlock.getByLabel( 'Phone' );
+
+ const billingPhoneToggle = editor.page.getByRole( 'checkbox', {
+ name: 'Phone',
+ exact: true,
+ } );
+
+ // Verify the phone field on the billing address has the correct state from the shipping address.
+ await expect( billingPhoneToggle ).not.toBeChecked();
+ await expect( billingPhoneInput ).toBeHidden();
+ } );
} );
- await editor.openDocumentSettingsSidebar();
- await editor.selectBlocks(
- blockSelectorInEditor +
- ' [data-type="woocommerce/checkout-shipping-address-block"]'
- );
- await expect(
- editor.page
- .locator( '.wc-block-components-require-company-field' )
- .getByRole( 'radio', { name: 'Required' } )
- ).toBeChecked();
+ } );
- await frontendUtils.goToShop();
- await frontendUtils.addToCart( REGULAR_PRICED_PRODUCT_NAME );
- await frontendUtils.goToCheckout();
+ test.describe( 'Checkout actions', () => {
+ test.beforeEach( async ( { editor } ) => {
+ await editor.openDocumentSettingsSidebar();
+ await editor.selectBlocks( blockSelectorInEditor );
+ } );
- const shippingCompany = frontendUtils.page
- .getByRole( 'group', { name: 'Shipping address' } )
- .getByLabel( 'Company' );
- await expect( shippingCompany ).toBeVisible();
- await expect( shippingCompany ).toHaveAttribute( 'required' );
+ test( 'Return to cart link is visible and can be toggled', async ( {
+ editor,
+ } ) => {
+ await editor.selectBlocks(
+ `${ blockSelectorInEditor } .wp-block-woocommerce-checkout-actions-block`
+ );
- await frontendUtils.page
- .getByLabel( 'Use same address for billing' )
- .uncheck();
- const billingCompany = frontendUtils.page
- .getByRole( 'group', { name: 'Billing address' } )
- .getByLabel( 'Company' );
- await expect( billingCompany ).toBeVisible();
- await expect( billingCompany ).toHaveAttribute( 'required' );
+ // Turn on return to cart link and check it's visible in the block.
+ const returnToCartLinkToggle = editor.page.getByLabel(
+ 'Show a "Return to Cart" link',
+ { exact: true }
+ );
+ await returnToCartLinkToggle.check();
+ const shippingAddressBlock = await editor.getBlockByName(
+ 'woocommerce/checkout-actions-block'
+ );
+
+ // Turn on return to cart link and check it shows in the block.
+ const returnToCartLink = shippingAddressBlock.getByText(
+ 'Return to Cart',
+ { exact: true }
+ );
+
+ // Turn off return to cart link and check it's not visible in the block.
+ await expect( returnToCartLink ).toBeVisible();
+
+ await returnToCartLinkToggle.uncheck();
+
+ await expect( returnToCartLink ).toBeHidden();
+ } );
} );
} );