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();
+		} );
 	} );
 } );