Commit 60fc8f35513 for woocommerce

commit 60fc8f355134ec8045502fd5aa94d1afea7e084d
Author: Vlad Olaru <vlad.olaru@automattic.com>
Date:   Tue Sep 15 14:09:12 2026 +0300

    [tests] Reduce Checkout block shopper E2E tests from 13 to 5 (#68592)

    * test(blocks): Reduce Checkout block shopper E2E tests from 13 to 5

    The Checkout block shopper spec ran twelve browser titles and one
    skipped title. Several repeated journeys that other retained titles
    already walk, and one checked a shipping-topology guard that decides
    whether the Ship and Pickup choice renders at all.

    Move that guard below the browser: a Jest suite for the shipping
    method FrontendBlock checks the choice renders when every topology
    condition holds, and disappears when ordinary methods don't exist,
    store shipping is off, or the cart doesn't need shipping. A Checkout
    block PHPUnit test checks that enqueue_data exposes
    shippingMethodsExist and shippingEnabled from the store's real
    shipping setup. Drop the skipped account title and the duplicate
    pickup, postcode, guest order, digital order, and company field
    titles. Keep five browser titles: switching between pickup and
    shipping, choosing rates with separate addresses, ordering with store
    shipping disabled, the incomplete form errors, and the empty billing
    form. In the rates title, replace a phone comparison that could never
    fail with web-first checks of the real values.

    Consolidates the mega-branch slices:
    - Slice 011: test(blocks): Consolidate checkout shopper coverage
    - test: Fix migration branch lint (import order in the new Jest
      suite)
    - refactor(e2e): simplify migrated Blocks test contracts (this spec
      only)

    Refs TESTOPS-234
    Refs #68046

    Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

    * test(blocks): Stop the Checkout topology test restoring base-class state

    The finally block deleted the shipping zone, wrote every
    woocommerce_shipping_zone_methods row back to its previous is_enabled
    value, and restored two options. All of those are rows inside the
    per-test transaction, which tear_down() rolls back first.

    The query that reads the ambient method rows stays, because the test
    has to switch those methods off before it can assert on the topology.
    It no longer needs is_enabled, only the instance ids, so it stops
    selecting a column it was reading purely to write back.

    flush_shipping_method_cache() stays in the finally. It reloads the memo
    on the WC_Shipping singleton, and this class extends WP_UnitTestCase
    rather than WC_Unit_Test_Case, so nothing else puts that back.

    Same 2 tests and 13 assertions before and after.

    Refs TESTOPS-234

    Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

    * test(blocks): Drop the shipping memo instead of reloading it

    The topology test's finally called flush_shipping_method_cache(), whose
    last statement is load_shipping_methods(). That runs before tear_down()
    rolls anything back, so it rebuilds the WC_Shipping memo from option
    values the test is about to revert, and the rebuilt memo outlives the
    rollback.

    A review flagged this as leaking an enabled pickup_location into every
    later test. It does not: a probe test placed immediately after this one
    reports the memo as [flat_rate, free_shipping, local_pickup], with
    pickup_location absent, because ShippingController does not register it
    in the test environment. So there is no live leak to fix.

    Change it anyway, because it is clean by accident rather than by design
    and the correct call is no longer than the wrong one.
    unregister_shipping_methods() nulls the memo so the next reader reloads
    from the database once the transaction is gone, which is what the sibling
    order-confirmation tests already do.

    Suite unchanged at 15139 tests and 58767 assertions.

    Refs TESTOPS-234

    Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

    ---------

    Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>

diff --git a/plugins/woocommerce/changelog/testops-234-checkout-block-shopper b/plugins/woocommerce/changelog/testops-234-checkout-block-shopper
new file mode 100644
index 00000000000..903e321f1e7
--- /dev/null
+++ b/plugins/woocommerce/changelog/testops-234-checkout-block-shopper
@@ -0,0 +1,4 @@
+Significance: patch
+Type: dev
+Comment: Reduce Checkout block shopper E2E tests from 13 to 5; a Jest suite and a Checkout block PHPUnit test own the shipping-topology guard.
+
diff --git a/plugins/woocommerce/client/blocks/assets/js/blocks/checkout/inner-blocks/checkout-shipping-method-block/test/frontend.tsx b/plugins/woocommerce/client/blocks/assets/js/blocks/checkout/inner-blocks/checkout-shipping-method-block/test/frontend.tsx
new file mode 100644
index 00000000000..bbdfb9c9872
--- /dev/null
+++ b/plugins/woocommerce/client/blocks/assets/js/blocks/checkout/inner-blocks/checkout-shipping-method-block/test/frontend.tsx
@@ -0,0 +1,172 @@
+/**
+ * External dependencies
+ */
+import { render, screen } from '@testing-library/react';
+import { useDispatch, useSelect } from '@wordpress/data';
+
+/**
+ * Internal dependencies
+ */
+import { useShippingData } from '@woocommerce/base-context/hooks';
+import { useCheckoutBlockContext } from '@woocommerce/blocks/checkout/context';
+import FrontendBlock from '../frontend';
+
+let mockNeedsShipping = true;
+
+jest.mock( '@woocommerce/block-settings', () => {
+	const settings = {
+		shippingEnabled: true,
+		shippingMethodsExist: true,
+	};
+	(
+		globalThis as typeof globalThis & {
+			checkoutShippingMethodTestSettings: typeof settings;
+		}
+	 ).checkoutShippingMethodTestSettings = settings;
+
+	return {
+		...jest.requireActual( '@woocommerce/block-settings' ),
+		get SHIPPING_ENABLED() {
+			return settings.shippingEnabled;
+		},
+		get SHIPPING_METHODS_EXIST() {
+			return settings.shippingMethodsExist;
+		},
+		LOCAL_PICKUP_ENABLED: true,
+	};
+} );
+
+jest.mock( '@woocommerce/settings', () => ( {
+	...jest.requireActual( '@woocommerce/settings' ),
+	getSetting: jest.fn( ( key, defaultValue ) =>
+		key === 'collectableMethodIds' ? [ 'pickup_location' ] : defaultValue
+	),
+} ) );
+
+jest.mock( '@wordpress/data', () => ( {
+	...jest.requireActual( '@wordpress/data' ),
+	useDispatch: jest.fn(),
+	useSelect: jest.fn(),
+} ) );
+
+jest.mock( '@woocommerce/base-context/hooks', () => ( {
+	useShippingData: jest.fn(),
+} ) );
+
+jest.mock( '@woocommerce/blocks/checkout/context', () => ( {
+	useCheckoutBlockContext: jest.fn(),
+} ) );
+
+const shippingRates = [
+	{
+		shipping_rates: [
+			{
+				method_id: 'flat_rate',
+				price: '500',
+				taxes: '0',
+			},
+			{
+				method_id: 'pickup_location',
+				price: '0',
+				taxes: '0',
+			},
+		],
+	},
+];
+
+const getBlockSettings = () =>
+	(
+		globalThis as typeof globalThis & {
+			checkoutShippingMethodTestSettings: {
+				shippingEnabled: boolean;
+				shippingMethodsExist: boolean;
+			};
+		}
+	 ).checkoutShippingMethodTestSettings;
+
+const renderFrontendBlock = () =>
+	render(
+		<FrontendBlock
+			title="Delivery"
+			description=""
+			showPrice={ false }
+			showIcon={ false }
+			shippingText="Ship"
+			localPickupText="Pickup"
+		>
+			<div />
+		</FrontendBlock>
+	);
+
+describe( 'Checkout shipping method FrontendBlock', () => {
+	beforeEach( () => {
+		getBlockSettings().shippingEnabled = true;
+		getBlockSettings().shippingMethodsExist = true;
+		mockNeedsShipping = true;
+
+		( useCheckoutBlockContext as jest.Mock ).mockReturnValue( {
+			showFormStepNumbers: false,
+		} );
+		( useShippingData as jest.Mock ).mockImplementation( () => ( {
+			needsShipping: mockNeedsShipping,
+			isCollectable: true,
+			shippingRates,
+		} ) );
+		( useSelect as jest.Mock ).mockImplementation( ( mapSelect ) =>
+			mapSelect( () => ( {
+				isProcessing: () => false,
+				prefersCollection: () => false,
+				getShippingRates: () => shippingRates,
+			} ) )
+		);
+		( useDispatch as jest.Mock ).mockReturnValue( {
+			setPrefersCollection: jest.fn(),
+			selectShippingRate: jest.fn(),
+			setValidationErrors: jest.fn(),
+			clearValidationError: jest.fn(),
+		} );
+	} );
+
+	it( 'renders the Ship and Pickup choices when every topology guard passes', () => {
+		renderFrontendBlock();
+
+		expect(
+			screen.getByRole( 'radiogroup', { name: 'Shipping method' } )
+		).toBeInTheDocument();
+		expect(
+			screen.getByRole( 'radio', { name: 'Ship' } )
+		).toBeInTheDocument();
+		expect(
+			screen.getByRole( 'radio', { name: 'Pickup' } )
+		).toBeInTheDocument();
+	} );
+
+	it.each( [
+		[
+			'ordinary shipping methods do not exist',
+			() => {
+				getBlockSettings().shippingMethodsExist = false;
+			},
+		],
+		[
+			'store shipping is disabled',
+			() => {
+				getBlockSettings().shippingEnabled = false;
+			},
+		],
+		[
+			'the cart does not need shipping',
+			() => {
+				mockNeedsShipping = false;
+			},
+		],
+	] )( 'does not render when %s', ( _, disableGuard ) => {
+		disableGuard();
+
+		renderFrontendBlock();
+
+		expect(
+			screen.queryByRole( 'radiogroup', { name: 'Shipping method' } )
+		).not.toBeInTheDocument();
+	} );
+} );
diff --git a/plugins/woocommerce/client/blocks/changelog/testops-234-checkout-block-shopper b/plugins/woocommerce/client/blocks/changelog/testops-234-checkout-block-shopper
new file mode 100644
index 00000000000..903e321f1e7
--- /dev/null
+++ b/plugins/woocommerce/client/blocks/changelog/testops-234-checkout-block-shopper
@@ -0,0 +1,4 @@
+Significance: patch
+Type: dev
+Comment: Reduce Checkout block shopper E2E tests from 13 to 5; a Jest suite and a Checkout block PHPUnit test own the shipping-topology guard.
+
diff --git a/plugins/woocommerce/tests/e2e/tests/blocks/checkout/checkout-block.shopper.block_theme.spec.ts b/plugins/woocommerce/tests/e2e/tests/blocks/checkout/checkout-block.shopper.block_theme.spec.ts
index da700957ea9..38a3cc3ca60 100644
--- a/plugins/woocommerce/tests/e2e/tests/blocks/checkout/checkout-block.shopper.block_theme.spec.ts
+++ b/plugins/woocommerce/tests/e2e/tests/blocks/checkout/checkout-block.shopper.block_theme.spec.ts
@@ -6,21 +6,17 @@ import {
 	test as base,
 	customerFile,
 	guestFile,
-	BlockData,
-	BLOCK_THEME_SLUG,
 } from '@woocommerce/e2e-utils';

 /**
  * Internal dependencies
  */
 import {
-	REGULAR_PRICED_PRODUCT_NAME,
 	SIMPLE_PHYSICAL_PRODUCT_NAME,
 	FREE_SHIPPING_NAME,
 	FREE_SHIPPING_PRICE,
 	FLAT_RATE_SHIPPING_NAME,
 	FLAT_RATE_SHIPPING_PRICE,
-	SIMPLE_VIRTUAL_PRODUCT_NAME,
 } from './constants';
 import { CheckoutPage } from './checkout.page';

@@ -34,144 +30,21 @@ const test = base.extend< { checkoutPageObject: CheckoutPage } >( {
 	},
 } );

