Commit 7f556612eb4 for woocommerce

commit 7f556612eb43753f96ba19bde0d70151f752f132
Author: Vlad Olaru <vlad.olaru@automattic.com>
Date:   Thu Sep 24 18:10:13 2026 +0300

    Revert "[tests] Reduce Cart and Checkout shopper E2E from 21 titles to 8" (#69046)

    * revert: Revert "[tests] Reduce Cart and Checkout shopper E2E from 21 titles to 8" (#68581)

    This reverts commit 5c973679cbf2daba90b323dd102114fa669cb0a9.

    Rubik asked for the E2E migration's test changes in its areas to be
    reverted until the team can review them. #68581 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 #68581

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

    * test(cart): Expect the current empty cart heading after removing a product

    The #68581 revert restores "User can remove a product from cart", which
    waits for the heading "Your cart is currently empty!". #68560 has since
    changed the Cart block's empty state heading to "Your cart is empty"
    and updated the retained titles, so the restored one times out.

    Match the heading #68560 introduced.

    Refs #68581
    Refs #68560

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

    ---------

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

diff --git a/plugins/woocommerce/changelog/testops-234-cart-checkout-shopper-journeys b/plugins/woocommerce/changelog/testops-234-cart-checkout-shopper-journeys
deleted file mode 100644
index cc1b0125a68..00000000000
--- a/plugins/woocommerce/changelog/testops-234-cart-checkout-shopper-journeys
+++ /dev/null
@@ -1,4 +0,0 @@
-Significance: patch
-Type: dev
-Comment: Consolidate the Cart block shopper E2E journeys and move the discount-label, single-use coupon, and shipping-topology checks to Jest and PHPUnit; replace the wall-clock nonce expiry with one deterministic invalid nonce.
-
diff --git a/plugins/woocommerce/client/blocks/assets/js/base/components/cart-checkout/cart-line-items-table/test/cart-line-item-row.tsx b/plugins/woocommerce/client/blocks/assets/js/base/components/cart-checkout/cart-line-items-table/test/cart-line-item-row.tsx
index 36dccf546d2..ae787afc243 100644
--- a/plugins/woocommerce/client/blocks/assets/js/base/components/cart-checkout/cart-line-items-table/test/cart-line-item-row.tsx
+++ b/plugins/woocommerce/client/blocks/assets/js/base/components/cart-checkout/cart-line-items-table/test/cart-line-item-row.tsx
@@ -60,14 +60,7 @@ const mockGetSettingWithCoercion = getSettingWithCoercion as jest.Mock;
  * preview module's transitive imports (which expect `wcBlocksConfig` to be
  * populated at module-load time).
  */
-type RawPriceOverrides = Partial< {
-	precision: number;
-	price: string;
-	regular_price: string;
-	sale_price: string;
-} >;
-
-const buildLineItem = ( rawPriceOverrides: RawPriceOverrides = {} ): CartItem =>
+const buildLineItem = (): CartItem =>
 	( {
 		key: 'test-key',
 		id: 1,
@@ -109,7 +102,6 @@ const buildLineItem = ( rawPriceOverrides: RawPriceOverrides = {} ): CartItem =>
 				price: '10000000',
 				regular_price: '10000000',
 				sale_price: '10000000',
-				...rawPriceOverrides,
 			},
 		},
 		totals: {
@@ -171,82 +163,17 @@ const setSettings = ( {
 	);
 };

-const renderRow = ( rawPriceOverrides?: RawPriceOverrides ) => {
+const renderRow = () => {
 	// Wrap in a table so the row's <td>s render in a valid context.
 	return render(
 		<table>
 			<tbody>
-				<CartLineItemRow
-					lineItem={ buildLineItem( rawPriceOverrides ) }
-				/>
+				<CartLineItemRow lineItem={ buildLineItem() } />
 			</tbody>
 		</table>
 	);
 };

-describe( 'renders cart row price', () => {
-	it.each( [
-		{
-			name: 'sale price with its regular price',
-			rawPrices: {
-				precision: 6,
-				price: '8000000',
-				regular_price: '10000000',
-			},
-			currentPrice: '$8.00',
-			regularPrice: '$10.00',
-		},
-		{
-			name: 'ordinary price without sale markup',
-			rawPrices: {
-				price: '10000000',
-				regular_price: '10000000',
-			},
-			currentPrice: '$10.00',
-			regularPrice: undefined,
-		},
-		{
-			name: 'extension-filtered price above its regular price without sale markup',
-			rawPrices: {
-				price: '50000000',
-				regular_price: '10000000',
-			},
-			currentPrice: '$50.00',
-			regularPrice: undefined,
-		},
-	] )( '$name', ( { rawPrices, currentPrice, regularPrice } ) => {
-		const { container } = renderRow( rawPrices );
-		const price = container.querySelector( '.wc-block-cart-item__prices' );
-		const currentPriceElement = price?.querySelector(
-			'.wc-block-components-product-price__value'
-		);
-		const regularPriceElement = price?.querySelector(
-			'del.wc-block-components-product-price__regular'
-		);
-		const discountedPriceElement =
-			price?.querySelector( 'ins.is-discounted' );
-
-		expect( price ).toBeInTheDocument();
-		expect(
-			price?.querySelectorAll(
-				'.wc-block-components-product-price__value'
-			)
-		).toHaveLength( 1 );
-		expect( currentPriceElement?.textContent ).toBe( currentPrice );
-
-		expect( Boolean( regularPriceElement ) ).toBe(
-			Boolean( regularPrice )
-		);
-		expect( Boolean( discountedPriceElement ) ).toBe(
-			Boolean( regularPrice )
-		);
-		expect( regularPriceElement?.textContent ).toBe( regularPrice );
-		expect( discountedPriceElement?.textContent ).toBe(
-			regularPrice ? currentPrice : undefined
-		);
-	} );
-} );
-
 describe( 'CartLineItemRow — Save for later visibility', () => {
 	beforeEach( () => {
 		jest.clearAllMocks();
diff --git a/plugins/woocommerce/client/blocks/changelog/testops-234-cart-checkout-shopper-journeys b/plugins/woocommerce/client/blocks/changelog/testops-234-cart-checkout-shopper-journeys
deleted file mode 100644
index cc1b0125a68..00000000000
--- a/plugins/woocommerce/client/blocks/changelog/testops-234-cart-checkout-shopper-journeys
+++ /dev/null
@@ -1,4 +0,0 @@
-Significance: patch
-Type: dev
-Comment: Consolidate the Cart block shopper E2E journeys and move the discount-label, single-use coupon, and shipping-topology checks to Jest and PHPUnit; replace the wall-clock nonce expiry with one deterministic invalid nonce.
-
diff --git a/plugins/woocommerce/tests/e2e/test-plugins/blocks/short-nonce-life.php b/plugins/woocommerce/tests/e2e/test-plugins/blocks/short-nonce-life.php
new file mode 100644
index 00000000000..0af4a340bcb
--- /dev/null
+++ b/plugins/woocommerce/tests/e2e/test-plugins/blocks/short-nonce-life.php
@@ -0,0 +1,21 @@
+<?php
+/**
+ * Plugin Name: WooCommerce Blocks Test Short Nonce Life
+ * Description: Sets a very short nonce lifetime for testing nonce expiry scenarios.
+ * Plugin URI: https://github.com/woocommerce/woocommerce
+ * Author: WooCommerce
+ *
+ * @package woocommerce-blocks-test-short-nonce-life
+ */
+
+declare( strict_types=1 );
+
+/**
+ * Set nonce lifetime to 2 seconds to simulate cache expiry scenarios.
+ */
+add_filter(
+	'nonce_life',
+	function () {
+		return 2;
+	}
+);
diff --git a/plugins/woocommerce/tests/e2e/tests/blocks/cart/cart-block.shopper.block_theme.spec.ts b/plugins/woocommerce/tests/e2e/tests/blocks/cart/cart-block.shopper.block_theme.spec.ts
index 66142eb6e9b..5cc858cf7df 100644
--- a/plugins/woocommerce/tests/e2e/tests/blocks/cart/cart-block.shopper.block_theme.spec.ts
+++ b/plugins/woocommerce/tests/e2e/tests/blocks/cart/cart-block.shopper.block_theme.spec.ts
@@ -8,6 +8,8 @@ import { test as base, expect } from '@woocommerce/e2e-utils';
  */
 import { CartPage } from './cart.page';
 import {
+	DISCOUNTED_PRODUCT_NAME,
+	REGULAR_PRICED_PRODUCT_NAME,
 	SIMPLE_PHYSICAL_PRODUCT_NAME,
 	SIMPLE_VIRTUAL_PRODUCT_NAME,
 } from '../checkout/constants';
@@ -22,76 +24,135 @@ const test = base.extend< { pageObject: CartPage } >( {
 } );

 test.describe( 'Shopper → Cart block', () => {
-	test( 'User can add, update, remove, and proceed from the cart', async ( {
-		frontendUtils,
-		page,
+	test( 'The discount label is only visible next to the discounted product', async ( {
 		pageObject,
+		frontendUtils,
 	} ) => {
+		await frontendUtils.goToShop();
+		await frontendUtils.addToCart( DISCOUNTED_PRODUCT_NAME );
+		await frontendUtils.addToCart( REGULAR_PRICED_PRODUCT_NAME );
 		await frontendUtils.goToCart();
+		// Check for discount on the discounted product
+		const discountedProductRow = await pageObject.findProductRow(
+			DISCOUNTED_PRODUCT_NAME
+		);
+		await expect( discountedProductRow ).toBeVisible();
+		const capRegularPriceElement = discountedProductRow.locator(
+			'.wc-block-components-product-price__regular'
+		);
+		const capDiscountedPriceElement = discountedProductRow.locator(
+			'.wc-block-components-product-price__value.is-discounted'
+		);
+		await expect( capRegularPriceElement ).toBeVisible();
+		await expect( capDiscountedPriceElement ).toBeVisible();

-		await expect(
-			page.getByRole( 'heading', {
-				name: 'Your cart is empty',
-			} )
-		).toBeVisible();
+		// Check for absence of discount on the regular priced product
+		const regularPricedProductRow = await pageObject.findProductRow(
+			REGULAR_PRICED_PRODUCT_NAME
+		);
+		await expect( regularPricedProductRow ).toBeVisible();
+		const hoodieRegularPriceElement = regularPricedProductRow.locator(
+			'.wc-block-components-product-price__regular'
+		);
+		const hoodieDiscountedPriceElement = regularPricedProductRow.locator(
+			'.wc-block-components-product-price__value.is-discounted'
+		);
+		await expect( hoodieRegularPriceElement ).toBeHidden();
+		await expect( hoodieDiscountedPriceElement ).toBeHidden();
+	} );
+
+	test( 'Products with updated prices should not display a discount label', async ( {
+		pageObject,
+		requestUtils,
+		frontendUtils,
+	} ) => {
+		await requestUtils.activatePlugin(
+			'woocommerce-blocks-test-update-price'
+		);

 		await frontendUtils.goToShop();
-		await frontendUtils.addToCart( SIMPLE_PHYSICAL_PRODUCT_NAME );
-		await frontendUtils.goToShop();
-		await frontendUtils.addToCart( SIMPLE_VIRTUAL_PRODUCT_NAME );
+		await frontendUtils.addToCart( DISCOUNTED_PRODUCT_NAME );
+		await frontendUtils.addToCart( REGULAR_PRICED_PRODUCT_NAME );
 		await frontendUtils.goToCart();

-		const physicalRow = await pageObject.findProductRow(
-			SIMPLE_PHYSICAL_PRODUCT_NAME
+		// Ensure no discount label is present on the products in the cart
+		const capRow = await pageObject.findProductRow(
+			DISCOUNTED_PRODUCT_NAME
+		);
+		await expect( capRow ).toBeVisible();
+		const capRegularPriceElement = capRow.locator(
+			'.wc-block-components-product-price__regular'
 		);
-		const virtualRow = await pageObject.findProductRow(
-			SIMPLE_VIRTUAL_PRODUCT_NAME
+		const capDiscountedPriceElement = capRow.locator(
+			'.wc-block-components-product-price__value.is-discounted'
 		);
-		await expect( physicalRow ).toHaveCount( 1 );
-		await expect( physicalRow ).toBeVisible();
-		await expect( virtualRow ).toHaveCount( 1 );
-		await expect( virtualRow ).toBeVisible();
+		await expect( capRegularPriceElement ).toBeHidden();
+		await expect( capDiscountedPriceElement ).toBeHidden();
+
+		// Locate the price element within the Cap product row
+		const capPriceElement = capRow
+			.locator( '.wc-block-components-product-price__value' )
+			.first();
+		await expect( capPriceElement ).toBeVisible();
+
+		// Get the text content of the price element and check the price
+		const capPriceText = await capPriceElement.textContent();
+		expect( capPriceText ).toBe( '$50.00' );

-		const quantityInput = page.getByLabel(
-			`Quantity of ${ SIMPLE_VIRTUAL_PRODUCT_NAME } in your cart.`
+		const hoodieRow = await pageObject.findProductRow(
+			REGULAR_PRICED_PRODUCT_NAME
 		);
-		const proceedToCheckout = page.getByRole( 'link', {
-			name: 'Proceed to Checkout',
-		} );
+		await expect( hoodieRow ).toBeVisible();
+		const hoodieRegularPriceElement = hoodieRow.locator(
+			'.wc-block-components-product-price__regular'
+		);
+		const hoodieDiscountedPriceElement = hoodieRow.locator(
+			'.wc-block-components-product-price__value.is-discounted'
+		);
+		await expect( hoodieRegularPriceElement ).toBeHidden();
+		await expect( hoodieDiscountedPriceElement ).toBeHidden();

-		await quantityInput.fill( '4' );
+		// Locate the price element within the Hoodie with Logo product row
+		const hoodiePriceElement = hoodieRow
+			.locator( '.wc-block-components-product-price__value' )
+			.first();
+		await expect( hoodiePriceElement ).toBeVisible();

-		await expect( proceedToCheckout ).toBeDisabled();
-		await expect( proceedToCheckout ).toBeEnabled();
-		await expect( quantityInput ).toHaveValue( '4' );
+		// Get the text content of the price element and check the price
+		const hoodiePriceText = await hoodiePriceElement.textContent();
+		expect( hoodiePriceText ).toBe( '$50.00' );
+	} );

-		await page
-			.getByLabel(
-				`Increase quantity of ${ SIMPLE_VIRTUAL_PRODUCT_NAME }`
-			)
-			.click();
-		await expect( proceedToCheckout ).toBeDisabled();
-		await expect( proceedToCheckout ).toBeEnabled();
-		await expect( quantityInput ).toHaveValue( '5' );
+	test( 'User can view empty cart message', async ( {
+		frontendUtils,
+		page,
+	} ) => {
+		await frontendUtils.goToCart();

-		await page
-			.getByLabel( `Reduce quantity of ${ SIMPLE_VIRTUAL_PRODUCT_NAME }` )
-			.click();
-		await expect( proceedToCheckout ).toBeDisabled();
-		await expect( proceedToCheckout ).toBeEnabled();
-		await expect( quantityInput ).toHaveValue( '4' );
+		// Verify cart is empty
+		await expect(
+			page.getByRole( 'heading', {
+				name: 'Your cart is empty',
+			} )
+		).toBeVisible();
+	} );

-		await physicalRow
+	test( 'User can remove a product from cart', async ( {
+		frontendUtils,
+		page,
+	} ) => {
+		await frontendUtils.goToShop();
+		await frontendUtils.addToCart( SIMPLE_PHYSICAL_PRODUCT_NAME );
+		await frontendUtils.goToCart();
+		await page
 			.getByLabel( `Remove ${ SIMPLE_PHYSICAL_PRODUCT_NAME } from cart` )
 			.click();
-		await expect( physicalRow ).toBeHidden();
-		await expect( virtualRow ).toBeVisible();
-		await expect( quantityInput ).toHaveValue( '4' );
-
-		await proceedToCheckout.click();

+		// Verify product is removed from the cart'
 		await expect(
-			page.getByRole( 'button', { name: 'Place Order' } )
+			page.getByRole( 'heading', {
+				name: 'Your cart is empty',
+			} )
 		).toBeVisible();
 	} );

@@ -169,6 +230,20 @@ test.describe( 'Shopper → Cart block', () => {
 		).toHaveValue( '4' );
 	} );

+	test( 'User can proceed to checkout', async ( { frontendUtils, page } ) => {
+		await frontendUtils.goToShop();
+		await frontendUtils.addToCart( SIMPLE_VIRTUAL_PRODUCT_NAME );
+		await frontendUtils.goToCart();
+
+		// Click on "Proceed to Checkout" button
+		await page.getByRole( 'link', { name: 'Proceed to Checkout' } ).click();
+
+		// Verify that the "Place Order" button is visible, then we're on the checkout page
+		await expect(
+			page.getByRole( 'button', { name: 'Place Order' } )
+		).toBeVisible();
+	} );
+
 	test( 'User can see Cross-Sells products block', async ( {
 		frontendUtils,
 		page,
diff --git a/plugins/woocommerce/tests/e2e/tests/blocks/cart/cart-checkout-block-coupons.shopper.block_theme.spec.ts b/plugins/woocommerce/tests/e2e/tests/blocks/cart/cart-checkout-block-coupons.shopper.block_theme.spec.ts
index f8120490fe8..641ef4cb9c2 100644
--- a/plugins/woocommerce/tests/e2e/tests/blocks/cart/cart-checkout-block-coupons.shopper.block_theme.spec.ts
+++ b/plugins/woocommerce/tests/e2e/tests/blocks/cart/cart-checkout-block-coupons.shopper.block_theme.spec.ts
@@ -34,10 +34,6 @@ test.describe( 'Shopper → Coupon', () => {
 		await frontendUtils.addToCart( REGULAR_PRICED_PRODUCT_NAME );
 		await frontendUtils.goToCart();

-		// Removing an applied coupon is exercised nowhere else in the E2E suite, on
-		// either block. Applying on the Cart block is covered by
-		// tests/coupons/cart-block-coupons.spec.ts, so these two clicks are here for
-		// the removal that follows them.
 		await page.getByRole( 'button', { name: 'Add coupons' } ).click();
 		await page.getByLabel( 'Enter code' ).fill( 'single-use-coupon' );
 		await page.getByRole( 'button', { name: 'Apply' } ).click();
@@ -76,4 +72,40 @@ test.describe( 'Shopper → Coupon', () => {
 			page.getByRole( 'cell', { name: '–$2.00' } )
 		).toBeVisible();
 	} );
+
+	test( 'Logged in user cannot apply single-use coupon twice', async ( {
+		checkoutPageObject,
+		frontendUtils,
+		page,
+	} ) => {
+		await frontendUtils.goToShop();
+		await frontendUtils.addToCart( REGULAR_PRICED_PRODUCT_NAME );
+		await frontendUtils.goToCheckout();
+
+		await page.getByRole( 'button', { name: 'Add coupons' } ).click();
+		await page.getByLabel( 'Enter code' ).fill( 'single-use-coupon' );
+		await page.getByRole( 'button', { name: 'Apply' } ).click();
+
+		await expect(
+			page.getByLabel( 'Remove coupon "single-use-coupon"' )
+		).toBeVisible();
+
+		await checkoutPageObject.fillInCheckoutWithTestData();
+		await checkoutPageObject.placeOrder();
+
+		await frontendUtils.emptyCart();
+		await frontendUtils.goToShop();
+		await frontendUtils.addToCart( REGULAR_PRICED_PRODUCT_NAME );
+		await frontendUtils.goToCheckout();
+
+		await page.getByRole( 'button', { name: 'Add coupons' } ).click();
+		await page.getByLabel( 'Enter code' ).fill( 'single-use-coupon' );
+		await page.getByRole( 'button', { name: 'Apply' } ).click();
+
+		await expect(
+			page.getByText(
+				'Usage limit for coupon "SINGLE-USE-COUPON" has been reached.'
+			)
+		).toBeVisible();
+	} );
 } );
diff --git a/plugins/woocommerce/tests/e2e/tests/blocks/cart/cart-checkout-block-shipping.block_theme.spec.ts b/plugins/woocommerce/tests/e2e/tests/blocks/cart/cart-checkout-block-shipping.block_theme.spec.ts
index ad615e14424..8fb7c442948 100644
--- a/plugins/woocommerce/tests/e2e/tests/blocks/cart/cart-checkout-block-shipping.block_theme.spec.ts
+++ b/plugins/woocommerce/tests/e2e/tests/blocks/cart/cart-checkout-block-shipping.block_theme.spec.ts
@@ -1,7 +1,8 @@
 /**
  * External dependencies
  */
-import { expect, test as base, wpCLI } from '@woocommerce/e2e-utils';
+import { expect, test as base, FrontendUtils } from '@woocommerce/e2e-utils';
+import { Dialog } from '@playwright/test';

 /**
  * Internal dependencies
@@ -9,186 +10,244 @@ import { expect, test as base, wpCLI } from '@woocommerce/e2e-utils';
 import { CheckoutPage } from '../checkout/checkout.page';
 import { REGULAR_PRICED_PRODUCT_NAME } from '../checkout/constants';

-type ShippingTopology = {
-	defaultRate?: boolean;
-	gbRate?: boolean;
-	pickup?: boolean;
-	requiresAddress: boolean;
-};
-
 const test = base.extend< { checkoutPageObject: CheckoutPage } >( {
-	checkoutPageObject: async ( { page, requestUtils }, use ) => {
-		const pageObject = new CheckoutPage( { page, requestUtils } );
+	checkoutPageObject: async ( { page }, use ) => {
+		const pageObject = new CheckoutPage( {
+			page,
+		} );
 		await use( pageObject );
 	},
 } );

-const configureShippingTopology = async ( topology: ShippingTopology ) => {
-	const encodedTopology = Buffer.from(
-		JSON.stringify( {
-			defaultRate: false,
-			gbRate: false,
-			pickup: false,
-			...topology,
-		} )
-	).toString( 'base64' );
-
-	await wpCLI( `eval '
-		$config = json_decode( base64_decode( "${ encodedTopology }" ), true );
-
-		foreach ( WC_Shipping_Zones::get_zones() as $zone_data ) {
-			$zone = new WC_Shipping_Zone( $zone_data["zone_id"] );
-			$zone->delete( true );
-		}
+test.describe( 'Merchant → Shipping', () => {
+	test( 'Merchant can hide shipping costs before address is entered', async ( {
+		page,
+		shippingUtils,
+		localPickupUtils,
+	} ) => {
+		await localPickupUtils.disableLocalPickup();
+		await shippingUtils.enableShippingCostsRequireAddress();

-		$default_zone = WC_Shipping_Zones::get_zone( 0 );
-		foreach ( $default_zone->get_shipping_methods() as $method ) {
-			$default_zone->delete_shipping_method( $method->instance_id );
-		}
+		await expect(
+			page.getByLabel( 'Hide shipping costs until an address is entered' )
+		).toBeChecked();
+	} );
+} );

-		update_option( "woocommerce_flat_rate_settings", array( "enabled" => "no" ) );
-		update_option( "woocommerce_free_shipping_settings", array( "enabled" => "no" ) );
-		update_option( "woocommerce_local_pickup_settings", array( "enabled" => "no" ) );
-		update_option( "woocommerce_default_customer_address", "" );
-		update_option( "woocommerce_shipping_cost_requires_address", $config["requiresAddress"] ? "yes" : "no" );
-
-		if ( $config["defaultRate"] ) {
-			$instance_id = $default_zone->add_shipping_method( "flat_rate" );
-			update_option(
-				"woocommerce_flat_rate_{$instance_id}_settings",
-				array( "enabled" => "yes", "title" => "Home delivery", "tax_status" => "none", "cost" => "10" )
-			);
-		}
+test.describe( 'Shopper → Shipping', () => {
+	test.beforeEach( async ( { shippingUtils } ) => {
+		await shippingUtils.enableShippingCostsRequireAddress();
+	} );

-		if ( $config["gbRate"] ) {
-			$gb_zone = new WC_Shipping_Zone();
-			$gb_zone->set_zone_name( "United Kingdom" );
-			$gb_zone->set_zone_locations( array( (object) array( "code" => "GB", "type" => "country" ) ) );
-			$gb_zone->save();
-			$instance_id = $gb_zone->add_shipping_method( "flat_rate" );
-			update_option(
-				"woocommerce_flat_rate_{$instance_id}_settings",
-				array( "enabled" => "yes", "title" => "UK delivery", "tax_status" => "none", "cost" => "15" )
-			);
-		}
+	test.beforeEach( async ( { admin } ) => {
+		await admin.visitAdminPage( 'admin.php?page=wc-settings&tab=general' );
+		await admin.page
+			.getByLabel( 'Default customer location' )
+			.selectOption( 'No location by default' );
+		await admin.saveAdminPage();

-		update_option(
-			"woocommerce_pickup_location_settings",
-			array( "enabled" => $config["pickup"] ? "yes" : "no", "title" => "Pickup", "tax_status" => "none", "cost" => "" )
-		);
-		update_option(
-			"pickup_location_pickup_locations",
-			$config["pickup"]
-				? array(
-					array(
-						"name" => "Automattic, Inc.",
-						"address" => array(
-							"address_1" => "60 29th Street, Suite 343",
-							"city" => "San Francisco",
-							"postcode" => "94110",
-							"state" => "CA",
-							"country" => "US"
-						),
-						"details" => "American entity",
-						"enabled" => true
-					)
-				)
-				: array()
+		await admin.visitAdminPage(
+			'admin.php?page=wc-settings&tab=shipping&zone_id=new'
 		);
+		await admin.page.getByLabel( 'Zone name' ).fill( 'UK' );
+		await admin.page
+			.getByRole( 'combobox', { name: 'Start typing to filter zones' } )
+			.fill( 'United Kingdom' );
+		await admin.page
+			.getByRole( 'checkbox', { name: 'United Kingdom (UK)' } )
+			.click(); // .check() won't work here as the input disappears immediately after checking.
+		await admin.saveAdminPage();
+		await admin.page
+			.getByRole( 'button', { name: 'Add shipping method' } )
+			.click();
+		await admin.page.getByText( 'Flat rate' ).click();
+		await admin.page.getByRole( 'button', { name: 'Continue' } ).click();
+		await admin.page
+			.getByRole( 'button', { name: 'Save zone and method' } )
+			.click();
+		await expect( admin.page.getByText( 'Flat rate' ) ).toBeVisible();
+		if (
+			! ( await admin.page
+				.getByRole( 'button', { name: 'Save changes' } )
+				.isDisabled() )
+		) {
+			await admin.saveAdminPage();
+		}
+		await expect(
+			admin.page.getByRole( 'button', { name: 'Save changes' } )
+		).toBeDisabled();
+	} );

-		WC_Cache_Helper::get_transient_version( "shipping", true );
-		delete_transient( "wc_shipping_method_count" );
-		WC()->shipping()->reset_shipping();
-	'` );
-};
+	// Series of tests below to cover the following scenarios: see PR https://github.com/woocommerce/woocommerce/pull/56460 for more details

-test.describe( 'Merchant → Shipping', () => {
-	test( 'Merchant can hide shipping costs before address is entered', async ( {
-		page,
+	/**
+	 * Rates enabled for default customer location
+	 * Rates enabled for _any_ location
+	 * Local pickup enabled
+	 * Hide rates until an address is entered (only applicable when Local pickup is DISABLED)
+	 *
+	 * 1.  Y Y Y #
+	 * 2.  Y Y N N
+	 * 3.  Y N Y # - Skipping because this behaves the same as test 1.
+	 * 4.  Y N N N
+	 * 5.  N Y Y #
+	 * 6.  N Y N N
+	 * 7.  N N Y # - known bug here with the text/UI to enter an address, despite there being no methods.
+	 * 8.  N N N N
+	 * 9.  Y Y N Y
+	 * 10. Y N N Y
+	 * 11. N Y N Y
+	 * 12. N N N Y
+	 */
+
+	test( '1. With shipping methods for the default location, shipping methods for _any_ location, and local pickup enabled, the shopper sees shipping rates and pickup options - rates are selected default', async ( {
+		localPickupUtils,
+		frontendUtils,
 		shippingUtils,
 	} ) => {
-		await configureShippingTopology( { requiresAddress: false } );
-		await shippingUtils.openShippingSettings();
-
-		const hideShippingCosts = page.getByLabel(
-			'Hide shipping costs until an address is entered'
-		);
-		await expect( hideShippingCosts ).not.toBeChecked();
-		await hideShippingCosts.check();
-		await shippingUtils.saveShippingSettings();
-		await page.reload();
+		await localPickupUtils.enableLocalPickup();
+		await shippingUtils.disableShippingCostsRequireAddress();
+		await localPickupUtils.addPickupLocation( {
+			location: {
+				name: 'Automattic, Inc.',
+				address: '60 29th Street, Suite 343',
+				city: 'San Francisco',
+				postcode: '94110',
+				state: 'US:CA',
+				details: 'American entity',
+			},
+		} );

-		await expect( hideShippingCosts ).toBeChecked();
+		await frontendUtils.goToShop();
+		await frontendUtils.addToCart( REGULAR_PRICED_PRODUCT_NAME );
+		await frontendUtils.goToCheckout();
+		await expect(
+			frontendUtils.page.getByRole( 'radio', {
+				name: 'Ship',
+				exact: true,
+			} )
+		).toBeChecked();
+		await expect(
+			frontendUtils.page.getByRole( 'radio', {
+				name: 'Flat rate shipping $',
+			} )
+		).toBeChecked();
+		await expect(
+			frontendUtils.page.getByRole( 'radio', {
+				name: 'Flat rate shipping $',
+			} )
+		).toBeChecked();
 	} );
-} );

-test.describe( 'Shopper → Shipping', () => {
-	test( 'Shopper can switch between shipping and local pickup while preserving the effective selected rate', async ( {
+	test( '2. With shipping methods for the default location, shipping methods for _any_ location, local pickup disabled, and shipping costs requires address disabled, the shopper sees shipping rates only', async ( {
+		localPickupUtils,
 		frontendUtils,
-		page,
+		shippingUtils,
 	} ) => {
-		await configureShippingTopology( {
-			defaultRate: true,
-			pickup: true,
-			requiresAddress: false,
-		} );
+		await localPickupUtils.disableLocalPickup();
+		await shippingUtils.disableShippingCostsRequireAddress();

 		await frontendUtils.goToShop();
 		await frontendUtils.addToCart( REGULAR_PRICED_PRODUCT_NAME );
 		await frontendUtils.goToCheckout();
+		await expect(
+			frontendUtils.page.getByRole( 'radio', {
+				name: 'Ship',
+				exact: true,
+			} )
+		).toBeHidden();
+		await expect(
+			frontendUtils.page.getByRole( 'radio', {
+				name: 'Flat rate shipping $',
+			} )
+		).toBeChecked();
+		await expect(
+			frontendUtils.page.getByRole( 'radio', {
+				name: 'Flat rate shipping $',
+			} )
+		).toBeChecked();
+	} );

-		const ship = page.getByRole( 'radio', { name: 'Ship', exact: true } );
-		const pickup = page.getByRole( 'radio', {
-			name: 'Pickup',
-			exact: true,
-		} );
-		const deliveryRate = page.getByRole( 'radio', {
-			name: /Home delivery/,
-		} );
-		const pickupRate = page.getByRole( 'radio', {
-			name: /Automattic, Inc\./,
-		} );
+	// 3. With shipping methods for the default location, no shipping methods for _any_ other location, and local pickup enabled, the shopper sees shipping rates and pickup options - skipped as same result as 1.

-		await expect( ship ).toBeChecked();
-		await expect( pickup ).not.toBeChecked();
-		await expect( deliveryRate ).toBeChecked();
+	test( '4. With shipping methods for the default location, no shipping methods for _any_ other location, local pickup disabled, and shipping costs require address disabled, the shopper sees shipping rates only after entering an address', async ( {
+		localPickupUtils,
+		admin,
+		frontendUtils,
+		checkoutPageObject,
+		shippingUtils,
+	} ) => {
+		await localPickupUtils.disableLocalPickup();
+		await shippingUtils.disableShippingCostsRequireAddress();

-		await pickup.click();
-		await expect( pickup ).toBeChecked();
-		await expect( ship ).not.toBeChecked();
-		await expect( pickupRate ).toBeChecked();
-		await expect( deliveryRate ).toBeHidden();
+		await admin.visitAdminPage( 'admin.php?page=wc-settings&tab=shipping' );
+		// Accept the delete dialog, then remove the listener;
+		const acceptDialog = ( dialog: Dialog ) => dialog.accept();
+		admin.page.on( 'dialog', acceptDialog );
+		await admin.page.getByRole( 'link', { name: 'Delete' } ).click();
+		admin.page.off( 'dialog', acceptDialog );

-		await ship.click();
-		await expect( ship ).toBeChecked();
-		await expect( pickup ).not.toBeChecked();
-		await expect( deliveryRate ).toBeChecked();
+		await frontendUtils.goToShop();
+		await frontendUtils.addToCart( REGULAR_PRICED_PRODUCT_NAME );
+		await frontendUtils.goToCheckout();
+
+		await expect(
+			frontendUtils.page.getByText(
+				'Enter a shipping address to view shipping options'
+			)
+		).toBeHidden();
+
+		await expect(
+			checkoutPageObject.page.getByRole( 'radio', {
+				name: 'Flat rate shipping $',
+			} )
+		).toBeChecked();
 	} );

-	test( 'Shopper sees no matching rates until a complete address reveals the zone rate', async ( {
-		checkoutPageObject,
+	// 5. With no shipping methods for the default location, but shipping methods for _any_ other location, local pickup enabled, the shopper sees pickup rates until entering an address for the zone with rates
+	// Not testing because this is a "bug" we are going to fix - see https://github.com/woocommerce/woocommerce/issues/56462
+
+	test( '6. With no shipping methods for the default location, but shipping methods for _any_ other location, local pickup disabled, and shipping costs require address disabled, the shopper sees shipping rates only after entering an address', async ( {
+		localPickupUtils,
+		admin,
 		frontendUtils,
-		page,
+		checkoutPageObject,
+		shippingUtils,
 	} ) => {
-		await configureShippingTopology( {
-			gbRate: true,
-			requiresAddress: true,
-		} );
+		await localPickupUtils.disableLocalPickup();
+		await shippingUtils.disableShippingCostsRequireAddress();
+		await admin.visitAdminPage( 'admin.php?page=wc-settings&tab=general' );
+		await admin.page
+			.getByLabel( 'Default customer location' )
+			.selectOption( 'No location by default' );
+		await admin.saveAdminPage();
+
+		await admin.visitAdminPage( 'admin.php?page=wc-settings&tab=shipping' );
+
+		await admin.page
+			.getByRole( 'row', { name: 'Rest of the world' } )
+			.getByRole( 'link' )
+			.click();
+
+		// There are two shipping rates enabled. Clicking the first one turns it off.
+		// Then only one "name: yes" remains, making it the first, even though it's the second rate.
+		await admin.page.getByRole( 'link', { name: 'Yes' } ).first().click();
+		await admin.page.getByRole( 'link', { name: 'Yes' } ).first().click();
+		await admin.saveAdminPage();

 		await frontendUtils.goToShop();
 		await frontendUtils.addToCart( REGULAR_PRICED_PRODUCT_NAME );
 		await frontendUtils.goToCheckout();

 		await expect(
-			page.getByText(
-				/Enter a shipping address to view shipping options/
+			frontendUtils.page.getByText(
+				'Enter a shipping address to view shipping options'
 			)
 		).toBeVisible();
-
 		await checkoutPageObject.fillInCheckoutWithTestData();
-		await checkoutPageObject.waitForCheckoutToFinishUpdating();
+
 		await expect(
-			page
+			checkoutPageObject.page
 				.getByLabel( 'Checkout' )
 				.getByText(
 					'No shipping options are available for this address. Please verify the address is correct or try a different address.'
@@ -196,26 +255,275 @@ test.describe( 'Shopper → Shipping', () => {
 		).toBeVisible();

 		await checkoutPageObject.fillInCheckoutWithTestData( {
-			country: 'United Kingdom (UK)',
-			countryKey: 'GB',
-			city: 'London',
-			state: '',
-			postcode: 'EC4M 9AF',
+			country: 'GB',
+			postcode: 'SW19 5AE',
 		} );

-		const shippingAddress = page.getByRole( 'group', {
-			name: 'Shipping address',
+		await expect(
+			checkoutPageObject.page.getByRole( 'radio', {
+				name: 'Flat rate Free',
+			} )
+		).toBeChecked();
+	} );
+
+	test( '7. With no shipping methods for the default location, no shipping methods for _any_ other location, local pickup enabled the shopper sees local pickup rates only', async ( {
+		localPickupUtils,
+		admin,
+		frontendUtils,
+		shippingUtils,
+	} ) => {
+		await admin.visitAdminPage( 'admin.php?page=wc-settings&tab=shipping' );
+		// Accept the delete dialog, then remove the listener;
+		const acceptDialog = ( dialog: Dialog ) => dialog.accept();
+		admin.page.on( 'dialog', acceptDialog );
+		await admin.page.getByRole( 'link', { name: 'Delete' } ).click();
+		admin.page.off( 'dialog', acceptDialog );
+
+		await localPickupUtils.enableLocalPickup();
+		await shippingUtils.disableShippingCostsRequireAddress();
+		await localPickupUtils.addPickupLocation( {
+			location: {
+				name: 'Automattic, Inc.',
+				address: '60 29th Street, Suite 343',
+				city: 'San Francisco',
+				postcode: '94110',
+				state: 'US:CA',
+				details: 'American entity',
+			},
 		} );
+
+		await admin.visitAdminPage( 'admin.php?page=wc-settings&tab=shipping' );
+
+		await admin.page
+			.getByRole( 'row', { name: 'Rest of the world' } )
+			.getByRole( 'link' )
+			.click();
+
+		// There are two shipping rates enabled. Clicking the first one turns it off.
+		// Then only one "name: yes" remains, making it the first, even though it's the second rate.
+		await admin.page.getByRole( 'link', { name: 'Yes' } ).first().click();
+		await admin.page.getByRole( 'link', { name: 'Yes' } ).first().click();
+		await admin.saveAdminPage();
+
+		await frontendUtils.goToShop();
+		await frontendUtils.addToCart( REGULAR_PRICED_PRODUCT_NAME );
+		await frontendUtils.goToCheckout();
+
 		await expect(
-			shippingAddress.getByLabel( 'Country/Region' )
-		).toHaveValue( 'GB' );
+			frontendUtils.page.getByRole( 'radio', {
+				name: 'Automattic, Inc. free 60 29th',
+			} )
+		).toBeChecked();
+
 		await expect(
-			shippingAddress.locator( '#shipping-postcode' )
-		).toHaveValue( 'EC4M 9AF' );
-		await checkoutPageObject.waitForCheckoutToFinishUpdating();
+			frontendUtils.page.getByRole( 'radio', {
+				name: 'Ship',
+				exact: true,
+			} )
+		).toBeHidden();
+	} );
+
+	// Skipping test due to a known bug with needs_shipping - see issue https://github.com/woocommerce/woocommerce/issues/56507
+	test.skip( '8. With no shipping methods for the default location, no shipping methods for _any_ other location, local pickup disabled the shopper sees no shipping and no pickup rates', async ( {
+		localPickupUtils,
+		admin,
+		frontendUtils,
+		shippingUtils,
+	} ) => {
+		await admin.visitAdminPage( 'admin.php?page=wc-settings&tab=shipping' );
+		// Accept the delete dialog, then remove the listener;
+		const acceptDialog = ( dialog: Dialog ) => dialog.accept();
+		admin.page.on( 'dialog', acceptDialog );
+		await admin.page.getByRole( 'link', { name: 'Delete' } ).click();
+		admin.page.off( 'dialog', acceptDialog );
+
+		await localPickupUtils.disableLocalPickup();
+		await shippingUtils.disableShippingCostsRequireAddress();
+
+		await admin.visitAdminPage( 'admin.php?page=wc-settings&tab=shipping' );
+
+		await admin.page
+			.getByRole( 'row', { name: 'Rest of the world' } )
+			.getByRole( 'link' )
+			.click();
+
+		// There are two shipping rates enabled. Clicking the first one turns it off.
+		// Then only one "name: yes" remains, making it the first, even though it's the second rate.
+		await admin.page.getByRole( 'link', { name: 'Yes' } ).first().click();
+		await admin.page.getByRole( 'link', { name: 'Yes' } ).first().click();
+		await admin.saveAdminPage();
+
+		await frontendUtils.goToShop();
+		await frontendUtils.addToCart( REGULAR_PRICED_PRODUCT_NAME );
+		await frontendUtils.goToCheckout();

 		await expect(
-			page.getByRole( 'radio', { name: /UK delivery/ } )
-		).toBeChecked();
+			frontendUtils.page.getByRole( 'radio', {
+				name: 'Ship',
+				exact: true,
+			} )
+		).toBeHidden();
+
+		await expect(
+			frontendUtils.page.getByRole( 'heading', {
+				name: 'Shipping options',
+			} )
+		).toBeHidden();
+	} );
+
+	test( '9. With shipping methods for the default location, shipping methods for _any_ other location, local pickup disabled and shipping requires address enabled, shopper sees shipping rates immediately.', async ( {
+		localPickupUtils,
+		frontendUtils,
+		shippingUtils,
+		checkoutPageObject,
+	} ) => {
+		await localPickupUtils.disableLocalPickup();
+		await shippingUtils.enableShippingCostsRequireAddress();
+
+		await frontendUtils.goToShop();
+		await frontendUtils.addToCart( REGULAR_PRICED_PRODUCT_NAME );
+		await frontendUtils.goToCheckout();
+
+		await expect(
+			frontendUtils.page.getByText(
+				'Enter a shipping address to view shipping options.'
+			)
+		).toBeVisible();
+
+		await expect(
+			frontendUtils.page.getByRole( 'radio', {
+				name: 'Ship',
+				exact: true,
+			} )
+		).toBeHidden();
+
+		await expect(
+			frontendUtils.page.getByRole( 'heading', {
+				name: 'Shipping options',
+			} )
+		).toBeVisible();
+
+		await checkoutPageObject.fillInCheckoutWithTestData();
+
+		await expect(
+			checkoutPageObject.page.getByRole( 'radio', {
+				name: 'Flat rate shipping $',
+			} )
+		).toBeVisible();
+	} );
+
+	test( '10. With shipping methods for the default location, no shipping methods for _any_ other location, local pickup disabled, and shipping costs require address enabled, the shopper sees shipping rates only after entering an address', async ( {
+		localPickupUtils,
+		admin,
+		frontendUtils,
+		checkoutPageObject,
+		shippingUtils,
+	} ) => {
+		await localPickupUtils.disableLocalPickup();
+		await shippingUtils.enableShippingCostsRequireAddress();
+
+		await admin.visitAdminPage( 'admin.php?page=wc-settings&tab=shipping' );
+		// Accept the delete dialog, then remove the listener;
+		const acceptDialog = ( dialog: Dialog ) => dialog.accept();
+		admin.page.on( 'dialog', acceptDialog );
+		await admin.page.getByRole( 'link', { name: 'Delete' } ).click();
+		admin.page.off( 'dialog', acceptDialog );
+
+		await frontendUtils.goToShop();
+		await frontendUtils.addToCart( REGULAR_PRICED_PRODUCT_NAME );
+		await frontendUtils.goToCheckout();
+
+		await expect(
+			frontendUtils.page.getByText(
+				'Enter a shipping address to view shipping options'
+			)
+		).toBeVisible();
+		await checkoutPageObject.fillInCheckoutWithTestData();
+
+		await expect(
+			checkoutPageObject.page.getByRole( 'radio', {
+				name: 'Flat rate shipping $',
+			} )
+		).toBeVisible();
+	} );
+
+	// 11. With no shipping methods for the default location, but shipping methods for _any_ other location, local pickup disabled, and shipping requires address enabled, the shopper sees no shipping until an address is entered no pickup rates
+	// Skipping testing 11 because it is the same as 6.
+
+	// Skipping test due to a known bug with needs_shipping - see issue https://github.com/woocommerce/woocommerce/issues/56507
+	test.skip( '12. With no shipping methods for the default location, no shipping methods for _any_ other location, local pickup disabled, and shipping requires address enabled the shopper sees no shipping and no pickup rates', async ( {
+		localPickupUtils,
+		admin,
+		frontendUtils,
+		shippingUtils,
+	} ) => {
+		await admin.visitAdminPage( 'admin.php?page=wc-settings&tab=shipping' );
+		// Accept the delete dialog, then remove the listener;
+		const acceptDialog = ( dialog: Dialog ) => dialog.accept();
+		admin.page.on( 'dialog', acceptDialog );
+		await admin.page.getByRole( 'link', { name: 'Delete' } ).click();
+		admin.page.off( 'dialog', acceptDialog );
+
+		await localPickupUtils.disableLocalPickup();
+		await shippingUtils.enableShippingCostsRequireAddress();
+
+		await admin.visitAdminPage( 'admin.php?page=wc-settings&tab=shipping' );
+
+		await admin.page
+			.getByRole( 'row', { name: 'Rest of the world' } )
+			.getByRole( 'link' )
+			.click();
+
+		// There are two shipping rates enabled. Clicking the first one turns it off.
+		// Then only one "name: yes" remains, making it the first, even though it's the second rate.
+		await admin.page.getByRole( 'link', { name: 'Yes' } ).first().click();
+		await admin.page.getByRole( 'link', { name: 'Yes' } ).first().click();
+		await admin.saveAdminPage();
+
+		await frontendUtils.goToShop();
+		await frontendUtils.addToCart( REGULAR_PRICED_PRODUCT_NAME );
+		await frontendUtils.goToCheckout();
+
+		await expect(
+			frontendUtils.page.getByRole( 'radio', {
+				name: 'Ship',
+				exact: true,
+			} )
+		).toBeHidden();
+
+		await expect(
+			frontendUtils.page.getByRole( 'heading', {
+				name: 'Shipping options',
+			} )
+		).toBeHidden();
+	} );
+
+	test( 'Guest user does not see shipping rates until full address is entered', async ( {
+		requestUtils,
+		browser,
+	} ) => {
+		const guestContext = await browser.newContext();
+		const userPage = await guestContext.newPage();
+
+		const userFrontendUtils = new FrontendUtils( userPage, requestUtils );
+		const userCheckoutPageObject = new CheckoutPage( { page: userPage } );
+
+		await userFrontendUtils.goToShop();
+		await userFrontendUtils.addToCart( REGULAR_PRICED_PRODUCT_NAME );
+		await userFrontendUtils.goToCheckout();
+
+		await expect(
+			userPage.getByText(
+				'Enter a shipping address to view shipping options.'
+			)
+		).toBeVisible();
+
+		await userCheckoutPageObject.fillInCheckoutWithTestData();
+
+		await expect(
+			userPage.getByText(
+				'Enter a shipping address to view shipping options.'
+			)
+		).toBeHidden();
 	} );
 } );
diff --git a/plugins/woocommerce/tests/e2e/tests/blocks/cart/cart-store.block_theme.spec.ts b/plugins/woocommerce/tests/e2e/tests/blocks/cart/cart-store.block_theme.spec.ts
index eab4ff760bd..83b4f025a9e 100644
--- a/plugins/woocommerce/tests/e2e/tests/blocks/cart/cart-store.block_theme.spec.ts
+++ b/plugins/woocommerce/tests/e2e/tests/blocks/cart/cart-store.block_theme.spec.ts
@@ -11,97 +11,63 @@ import { REGULAR_PRICED_PRODUCT_NAME } from '../checkout/constants';
 test.describe( 'Cart Store', () => {
 	test.use( { storageState: guestFile } );

+	test.beforeEach( async ( { requestUtils } ) => {
+		await requestUtils.activatePlugin(
+			'woocommerce-blocks-test-short-nonce-life'
+		);
+	} );
+
 	test( 'should refresh nonce from Store API and use it for cart mutations', async ( {
 		page,
 		frontendUtils,
 	} ) => {
-		const refreshCartResponse = page.waitForResponse(
-			( response ) =>
-				response.url().includes( '/wc/store/v1/cart' ) &&
-				response.request().method() === 'GET'
-		);
-		let initialBatchRequestNonce: string | null = null;
-		let invalidateNextBatch = false;
-		let invalidBatchRequestNonce: string | null = null;
-		let invalidResponseNonce: string | null = null;
-		let invalidResponseBody = '';
-		let captureRecoveryBatch = false;
-		let recoveryBatchRequestNonce: string | null = null;
+		let refreshNonce: string | null = null;
+		let requestNonce: string | null = null;
+		let responseNonce: string | null = null;

-		// Forward exactly one invalid nonce to the real Store API so its response
-		// supplies the replacement nonce the client must use for the next mutation.
-		await page.route( '**/wc/store/v1/batch**', async ( route ) => {
-			const batch = JSON.parse( route.request().postData() || '{}' );
-			const [ batchRequest ] = batch.requests || [];
-			const isCartAddItemBatch =
-				batch.requests?.length === 1 &&
-				batchRequest?.method === 'POST' &&
-				batchRequest.path === '/wc/store/v1/cart/add-item';
-			const requestNonce = isCartAddItemBatch
-				? batchRequest.headers?.Nonce || null
-				: null;
-
-			if ( invalidateNextBatch && isCartAddItemBatch ) {
-				invalidateNextBatch = false;
-				invalidBatchRequestNonce = requestNonce;
-				const invalidBatch = {
-					...batch,
-					requests: [
-						{
-							...batchRequest,
-							headers: {
-								...batchRequest.headers,
-								Nonce: 'invalid-test-nonce',
-							},
-						},
-					],
-				};
-				const response = await route.fetch( {
-					postData: JSON.stringify( invalidBatch ),
-				} );
-				invalidResponseNonce = response.headers().nonce || null;
-				invalidResponseBody = await response.text();
+		// Intercept GET /cart (refreshCartItems) to capture the nonce.
+		await page.route( '**/wc/store/v1/cart**', async ( route ) => {
+			if ( route.request().method() === 'GET' ) {
+				const response = await route.fetch();
+				refreshNonce = response.headers().nonce || null;
 				await route.fulfill( { response } );
-				return;
-			}
-
-			if (
-				isCartAddItemBatch &&
-				captureRecoveryBatch &&
-				! recoveryBatchRequestNonce
-			) {
-				recoveryBatchRequestNonce = requestNonce;
-			} else if ( isCartAddItemBatch && ! initialBatchRequestNonce ) {
-				initialBatchRequestNonce = requestNonce;
+			} else {
+				await route.continue();
 			}
+		} );

+		// Intercept batch requests to track which nonce the client sends
+		// and which nonce the server returns.
+		await page.route( '**/wc/store/v1/batch**', async ( route ) => {
+			requestNonce = route.request().headers().nonce || null;
 			const response = await route.fetch();
+			responseNonce = response.headers().nonce || null;
 			await route.fulfill( { response } );
 		} );

 		await frontendUtils.goToShop();
-		const refreshCartNonce =
-			( await refreshCartResponse ).headers().nonce || null;
-		expect( refreshCartNonce ).toBeTruthy();
+
+		// The GET /cart fires during page load, so a waitForResponse set up
+		// here can miss it — poll the intercepted nonce instead.
+		await expect.poll( () => refreshNonce ).toBeTruthy();

 		// Adding a product should use the nonce from refreshCartItems.
 		await frontendUtils.addToCart( REGULAR_PRICED_PRODUCT_NAME );
-		expect( initialBatchRequestNonce ).toBe( refreshCartNonce );
+		expect( requestNonce ).toBe( refreshNonce );
+
+		// Wait for the nonce to expire.
+		// eslint-disable-next-line playwright/no-wait-for-timeout, no-restricted-syntax
+		await page.waitForTimeout( 2000 );

-		// Forward an invalid nonce and let the real Store API return its error and replacement nonce.
-		invalidateNextBatch = true;
+		// Adding another product should fail because it is using an expired nonce.
 		await frontendUtils.addToCart( REGULAR_PRICED_PRODUCT_NAME );
-		expect( invalidResponseBody ).toContain(
-			'woocommerce_rest_invalid_nonce'
-		);
 		await expect( page.getByText( 'Nonce is invalid.' ) ).toBeVisible();
-		expect( invalidBatchRequestNonce ).toBe( initialBatchRequestNonce );
-		expect( invalidResponseNonce ).toBeTruthy();
+		const previousResponseNonce = responseNonce;

-		// The next mutation should use the exact nonce returned by the invalid response.
-		captureRecoveryBatch = true;
+		// Nonce should be updated now and the request should succeed.
 		await frontendUtils.addToCart( REGULAR_PRICED_PRODUCT_NAME );
-		expect( recoveryBatchRequestNonce ).toBe( invalidResponseNonce );
+		expect( requestNonce ).not.toBe( refreshNonce );
+		expect( requestNonce ).toBe( previousResponseNonce );

 		// Verify the product was actually added to the cart properly.
 		await frontendUtils.goToCart();
diff --git a/plugins/woocommerce/tests/legacy/unit-tests/coupon/coupon.php b/plugins/woocommerce/tests/legacy/unit-tests/coupon/coupon.php
index 3cea2928fc0..e6fd2127c68 100644
--- a/plugins/woocommerce/tests/legacy/unit-tests/coupon/coupon.php
+++ b/plugins/woocommerce/tests/legacy/unit-tests/coupon/coupon.php
@@ -284,13 +284,6 @@ class WC_Tests_Coupon extends WC_Unit_Test_Case {

 	/**
 	 * Test an item limit for percent discounts.
-	 *
-	 * Defines WOOCOMMERCE_CHECKOUT, which a process cannot undefine, so it stays set
-	 * for every test that runs after this one. Do not reach for process isolation to
-	 * contain that: the forked child re-runs tests/legacy/bootstrap.php, which writes
-	 * woocommerce_custom_orders_table_enabled over its own connection, outside the
-	 * parent's rolled-back transaction, and flips the order store for the rest of the
-	 * run.
 	 */
 	public function test_percent_discount_item_limit() {
 		// Create product.
diff --git a/plugins/woocommerce/tests/php/src/Blocks/StoreApi/Routes/Cart.php b/plugins/woocommerce/tests/php/src/Blocks/StoreApi/Routes/Cart.php
index ea631492200..0b1f9ca1023 100644
--- a/plugins/woocommerce/tests/php/src/Blocks/StoreApi/Routes/Cart.php
+++ b/plugins/woocommerce/tests/php/src/Blocks/StoreApi/Routes/Cart.php
@@ -146,45 +146,6 @@ class Cart extends ControllerTestCase {
 		wc()->customer->set_shipping_country( 'US' );
 	}

-	/**
-	 * Dispatches a Store API add-item request.
-	 *
-	 * @param array $body Request body.
-	 * @return \WP_REST_Response
-	 */
-	private function dispatch_add_item_request( array $body ): \WP_REST_Response {
-		$request = new \WP_REST_Request( 'POST', '/wc/store/v1/cart/add-item' );
-		$request->set_header( 'Nonce', wp_create_nonce( 'wc_store_api' ) );
-		$request->set_body_params( $body );
-
-		return rest_get_server()->dispatch( $request );
-	}
-
-	/**
-	 * Gets a canonical map of the cart lines that participate in identity.
-	 *
-	 * @return array<string, array{key: string, product_id: int, variation_id: int, variation: array, quantity: int|float}>
-	 */
-	private function get_cart_line_identity_map(): array {
-		$cart_line_map = array();
-
-		foreach ( WC()->cart->get_cart() as $key => $cart_item ) {
-			$variation = $cart_item['variation'] ?? array();
-			ksort( $variation );
-
-			$cart_line_map[ $key ] = array(
-				'key'          => $key,
-				'product_id'   => (int) $cart_item['product_id'],
-				'variation_id' => (int) $cart_item['variation_id'],
-				'variation'    => $variation,
-				'quantity'     => wc_stock_amount( $cart_item['quantity'] ),
-			);
-		}
-
-		ksort( $cart_line_map );
-		return $cart_line_map;
-	}
-
 	/**
 	 * Test getting cart.
 	 */
@@ -367,420 +328,6 @@ class Cart extends ControllerTestCase {
 		);
 	}

-	/**
-	 * Test the shipping topology returned by the Store API.
-	 *
-	 * @testdox Store API serializes the expected rates and selected method for $scenario.
-	 * @dataProvider shipping_topology_provider
-	 *
-	 * @param string $scenario                 Scenario name.
-	 * @param bool   $has_default_rate         Whether the Rest of the World zone has a rate.
-	 * @param bool   $has_gb_rate              Whether the GB zone has a rate.
-	 * @param bool   $has_pickup               Whether Local Pickup is enabled.
-	 * @param bool   $requires_address          Whether rates require a complete address.
-	 * @param string $address_key               Address fixture key.
-	 * @param array  $expected_rate_keys        Expected rate fixture keys.
-	 * @param string $expected_selected_rate_key Expected selected rate fixture key.
-	 */
-	public function test_shipping_topology(
-		string $scenario,
-		bool $has_default_rate,
-		bool $has_gb_rate,
-		bool $has_pickup,
-		bool $requires_address,
-		string $address_key,
-		array $expected_rate_keys,
-		string $expected_selected_rate_key
-	): void {
-		unset( $scenario );
-
-		$customer     = $this->capture_shipping_address();
-		$session      = $this->capture_shipping_session();
-		$cart_context = WC()->cart->cart_context;
-		$country_data = get_object_vars( WC()->countries );
-		$has_locale   = array_key_exists( 'locale', $country_data );
-		$locale       = $has_locale ? $country_data['locale'] : array();
-		$fixtures     = new FixtureData();
-		$topology     = array();
-
-		try {
-			unset( WC()->countries->locale );
-			$this->configure_shipping_topology( $fixtures, $has_default_rate, $has_gb_rate, $has_pickup, $topology );
-
-			update_option( 'woocommerce_default_customer_address', 'blank' === $address_key ? '' : 'base' );
-			update_option( 'woocommerce_shipping_cost_requires_address', $requires_address ? 'yes' : 'no' );
-			WC()->cart->cart_context = 'store-api';
-			$this->clear_shipping_session();
-
-			$address = $this->get_shipping_address_fixture( $address_key );
-			$request = new \WP_REST_Request( 'POST', '/wc/store/v1/cart/update-customer' );
-			$request->set_header( 'Nonce', wp_create_nonce( 'wc_store_api' ) );
-			$request->set_body_params( array( 'shipping_address' => (object) $address ) );
-			$response = rest_get_server()->dispatch( $request );
-			$data     = $response->get_data();
-
-			$this->assertSame( 200, $response->get_status(), 'The customer update should succeed.' );
-			$this->assertTrue( $data['needs_shipping'], 'The cart should continue to require shipping.' );
-
-			$expected_package_count = $requires_address && 'blank' === $address_key && ! $has_pickup ? 0 : 1;
-			$this->assertCount( $expected_package_count, $data['shipping_rates'], 'The response should serialize the exact expected package count.' );
-
-			if ( 0 === $expected_package_count ) {
-				$this->assertSame( array(), WC()->session->get( 'chosen_shipping_methods', array() ), 'No hidden package should choose a shipping method.' );
-				return;
-			}
-
-			$package              = (array) $data['shipping_rates'][0];
-			$destination          = (array) $package['destination'];
-			$rates                = array_map(
-				function ( $rate ): array {
-					return (array) $rate;
-				},
-				$package['shipping_rates']
-			);
-			$expected_destination = array_intersect_key(
-				$address,
-				array_flip( array( 'address_1', 'address_2', 'city', 'state', 'postcode', 'country' ) )
-			);
-
-			$this->assertSame( $expected_destination, $destination, 'The serialized package destination should match the submitted address exactly.' );
-
-			$expected_rate_ids = array_map(
-				function ( string $key ) use ( $topology ): string {
-					return $topology['rate_ids'][ $key ];
-				},
-				$expected_rate_keys
-			);
-			$actual_rate_ids   = array_column( $rates, 'rate_id' );
-			sort( $expected_rate_ids );
-			sort( $actual_rate_ids );
-
-			$this->assertSame( $expected_rate_ids, $actual_rate_ids, 'The response should contain only the expected concrete rates.' );
-
-			$expected_method_ids = array_map(
-				function ( string $key ) use ( $topology ): string {
-					return $topology['method_ids'][ $key ];
-				},
-				$expected_rate_keys
-			);
-			$actual_method_ids   = array_column( $rates, 'method_id' );
-			sort( $expected_method_ids );
-			sort( $actual_method_ids );
-
-			$this->assertSame( $expected_method_ids, $actual_method_ids, 'The response should contain only the expected shipping method types.' );
-
-			$selected_by_rate = array_column( $rates, 'selected', 'rate_id' );
-			foreach ( $expected_rate_ids as $rate_id ) {
-				$this->assertSame(
-					$expected_selected_rate_key && $topology['rate_ids'][ $expected_selected_rate_key ] === $rate_id,
-					$selected_by_rate[ $rate_id ],
-					"The selected flag should be exact for {$rate_id}."
-				);
-			}
-
-			$chosen_methods  = WC()->session->get( 'chosen_shipping_methods', array() );
-			$expected_chosen = $expected_selected_rate_key ? $topology['rate_ids'][ $expected_selected_rate_key ] : '';
-			$this->assertArrayHasKey( 0, $chosen_methods, 'A serialized package should persist a choice for package zero.' );
-			$this->assertSame( $expected_chosen, $chosen_methods[0], 'The session should persist the same method selected in the response.' );
-		} finally {
-			// The five shipping options this test writes are rows inside the transaction.
-			// Everything else below is on the WC() singletons, which this class does not
-			// inherit a teardown for: it extends WP_Test_REST_TestCase, not
-			// WC_Unit_Test_Case, so clear_wc_singleton_state() never runs.
-			$this->remove_shipping_topology( $fixtures, $topology );
-			$this->restore_shipping_address( $customer );
-			WC()->shipping()->reset_shipping();
-			$this->restore_shipping_session( $session );
-			WC()->cart->cart_context = $cart_context;
-			if ( $has_locale ) {
-				WC()->countries->locale = $locale;
-			} else {
-				unset( WC()->countries->locale );
-			}
-			\WC_Cache_Helper::get_transient_version( 'shipping', true );
-			delete_transient( 'wc_shipping_method_count' );
-		}
-	}
-
-	/**
-	 * The topology owner restores both present and missing incoming session values.
-	 *
-	 * @testdox Shipping topology restores exact incoming shipping and customer session values.
-	 */
-	public function test_shipping_topology_restores_existing_session_state(): void {
-		$keys     = array( 'chosen_shipping_methods', 'customer', 'shipping_method_counts' );
-		$original = array();
-
-		foreach ( $keys as $key ) {
-			$original[ $key ] = array(
-				'exists' => isset( WC()->session->{$key} ),
-				'value'  => WC()->session->get( $key ),
-			);
-		}
-
-		try {
-			$chosen_methods = array( 'external_shipping:7' );
-			$customer       = array( 'shipping_country' => 'SE' );
-			WC()->session->set( 'chosen_shipping_methods', $chosen_methods );
-			WC()->session->set( 'customer', $customer );
-			WC()->session->set( 'shipping_method_counts', null );
-
-			$this->test_shipping_topology(
-				'session restoration',
-				false,
-				true,
-				true,
-				true,
-				'blank',
-				array( 'pickup' ),
-				''
-			);
-
-			$this->assertTrue( isset( WC()->session->chosen_shipping_methods ), 'The incoming chosen-method key should remain present.' );
-			$this->assertSame( $chosen_methods, WC()->session->get( 'chosen_shipping_methods' ), 'The incoming chosen methods should be restored exactly.' );
-			$this->assertTrue( isset( WC()->session->customer ), 'The incoming customer key should remain present.' );
-			$this->assertSame( $customer, WC()->session->get( 'customer' ), 'The incoming customer session value should be restored exactly.' );
-			$this->assertFalse( isset( WC()->session->shipping_method_counts ), 'An incoming missing session key should remain missing.' );
-		} finally {
-			foreach ( $original as $key => $session_value ) {
-				WC()->session->set( $key, $session_value['exists'] ? $session_value['value'] : null );
-			}
-		}
-	}
-
-	/**
-	 * Shipping topology scenarios.
-	 *
-	 * @return array<string, array{string, bool, bool, bool, bool, string, string[], string}>
-	 */
-	public function shipping_topology_provider(): array {
-		return array(
-			'default and any rates with pickup'       => array( 'default and any rates with pickup', true, true, true, false, 'us', array( 'default', 'pickup' ), 'default' ),
-			'default and any rates without pickup'    => array( 'default and any rates without pickup', true, true, false, false, 'us', array( 'default' ), 'default' ),
-			'default rate only'                       => array( 'default rate only', true, false, false, false, 'us', array( 'default' ), 'default' ),
-			'any rate only before address'            => array( 'any rate only before address', false, true, false, false, 'blank', array(), '' ),
-			'any rate only for a nonmatching address' => array( 'any rate only for a nonmatching address', false, true, false, false, 'us', array(), '' ),
-			'any rate only for a matching address'    => array( 'any rate only for a matching address', false, true, false, false, 'gb', array( 'gb' ), 'gb' ),
-			'pickup only without required address'    => array( 'pickup only without required address', false, false, true, false, 'blank', array( 'pickup' ), 'pickup' ),
-			'pickup only with required address'       => array( 'pickup only with required address', false, true, true, true, 'blank', array( 'pickup' ), '' ),
-			'no rates without required address'       => array( 'no rates without required address', false, false, false, false, 'blank', array(), '' ),
-			'no rates with required address'          => array( 'no rates with required address', false, false, false, true, 'blank', array(), '' ),
-			'required address before entry'           => array( 'required address before entry', true, true, false, true, 'blank', array(), '' ),
-			'required address with default rate'      => array( 'required address with default rate', true, true, false, true, 'us', array( 'default' ), 'default' ),
-			'required address with any rate'          => array( 'required address with any rate', true, true, false, true, 'gb', array( 'gb' ), 'gb' ),
-		);
-	}
-
-	/**
-	 * Configure real zones and shipping methods for a topology scenario.
-	 *
-	 * @param FixtureData $fixtures         Fixture helper.
-	 * @param bool        $has_default_rate Whether the default zone gets a rate.
-	 * @param bool        $has_gb_rate      Whether the GB zone gets a rate.
-	 * @param bool        $has_pickup       Whether pickup is enabled.
-	 * @param array       $topology         Created topology data, updated as records are added.
-	 */
-	private function configure_shipping_topology( FixtureData $fixtures, bool $has_default_rate, bool $has_gb_rate, bool $has_pickup, array &$topology ): void {
-		update_option( 'woocommerce_flat_rate_settings', array( 'enabled' => 'no' ) );
-
-		$topology = array(
-			'rate_ids'   => array( 'pickup' => 'pickup_location:0' ),
-			'method_ids' => array(
-				'default' => 'flat_rate',
-				'gb'      => 'flat_rate',
-				'pickup'  => 'pickup_location',
-			),
-		);
-
-		if ( $has_default_rate ) {
-			$default_zone = \WC_Shipping_Zones::get_zone( 0 );
-			if ( ! $default_zone instanceof \WC_Shipping_Zone ) {
-				throw new \RuntimeException( 'The default shipping zone should be available.' );
-			}
-
-			$topology['default_instance_id'] = $default_zone->add_shipping_method( 'flat_rate' );
-			$topology['rate_ids']['default'] = 'flat_rate:' . $topology['default_instance_id'];
-			update_option(
-				'woocommerce_flat_rate_' . $topology['default_instance_id'] . '_settings',
-				array(
-					'enabled'    => 'yes',
-					'title'      => 'Default delivery',
-					'tax_status' => 'none',
-					'cost'       => '10',
-				)
-			);
-		}
-
-		if ( $has_gb_rate ) {
-			$gb_zone = new \WC_Shipping_Zone();
-			$gb_zone->set_zone_name( 'United Kingdom' );
-			$gb_zone->set_zone_locations(
-				array(
-					(object) array(
-						'code' => 'GB',
-						'type' => 'country',
-					),
-				)
-			);
-			$gb_zone->save();
-			$topology['gb_zone']        = $gb_zone;
-			$topology['gb_instance_id'] = $gb_zone->add_shipping_method( 'flat_rate' );
-			$topology['rate_ids']['gb'] = 'flat_rate:' . $topology['gb_instance_id'];
-			update_option(
-				'woocommerce_flat_rate_' . $topology['gb_instance_id'] . '_settings',
-				array(
-					'enabled'    => 'yes',
-					'title'      => 'UK delivery',
-					'tax_status' => 'none',
-					'cost'       => '15',
-				)
-			);
-		}
-
-		if ( $has_pickup ) {
-			$fixtures->shipping_add_pickup_location();
-			$topology['pickup_registered'] = true;
-		}
-
-		WC()->shipping()->reset_shipping();
-		\WC_Cache_Helper::get_transient_version( 'shipping', true );
-		delete_transient( 'wc_shipping_method_count' );
-	}
-
-	/**
-	 * Remove topology records created by a scenario.
-	 *
-	 * @param FixtureData $fixtures Fixture helper.
-	 * @param array       $topology Created topology data.
-	 */
-	private function remove_shipping_topology( FixtureData $fixtures, array $topology ): void {
-		if ( isset( $topology['default_instance_id'] ) ) {
-			$default_zone = \WC_Shipping_Zones::get_zone( 0 );
-			if ( $default_zone instanceof \WC_Shipping_Zone ) {
-				$default_zone->delete_shipping_method( $topology['default_instance_id'] );
-			}
-		}
-
-		if ( isset( $topology['gb_zone'] ) && $topology['gb_zone'] instanceof \WC_Shipping_Zone ) {
-			$topology['gb_zone']->delete( true );
-		}
-
-		if ( ! empty( $topology['pickup_registered'] ) ) {
-			$fixtures->shipping_remove_pickup_location();
-		}
-	}
-
-	/**
-	 * Get an exact address fixture for a topology scenario.
-	 *
-	 * @param string $key Fixture key.
-	 * @return array<string, string>
-	 */
-	private function get_shipping_address_fixture( string $key ): array {
-		$addresses = array(
-			'blank' => array(
-				'first_name' => '',
-				'last_name'  => '',
-				'company'    => '',
-				'address_1'  => '',
-				'address_2'  => '',
-				'city'       => '',
-				'state'      => '',
-				'postcode'   => '',
-				'country'    => '',
-			),
-			'us'    => array(
-				'first_name' => 'Pat',
-				'last_name'  => 'Shopper',
-				'company'    => '',
-				'address_1'  => '60 29th Street',
-				'address_2'  => '',
-				'city'       => 'San Francisco',
-				'state'      => 'CA',
-				'postcode'   => '94110',
-				'country'    => 'US',
-			),
-			'gb'    => array(
-				'first_name' => 'Pat',
-				'last_name'  => 'Shopper',
-				'company'    => '',
-				'address_1'  => '1 New Change',
-				'address_2'  => '',
-				'city'       => 'London',
-				'state'      => '',
-				'postcode'   => 'EC4M 9AF',
-				'country'    => 'GB',
-			),
-		);
-
-		return $addresses[ $key ];
-	}
-
-	/**
-	 * Capture the current shipping address.
-	 *
-	 * @return array<string, string>
-	 */
-	private function capture_shipping_address(): array {
-		$address = array();
-		foreach ( array( 'first_name', 'last_name', 'company', 'address_1', 'address_2', 'city', 'state', 'postcode', 'country' ) as $field ) {
-			$getter            = 'get_shipping_' . $field;
-			$address[ $field ] = WC()->customer->$getter();
-		}
-
-		return $address;
-	}
-
-	/**
-	 * Restore a shipping address.
-	 *
-	 * @param array<string, string> $address Shipping address.
-	 */
-	private function restore_shipping_address( array $address ): void {
-		foreach ( $address as $field => $value ) {
-			$setter = 'set_shipping_' . $field;
-			WC()->customer->$setter( $value );
-		}
-	}
-
-	/**
-	 * Capture session values involved in shipping selection and caching.
-	 *
-	 * @return array<string, array{exists: bool, value: mixed}>
-	 */
-	private function capture_shipping_session(): array {
-		$session = array();
-		foreach ( array( 'chosen_shipping_methods', 'shipping_method_counts', 'previous_shipping_methods', 'shipping_for_package_0', 'customer' ) as $key ) {
-			$session[ $key ] = array(
-				'exists' => isset( WC()->session->{$key} ),
-				'value'  => WC()->session->get( $key ),
-			);
-		}
-
-		return $session;
-	}
-
-	/**
-	 * Clear session values involved in shipping selection and caching.
-	 */
-	private function clear_shipping_session(): void {
-		foreach ( array( 'chosen_shipping_methods', 'shipping_method_counts', 'previous_shipping_methods', 'shipping_for_package_0' ) as $key ) {
-			WC()->session->set( $key, null );
-		}
-		WC()->shipping()->reset_shipping();
-	}
-
-	/**
-	 * Restore shipping session values.
-	 *
-	 * @param array<string, array{exists: bool, value: mixed}> $session Session values.
-	 */
-	private function restore_shipping_session( array $session ): void {
-		foreach ( $session as $key => $session_value ) {
-			WC()->session->set( $key, $session_value['exists'] ? $session_value['value'] : null );
-		}
-	}
-
 	/**
 	 * Test shipping address validation.
 	 */
@@ -1470,288 +1017,6 @@ class Cart extends ControllerTestCase {
 		);
 	}

-	/**
-	 * @testdox Re-adding a standalone product preserves its cart-line key and increments its quantity.
-	 */
-	public function test_add_item_preserves_standalone_cart_line_identity(): void {
-		wc_empty_cart();
-
-		$first_response = $this->dispatch_add_item_request(
-			array(
-				'id'       => $this->products[0]->get_id(),
-				'quantity' => 1,
-			)
-		);
-		$first_data     = $first_response->get_data();
-
-		$this->assertSame( 201, $first_response->get_status(), 'The first standalone add should succeed.' );
-		$this->assertCount( 1, $first_data['items'], 'The first add should create exactly one cart line.' );
-		$cart_item_key = $first_data['items'][0]['key'];
-		$this->assertSame(
-			array(
-				$cart_item_key => array(
-					'key'          => $cart_item_key,
-					'product_id'   => $this->products[0]->get_id(),
-					'variation_id' => 0,
-					'variation'    => array(),
-					'quantity'     => 1,
-				),
-			),
-			$this->get_cart_line_identity_map(),
-			'The first add should create the expected standalone cart line.'
-		);
-
-		$second_response = $this->dispatch_add_item_request(
-			array(
-				'id'       => $this->products[0]->get_id(),
-				'quantity' => 1,
-			)
-		);
-		$second_data     = $second_response->get_data();
-
-		$this->assertSame( 201, $second_response->get_status(), 'The standalone re-add should succeed.' );
-		$this->assertCount( 1, $second_data['items'], 'The re-add should not create another cart line.' );
-		$this->assertSame( $cart_item_key, $second_data['items'][0]['key'], 'The re-add should preserve the server cart-line key.' );
-		$this->assertSame(
-			array(
-				$cart_item_key => array(
-					'key'          => $cart_item_key,
-					'product_id'   => $this->products[0]->get_id(),
-					'variation_id' => 0,
-					'variation'    => array(),
-					'quantity'     => 2,
-				),
-			),
-			$this->get_cart_line_identity_map(),
-			'The re-add should increment only the existing standalone line.'
-		);
-	}
-
-	/**
-	 * @testdox Cart item data keeps a same-product meta line distinct from the standalone line.
-	 */
-	public function test_add_item_preserves_cart_item_data_identity(): void {
-		wc_empty_cart();
-
-		$add_cart_item_data = function ( $add_to_cart_data, $request ) {
-			if ( 'meta-line' === $request->get_param( 'cart_line_identity_marker' ) ) {
-				$add_to_cart_data['cart_item_data']['_cart_line_identity'] = 'meta-line';
-			}
-			return $add_to_cart_data;
-		};
-		add_filter( 'woocommerce_store_api_add_to_cart_data', $add_cart_item_data, 10, 2 );
-
-		try {
-			$meta_response = $this->dispatch_add_item_request(
-				array(
-					'id'                        => $this->products[0]->get_id(),
-					'quantity'                  => 1,
-					'cart_line_identity_marker' => 'meta-line',
-				)
-			);
-			$meta_map      = $this->get_cart_line_identity_map();
-			$meta_key      = array_key_first( $meta_map );
-
-			$this->assertSame( 201, $meta_response->get_status(), 'The marker-scoped meta-line add should succeed.' );
-			$this->assertCount( 1, $meta_map, 'The first request should create exactly the meta line.' );
-
-			$plain_response = $this->dispatch_add_item_request(
-				array(
-					'id'       => $this->products[0]->get_id(),
-					'quantity' => 1,
-				)
-			);
-			$mixed_map      = $this->get_cart_line_identity_map();
-			$plain_keys     = array_values( array_diff( array_keys( $mixed_map ), array( $meta_key ) ) );
-
-			$this->assertSame( 201, $plain_response->get_status(), 'The first plain add should succeed.' );
-			$this->assertCount( 1, $plain_keys, 'The plain add should create one distinct standalone key.' );
-			$plain_key = $plain_keys[0];
-			$expected  = array(
-				$meta_key  => array(
-					'key'          => $meta_key,
-					'product_id'   => $this->products[0]->get_id(),
-					'variation_id' => 0,
-					'variation'    => array(),
-					'quantity'     => 1,
-				),
-				$plain_key => array(
-					'key'          => $plain_key,
-					'product_id'   => $this->products[0]->get_id(),
-					'variation_id' => 0,
-					'variation'    => array(),
-					'quantity'     => 1,
-				),
-			);
-			ksort( $expected );
-			$this->assertSame( $expected, $mixed_map, 'The meta and standalone lines should remain distinct at quantity one.' );
-
-			$second_plain_response              = $this->dispatch_add_item_request(
-				array(
-					'id'       => $this->products[0]->get_id(),
-					'quantity' => 1,
-				)
-			);
-			$expected[ $plain_key ]['quantity'] = 2;
-
-			$this->assertSame( 201, $second_plain_response->get_status(), 'The standalone re-add should succeed.' );
-			$this->assertSame( $expected, $this->get_cart_line_identity_map(), 'Only the standalone line should increment.' );
-		} finally {
-			remove_filter( 'woocommerce_store_api_add_to_cart_data', $add_cart_item_data, 10 );
-		}
-	}
-
-	/**
-	 * @testdox Re-adding one variation preserves its key while another variation creates a distinct line.
-	 */
-	public function test_add_item_preserves_variation_identity(): void {
-		wc_empty_cart();
-
-		$fixtures         = new FixtureData();
-		$variable_product = $fixtures->get_variable_product(
-			array(
-				'name'          => 'Cart line identity variable product',
-				'stock_status'  => ProductStockStatus::IN_STOCK,
-				'regular_price' => 10,
-			),
-			array(
-				$fixtures->get_product_attribute( 'color', array( 'red', 'blue' ) ),
-			)
-		);
-		$red_variation    = $fixtures->get_variation_product( $variable_product->get_id(), array( 'pa_color' => 'red' ) );
-		$blue_variation   = $fixtures->get_variation_product( $variable_product->get_id(), array( 'pa_color' => 'blue' ) );
-
-		$red_body       = array(
-			'id'        => $red_variation->get_id(),
-			'quantity'  => 1,
-			'variation' => array(
-				array(
-					'attribute' => 'pa_color',
-					'value'     => 'red',
-				),
-			),
-		);
-		$first_response = $this->dispatch_add_item_request( $red_body );
-		$first_map      = $this->get_cart_line_identity_map();
-		$red_key        = array_key_first( $first_map );
-
-		$this->assertSame( 201, $first_response->get_status(), 'The first variation add should succeed.' );
-		$this->assertCount( 1, $first_map, 'The first variation add should create exactly one line.' );
-
-		$second_response = $this->dispatch_add_item_request( $red_body );
-		$second_map      = $this->get_cart_line_identity_map();
-
-		$this->assertSame( 201, $second_response->get_status(), 'Re-adding the same variation should succeed.' );
-		$this->assertSame( array( $red_key ), array_keys( $second_map ), 'The same variation should preserve its cart-line key.' );
-		$this->assertSame( 2, $second_map[ $red_key ]['quantity'], 'The same variation should increment its line.' );
-
-		$blue_response = $this->dispatch_add_item_request(
-			array(
-				'id'        => $blue_variation->get_id(),
-				'quantity'  => 1,
-				'variation' => array(
-					array(
-						'attribute' => 'pa_color',
-						'value'     => 'blue',
-					),
-				),
-			)
-		);
-		$final_map     = $this->get_cart_line_identity_map();
-		$blue_keys     = array_values( array_diff( array_keys( $final_map ), array( $red_key ) ) );
-
-		$this->assertSame( 201, $blue_response->get_status(), 'Adding a different variation should succeed.' );
-		$this->assertCount( 1, $blue_keys, 'The different variation should create one distinct key.' );
-		$blue_key = $blue_keys[0];
-		$this->assertSame( $red_variation->get_id(), $final_map[ $red_key ]['variation_id'], 'The original key should still identify the red variation.' );
-		$this->assertSame( 2, $final_map[ $red_key ]['quantity'], 'The red variation quantity should remain two.' );
-		$this->assertSame( $blue_variation->get_id(), $final_map[ $blue_key ]['variation_id'], 'The new key should identify the blue variation.' );
-		$this->assertSame( 1, $final_map[ $blue_key ]['quantity'], 'The blue variation should start at quantity one.' );
-	}
-
-	/**
-	 * @testdox A rejected sold-individually re-add leaves the exact cart-line map unchanged.
-	 */
-	public function test_rejected_add_item_leaves_sold_individually_cart_unchanged(): void {
-		wc_empty_cart();
-
-		$product                    = $this->products[0];
-		$original_sold_individually = $product->get_sold_individually();
-		$product->set_sold_individually( true );
-		$product->save();
-
-		try {
-			$first_response  = $this->dispatch_add_item_request(
-				array(
-					'id'       => $product->get_id(),
-					'quantity' => 1,
-				)
-			);
-			$before          = $this->get_cart_line_identity_map();
-			$second_response = $this->dispatch_add_item_request(
-				array(
-					'id'       => $product->get_id(),
-					'quantity' => 1,
-				)
-			);
-			$second_data     = $second_response->get_data();
-
-			$this->assertSame( 201, $first_response->get_status(), 'The first sold-individually add should succeed.' );
-			$this->assertSame( 400, $second_response->get_status(), 'The sold-individually re-add should be rejected.' );
-			$this->assertSame( 'readonly_quantity', $second_data['code'], 'The rejection should report the Store API quantity-limit code.' );
-			$this->assertSame( $before, $this->get_cart_line_identity_map(), 'The rejected re-add should leave every cart line unchanged.' );
-		} finally {
-			$product->set_sold_individually( $original_sold_individually );
-			$product->save();
-		}
-	}
-
-	/**
-	 * @testdox A rejected managed-stock re-add leaves the exact cart-line map unchanged.
-	 */
-	public function test_rejected_add_item_leaves_managed_stock_cart_unchanged(): void {
-		wc_empty_cart();
-
-		$product                 = $this->products[1];
-		$original_manage_stock   = $product->get_manage_stock();
-		$original_stock_quantity = $product->get_stock_quantity();
-		$original_backorders     = $product->get_backorders();
-		$original_stock_status   = $product->get_stock_status();
-		$product->set_manage_stock( true );
-		$product->set_stock_quantity( 1 );
-		$product->set_backorders( 'no' );
-		$product->set_stock_status( ProductStockStatus::IN_STOCK );
-		$product->save();
-
-		try {
-			$first_response  = $this->dispatch_add_item_request(
-				array(
-					'id'       => $product->get_id(),
-					'quantity' => 1,
-				)
-			);
-			$before          = $this->get_cart_line_identity_map();
-			$second_response = $this->dispatch_add_item_request(
-				array(
-					'id'       => $product->get_id(),
-					'quantity' => 1,
-				)
-			);
-			$second_data     = $second_response->get_data();
-
-			$this->assertSame( 201, $first_response->get_status(), 'The first managed-stock add should succeed.' );
-			$this->assertSame( 400, $second_response->get_status(), 'The managed-stock re-add should be rejected.' );
-			$this->assertSame( 'woocommerce_rest_product_partially_out_of_stock', $second_data['code'], 'The rejection should report the Store API partial-stock code.' );
-			$this->assertSame( $before, $this->get_cart_line_identity_map(), 'The rejected re-add should leave every cart line unchanged.' );
-		} finally {
-			$product->set_manage_stock( $original_manage_stock );
-			$product->set_stock_quantity( $original_stock_quantity );
-			$product->set_backorders( $original_backorders );
-			$product->set_stock_status( $original_stock_status );
-			$product->save();
-		}
-	}
-
 	/**
 	 * Test adding item to cart with quantity 0 shows an error.
 	 */
diff --git a/plugins/woocommerce/tests/php/src/Blocks/StoreApi/Routes/CartApplyCoupon.php b/plugins/woocommerce/tests/php/src/Blocks/StoreApi/Routes/CartApplyCoupon.php
index c1ab38bad61..fec8c48448a 100644
--- a/plugins/woocommerce/tests/php/src/Blocks/StoreApi/Routes/CartApplyCoupon.php
+++ b/plugins/woocommerce/tests/php/src/Blocks/StoreApi/Routes/CartApplyCoupon.php
@@ -217,7 +217,6 @@ class CartApplyCoupon extends ControllerTestCase {
 	 */
 	public function test_coupon_usage_limit() {
 		wc()->cart->remove_coupons();
-		wp_set_current_user( 1 );

 		$fixtures = new FixtureData();

@@ -245,22 +244,10 @@ class CartApplyCoupon extends ControllerTestCase {

 		$response = rest_get_server()->dispatch( $request );
 		$data     = $response->get_data();
-		wp_set_current_user( 0 );

 		$this->assertEquals( 400, $response->get_status() );
 		$this->assertEquals( 'woocommerce_rest_cart_coupon_error', $data['code'] );
-		// Match the opening sentence rather than the whole message. WooCommerce has
-		// three usage-limit wordings and picks between them on whether the current
-		// user has a failed or pending order -- state this test does not own and any
-		// earlier test in the process can create. All three start the same way, and
-		// the coupon code is the part worth pinning.
-		$this->assertStringStartsWith(
-			sprintf(
-				'Usage limit for coupon "%s" has been reached.',
-				$limited_coupon->get_code()
-			),
-			html_entity_decode( $data['message'] )
-		);
+		$this->assertStringContainsString( 'Usage limit', html_entity_decode( $data['message'] ) );
 	}

 	/**