-const blockData: BlockData = {
-	name: 'Checkout',
-	slug: 'woocommerce/checkout',
-	mainClass: '.wp-block-woocommerce-checkout',
-	selectors: {
-		editor: {
-			block: '.wp-block-woocommerce-checkout',
-			insertButton: "//button//span[text()='Checkout']",
-		},
-		frontend: {},
-	},
-};
-
-test.describe( 'Shopper → Account (guest user)', () => {
-	test.use( { storageState: guestFile } );
-
-	test.beforeEach( async ( { requestUtils, frontendUtils } ) => {
-		await requestUtils.rest( {
-			method: 'PUT',
-			path: 'wc/v3/settings/account/woocommerce_enable_guest_checkout',
-			data: { value: 'yes' },
-		} );
-		await requestUtils.rest( {
-			method: 'PUT',
-			path: 'wc/v3/settings/account/woocommerce_enable_checkout_login_reminder',
-			data: { value: 'yes' },
-		} );
-
-		await frontendUtils.goToShop();
-		await frontendUtils.addToCart( REGULAR_PRICED_PRODUCT_NAME );
-		await frontendUtils.goToCheckout();
-	} );
-
-	// eslint-disable-next-line playwright/no-skipped-test -- This will be rewritten as a unit/integration test - WOOPLUG-4303
-	test.skip( 'Shopper can log in to an existing account and can create an account', async ( {
-		requestUtils,
-		checkoutPageObject,
-		page,
-		baseURL,
-	} ) => {
-		//Get the login link from checkout page.
-		const loginLink = page.getByRole( 'link', { name: 'Log in' } );
-
-		await expect( loginLink ).toHaveAttribute(
-			'href',
-			baseURL +
-				'/my-account/?redirect_to=' +
-				encodeURIComponent( baseURL + '/checkout/' )
-		);
-
-		await requestUtils.rest( {
-			method: 'PUT',
-			path: 'wc/v3/settings/account/woocommerce_enable_signup_and_login_from_checkout',
-			data: { value: 'yes' },
-		} );
-		await requestUtils.rest( {
-			method: 'PUT',
-			path: 'wc/v3/settings/account/woocommerce_registration_generate_password',
-			data: { value: 'yes' },
-		} );
-
-		await page.reload();
-
-		const createAccount = page.getByLabel( 'Create an account' );
-		await createAccount.check();
-
-		const testEmail = `test-${ Date.now() }@example.com`;
-		await checkoutPageObject.fillInCheckoutWithTestData( {
-			email: testEmail,
-		} );
-		await checkoutPageObject.placeOrder();
-
-		// Get users from API with same email used when purchasing.
-		await requestUtils
-			.rest( {
-				method: 'GET',
-				path: `wc/v3/customers?email=${ testEmail }`,
-			} )
-			.then( ( response ) => {
-				expect( response[ 0 ].email ).toBe( testEmail );
-			} );
-	} );
-} );
-
 test.describe( 'Shopper → Local pickup', () => {
-	test.beforeEach( async ( { admin } ) => {
-		// Enable local pickup.
-		await admin.visitAdminPage(
-			'admin.php',
-			'page=wc-settings&tab=shipping&section=pickup_location'
-		);
-		await admin.page.getByLabel( 'Enable local pickup' ).check();
-		await admin.page
-			.getByRole( 'button', { name: 'Add pickup location' } )
-			.click();
-		await admin.page.getByLabel( 'Location name' ).fill( 'Testing' );
-		await admin.page.getByPlaceholder( 'Address' ).fill( 'Test Address' );
-		await admin.page.getByPlaceholder( 'City' ).fill( 'Test City' );
-		await admin.page.getByPlaceholder( 'Postcode / ZIP' ).fill( '90210' );
-		await admin.page
-			.getByLabel( 'Pickup details' )
-			.fill( 'Pickup method.' );
-		await admin.page.getByRole( 'button', { name: 'Done' } ).click();
-		await admin.page
-			.getByRole( 'button', { name: 'Save changes' } )
-			.click();
-		await admin.page.waitForResponse( ( response ) => {
-			return response.url().includes( 'wp-json/wc/v3/pickup-locations' );
+	test.beforeEach( async ( { localPickupUtils } ) => {
+		await localPickupUtils.enableLocalPickup();
+		await localPickupUtils.addPickupLocation( {
+			location: {
+				name: 'Testing',
+				address: 'Test Address',
+				city: 'Test City',
+				postcode: '90210',
+				state: 'US:CA',
+				details: 'Pickup method.',
+			},
 		} );
 	} );

-	test( 'The shopper can choose a local pickup option', async ( {
-		page,
-		frontendUtils,
-		checkoutPageObject,
-	} ) => {
-		await frontendUtils.goToShop();
-		await frontendUtils.addToCart( SIMPLE_PHYSICAL_PRODUCT_NAME );
-		await frontendUtils.goToCheckout();
-
-		await checkoutPageObject.selectDeliveryOption( 'Pickup' );
-		await expect( page.getByLabel( 'Testing' ).last() ).toBeVisible();
-		await page.getByLabel( 'Testing' ).last().check();
-
-		await checkoutPageObject.fillInCheckoutWithTestData();
-		await checkoutPageObject.placeOrder();
-
-		await expect(
-			page.getByText( 'Thank you. Your order has been received.' )
-		).toBeVisible();
-
-		await expect(
-			// The regex pattern matches "Collection from Testing" followed by any characters (.*)
-			page.getByRole( 'cell', { name: /Collection from Testing.*/ } )
-		).toBeVisible();
-		await checkoutPageObject.verifyBillingDetails();
-	} );
-
 	test( 'Switching between local pickup and shipping does not affect the address and is used for the order', async ( {
 		page,
 		frontendUtils,
@@ -221,152 +94,6 @@ test.describe( 'Shopper → Local pickup', () => {
 		).toBeVisible();
 		await checkoutPageObject.verifyBillingDetails();
 	} );
-
-	test( 'Delivery/pickup toggle is not shown when shipping methods are disabled', async ( {
-		admin,
-		page,
-		frontendUtils,
-		checkoutPageObject,
-	} ) => {
-		// Disable hide rates until address is entered.
-		await admin.visitAdminPage(
-			'admin.php',
-			'page=wc-settings&tab=shipping&section=options'
-		);
-
-		await admin.page
-			.getByLabel( 'Hide shipping costs until an address is entered' )
-			.uncheck();
-
-		let saveButton = admin.page.getByRole( 'button', {
-			name: 'Save changes',
-		} );
-
-		if ( await saveButton.isEnabled() ) {
-			await saveButton.click();
-		}
-
-		// Disable all other shipping methods.
-		await admin.visitAdminPage(
-			'admin.php',
-			'page=wc-settings&tab=shipping&zone_id=0'
-		);
-
-		// There are 2 shipping methods and 2 toggles with our test data. Disable both.
-		await admin.page.getByRole( 'link', { name: 'Yes' } ).first().click();
-		await admin.page.getByRole( 'link', { name: 'Yes' } ).last().click();
-
-		saveButton = admin.page.getByRole( 'button', {
-			name: 'Save changes',
-		} );
-
-		await saveButton.click();
-
-		// Go to checkout.
-		await frontendUtils.goToShop();
-		await frontendUtils.addToCart( SIMPLE_PHYSICAL_PRODUCT_NAME );
-		await frontendUtils.goToCheckout();
-
-		await expect(
-			page.getByRole( 'radio', { name: 'Pickup', exact: true } )
-		).toBeHidden();
-
-		await expect(
-			page.getByRole( 'radio', { name: 'Ship', exact: true } )
-		).toBeHidden();
-
-		await expect( page.getByLabel( 'Testing' ).last() ).toBeVisible();
-		await page.getByLabel( 'Testing' ).last().check();
-
-		await checkoutPageObject.fillInCheckoutWithTestData();
-		await checkoutPageObject.placeOrder();
-
-		await expect(
-			page.getByText( 'Thank you. Your order has been received.' )
-		).toBeVisible();
-
-		await expect(
-			// The regex pattern matches "Collection from Testing" followed by any characters (.*)
-			page.getByRole( 'cell', { name: /Collection from Testing.*/ } )
-		).toBeVisible();
-		await checkoutPageObject.verifyBillingDetails();
-	} );
-} );
-
-test.describe( 'Shopper → Shipping and Billing Addresses', () => {
-	const billingTestData = {
-		firstname: 'John',
-		lastname: 'Doe',
-		company: 'Automattic',
-		addressfirstline: '123 Main Road',
-		addresssecondline: 'Unit 23',
-		city: 'San Francisco',
-		state: 'California',
-		country: 'United Kingdom',
-		countryKey: 'GB',
-		postcode: 'SW1 1AA',
-		phone: '123456789',
-		email: 'john.doe@example.com',
-	};
-	const shippingTestData = {
-		firstname: 'Jane',
-		lastname: 'Doe',
-		company: 'WooCommerce',
-		addressfirstline: '123 Main Avenue',
-		addresssecondline: 'Unit 42',
-		city: 'Los Angeles',
-		phone: '987654321',
-		country: 'Albania',
-		countryKey: 'AL',
-		state: 'Berat',
-		postcode: '1234',
-	};
-	// `as string` is safe here because we know the variable is a string, it is defined above.
-	const blockSelectorInEditor = blockData.selectors.editor.block as string;
-
-	test.beforeEach( async ( { admin, editor, page } ) => {
-		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-shipping-address-block"]'
-		);
-		const checkbox = page.getByRole( 'checkbox', {
-			name: 'Company',
-			exact: true,
-		} );
-		await checkbox.click();
-		await expect( checkbox ).toBeChecked();
-		await expect(
-			editor.canvas.locator(
-				'div.wc-block-components-address-form__company'
-			)
-		).toBeVisible();
-		await editor.saveSiteEditorEntities();
-	} );
-
-	test( 'User can add postcodes for different countries', async ( {
-		frontendUtils,
-		page,
-		checkoutPageObject,
-	} ) => {
-		await frontendUtils.goToShop();
-		await frontendUtils.addToCart( SIMPLE_PHYSICAL_PRODUCT_NAME );
-		await frontendUtils.goToCheckout();
-
-		await page.getByLabel( 'Use same address for billing' ).uncheck();
-
-		await checkoutPageObject.fillShippingDetails( shippingTestData );
-		await checkoutPageObject.fillBillingDetails( billingTestData );
-		await expect(
-			page.getByText( 'Please enter a valid postcode' )
-		).toBeHidden();
-	} );
 } );

 test.describe( 'Shopper → Shipping (customer user)', () => {
@@ -414,9 +141,10 @@ test.describe( 'Shopper → Shipping (customer user)', () => {
 			name: 'Billing address',
 		} );

-		expect( shippingForm.getByLabel( 'Phone' ).inputValue ).toEqual(
-			billingForm.getByLabel( 'Phone' ).inputValue
-		);
+		const shippingPhone = shippingForm.getByLabel( 'Phone' );
+		const billingPhone = billingForm.getByLabel( 'Phone' );
+		await expect( shippingPhone ).toHaveValue( '0987654322' );
+		await expect( billingPhone ).toHaveValue( '0987654322' );

 		await checkoutPageObject.fillInCheckoutWithTestData();
 		const overrideBillingDetails = {
@@ -432,6 +160,12 @@ test.describe( 'Shopper → Shipping (customer user)', () => {
 			email: 'juan.perez@test.com',
 		};
 		await checkoutPageObject.fillBillingDetails( overrideBillingDetails );
+		await expect( billingPhone ).toHaveValue(
+			overrideBillingDetails.phone
+		);
+		await expect( shippingPhone ).not.toHaveValue(
+			overrideBillingDetails.phone
+		);
 		await checkoutPageObject.placeOrder();
 		await checkoutPageObject.verifyAddressDetails(
 			'billing',
@@ -441,32 +175,7 @@ test.describe( 'Shopper → Shipping (customer user)', () => {
 	} );
 } );

-test.describe( 'Shopper → Place Guest Order', () => {
-	test.use( { storageState: guestFile } );
-
-	test( 'Guest user can place order', async ( {
-		checkoutPageObject,
-		frontendUtils,
-		page,
-	} ) => {
-		await frontendUtils.goToShop();
-		await frontendUtils.addToCart( SIMPLE_PHYSICAL_PRODUCT_NAME );
-		await frontendUtils.goToCheckout();
-		expect(
-			await checkoutPageObject.selectAndVerifyShippingOption(
-				FREE_SHIPPING_NAME,
-				FREE_SHIPPING_PRICE
-			)
-		).toBe( true );
-		await checkoutPageObject.fillInCheckoutWithTestData();
-		await checkoutPageObject.placeOrder();
-		await expect(
-			page.getByText( 'Your order has been received.' )
-		).toBeVisible();
-	} );
-} );
-
-test.describe( 'Shopper → Place Virtual Order', () => {
+test.describe( 'Shopper → Store shipping disabled', () => {
 	test.beforeEach( async ( { requestUtils } ) => {
 		await requestUtils.rest( {
 			method: 'PUT',
@@ -475,44 +184,7 @@ test.describe( 'Shopper → Place Virtual Order', () => {
 		} );
 	} );

-	test( 'Does not see shipping options for digital orders when shipping is enabled', async ( {
-		checkoutPageObject,
-		frontendUtils,
-		localPickupUtils,
-		page,
-		requestUtils,
-	} ) => {
-		await requestUtils.rest( {
-			method: 'PUT',
-			path: 'wc/v3/settings/general/woocommerce_ship_to_countries',
-			data: { value: 'all' },
-		} );
-		await localPickupUtils.enableLocalPickup();
-
-		await frontendUtils.goToShop();
-		await frontendUtils.addToCart( SIMPLE_VIRTUAL_PRODUCT_NAME );
-		await frontendUtils.goToCart();
-
-		await expect(
-			page.getByText( 'Delivery', { exact: true } )
-		).toBeHidden();
-
-		await frontendUtils.goToCheckout();
-
-		await expect( page.getByText( 'Ship', { exact: true } ) ).toBeHidden();
-		await expect(
-			page.getByText( 'Pickup', { exact: true } )
-		).toBeHidden();
-
-		await checkoutPageObject.fillInCheckoutWithTestData();
-		await checkoutPageObject.placeOrder();
-
-		await expect(
-			page.getByText( 'Thank you. Your order has been received.' )
-		).toBeVisible();
-	} );
-
-	test( 'can place a digital order when shipping is disabled', async ( {
+	test( 'can place a physical order when store shipping is disabled', async ( {
 		checkoutPageObject,
 		frontendUtils,
 		localPickupUtils,
@@ -547,45 +219,6 @@ test.describe( 'Shopper → Place Virtual Order', () => {
 		await expect(
 			page.getByText( 'Thank you. Your order has been received.' )
 		).toBeVisible();
-
-		await localPickupUtils.enableLocalPickup();
-	} );
-
-	test( 'can place a digital order when shipping is disabled, but Local Pickup is still enabled', async ( {
-		checkoutPageObject,
-		frontendUtils,
-		localPickupUtils,
-		page,
-	} ) => {
-		await localPickupUtils.enableLocalPickup();
-
-		await frontendUtils.goToShop();
-		await frontendUtils.addToCart( SIMPLE_VIRTUAL_PRODUCT_NAME );
-		await frontendUtils.goToCart();
-
-		await expect(
-			page.getByText( 'Delivery', { exact: true } )
-		).toBeHidden();
-
-		await frontendUtils.goToCheckout();
-
-		// Delivery total in the sidebar.
-		await expect(
-			page.getByText( 'Delivery', { exact: true } )
-		).toBeHidden();
-
-		// Ship/Pickup method selector.
-		await expect( page.getByText( 'Ship', { exact: true } ) ).toBeHidden();
-		await expect(
-			page.getByText( 'Pickup', { exact: true } )
-		).toBeHidden();
-
-		await checkoutPageObject.fillInCheckoutWithTestData();
-		await checkoutPageObject.placeOrder();
-
-		await expect(
-			page.getByText( 'Thank you. Your order has been received.' )
-		).toBeVisible();
 	} );
 } );

@@ -624,38 +257,11 @@ test.describe( 'Shopper → Checkout Form Errors (guest user)', () => {
 		await expect(
 			page.getByText( 'Please enter a valid zip code' )
 		).toBeVisible();
+		await expect( page.getByLabel( 'Email address' ) ).toBeFocused();
 	} );
 } );

 test.describe( 'Billing Address Form', () => {
-	const blockSelectorInEditor = blockData.selectors.editor.block as string;
-
-	test( 'Enable company field', async ( { page, 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-shipping-address-block"]'
-		);
-
-		const companyCheckbox = page.getByLabel( 'Company', {
-			exact: true,
-		} );
-		await companyCheckbox.click();
-		await expect( companyCheckbox ).toBeChecked();
-
-		const companyInput = editor.canvas.getByLabel( 'Company (optional)' );
-		await expect( companyInput ).toBeVisible();
-
-		await editor.saveSiteEditorEntities();
-	} );
-
 	test.describe( 'Guest user', () => {
 		test.use( { storageState: guestFile } );

diff --git a/plugins/woocommerce/tests/php/src/Blocks/BlockTypes/Checkout.php b/plugins/woocommerce/tests/php/src/Blocks/BlockTypes/Checkout.php
index e2c1b7ce53e..dbd23594974 100644
--- a/plugins/woocommerce/tests/php/src/Blocks/BlockTypes/Checkout.php
+++ b/plugins/woocommerce/tests/php/src/Blocks/BlockTypes/Checkout.php
@@ -37,6 +37,13 @@ class Checkout extends \WP_UnitTestCase {
 	 */
 	private $mock_logger;

+	/**
+	 * Sequence for unique Checkout mock block names.
+	 *
+	 * @var int
+	 */
+	private $checkout_mock_sequence = 0;
+
 	/**
 	 * Set up the test. Creates a AssetDataRegistryMock.
 	 *
@@ -135,6 +142,128 @@ class Checkout extends \WP_UnitTestCase {
 		wp_delete_post( $page_id );
 	}

+	/**
+	 * @testdox Exposes whether store shipping and ordinary shipping methods are available.
+	 */
+	public function test_enqueue_data_exposes_shipping_topology(): void {
+		global $wpdb;
+
+		// Read rather than snapshot: the ambient methods have to be switched off for the
+		// topology assertions below, and the rollback switches them back on.
+		$ambient_method_states = $wpdb->get_results(
+			"SELECT instance_id FROM {$wpdb->prefix}woocommerce_shipping_zone_methods",
+			ARRAY_A
+		);
+		$shipping_zone         = new \WC_Shipping_Zone();
+
+		try {
+			foreach ( $ambient_method_states as $method_state ) {
+				$wpdb->update(
+					"{$wpdb->prefix}woocommerce_shipping_zone_methods",
+					array( 'is_enabled' => '0' ),
+					array( 'instance_id' => $method_state['instance_id'] )
+				);
+			}
+
+			update_option( 'woocommerce_ship_to_countries', 'all' );
+			update_option(
+				'woocommerce_pickup_location_settings',
+				array(
+					'enabled'    => 'yes',
+					'title'      => 'Pickup',
+					'cost'       => '',
+					'tax_status' => 'taxable',
+				)
+			);
+
+			$shipping_zone->set_zone_name( 'Checkout asset-data test' );
+			$shipping_zone->save();
+			$shipping_zone->add_shipping_method( 'flat_rate' );
+			$this->flush_shipping_method_cache();
+
+			$data = $this->get_checkout_asset_data();
+			$this->assertFalse(
+				\WP_Block_Type_Registry::get_instance()->is_registered( 'woocommerce/checkout-shipping-topology-1' ),
+				'The generated Checkout mock block should be unregistered after collecting asset data.'
+			);
+			$this->assertTrue( $data['shippingMethodsExist'], 'An enabled ordinary shipping method should be exposed.' );
+			$this->assertTrue( $data['shippingEnabled'], 'Shipping should be exposed as enabled when the store ships.' );
+
+			$shipping_zone->delete( true );
+			$this->flush_shipping_method_cache();
+
+			$data = $this->get_checkout_asset_data();
+			$this->assertFalse(
+				\WP_Block_Type_Registry::get_instance()->is_registered( 'woocommerce/checkout-shipping-topology-2' ),
+				'The generated Checkout mock block should be unregistered after collecting asset data.'
+			);
+			$this->assertFalse( $data['shippingMethodsExist'], 'Local pickup without an ordinary shipping method should not count as ordinary shipping.' );
+			$this->assertTrue( $data['shippingEnabled'], 'Store shipping remains enabled for the pickup-only topology.' );
+
+			update_option( 'woocommerce_ship_to_countries', 'disabled' );
+			$this->flush_shipping_method_cache();
+
+			$data = $this->get_checkout_asset_data();
+			$this->assertFalse(
+				\WP_Block_Type_Registry::get_instance()->is_registered( 'woocommerce/checkout-shipping-topology-3' ),
+				'The generated Checkout mock block should be unregistered after collecting asset data.'
+			);
+			$this->assertFalse( $data['shippingMethodsExist'], 'No ordinary shipping method should be exposed when none is configured.' );
+			$this->assertFalse( $data['shippingEnabled'], 'Globally disabled store shipping should be exposed.' );
+		} finally {
+			// The zone, the method rows and both options are inside the transaction.
+			// The memo on the WC_Shipping singleton is not, and this class extends
+			// WP_UnitTestCase, so nothing else reloads it.
+			//
+			// Drop the memo rather than reloading it. A reload here runs before
+			// tear_down() rolls anything back, so it rebuilds the memo from option
+			// values this test is about to revert. That happens to read back clean
+			// today, because pickup_location is not among the methods registered in
+			// the test environment, but it stays clean by accident rather than by
+			// design. Nulling the memo lets the next reader load from whatever the
+			// database says once the transaction is gone.
+			WC()->shipping()->unregister_shipping_methods();
+		}
+	}
+
+	/**
+	 * Get data registered by a fresh Checkout block instance.
+	 *
+	 * @return array<string, mixed>
+	 */
+	private function get_checkout_asset_data(): array {
+		$registry            = new AssetDataRegistryMock( $this->asset_api );
+		$block_type_registry = \WP_Block_Type_Registry::get_instance();
+		++$this->checkout_mock_sequence;
+		$block_name      = 'checkout-shipping-topology-' . $this->checkout_mock_sequence;
+		$full_block_name = 'woocommerce/' . $block_name;
+
+		try {
+			$checkout = new CheckoutMock(
+				$this->asset_api,
+				$registry,
+				$this->integration_registry,
+				$block_name
+			);
+			$checkout->mock_enqueue_data();
+
+			return $registry->get();
+		} finally {
+			if ( $block_type_registry->is_registered( $full_block_name ) ) {
+				$block_type_registry->unregister( $full_block_name );
+			}
+		}
+	}
+
+	/**
+	 * Flush cached shipping-method state after changing topology.
+	 */
+	private function flush_shipping_method_cache(): void {
+		\WC_Cache_Helper::get_transient_version( 'shipping', true );
+		delete_transient( 'wc_shipping_method_count' );
+		WC()->shipping()->load_shipping_methods();
+	}
+
 	/**
 	 * Overrides the WC logger.
 	 *