Commit 447fd1b706d for woocommerce
commit 447fd1b706dc9d02cbe6e77f098b604c7782f985
Author: Vlad Olaru <vlad.olaru@automattic.com>
Date: Thu Sep 24 18:18:18 2026 +0300
Revert "[tests] Move 4 extension cart update E2E tests to Jest and PHPUnit" (#69047)
* revert: Revert "[tests] Move 4 extension cart update E2E tests to Jest and PHPUnit" (#68585)
This reverts commit dc6c80ab111bf87f22c6e630f159538bffdb242a.
Rubik asked for the E2E migration's test changes in its areas to be
reverted until the team can review them. #68585 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 #68585
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* style: Add the space after function in a restored test closure
The #68585 revert brings back a closure in the Store API cart
extensions test written as `function()`. The rule that wants
`function ()` postdates it, and the CI lint job checks changed lines,
so the restored line would fail it as it is.
Refs #68585
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/client/blocks/changelog/testops-234-cart-checkout-extensibility b/plugins/woocommerce/client/blocks/changelog/testops-234-cart-checkout-extensibility
deleted file mode 100644
index 7cbcdb3e571..00000000000
--- a/plugins/woocommerce/client/blocks/changelog/testops-234-cart-checkout-extensibility
+++ /dev/null
@@ -1,4 +0,0 @@
-Significance: patch
-Type: dev
-Comment: Move 4 extension cart update E2E tests to Jest and PHPUnit, covering the extensionCartUpdate wrapper, the cart thunk, the notice context, and the CartExtensions route; keep one browser title per spec.
-
diff --git a/plugins/woocommerce/client/blocks/packages/public-api/block-data/cart/test/thunks.ts b/plugins/woocommerce/client/blocks/packages/public-api/block-data/cart/test/thunks.ts
index b50e9787307..59a92989540 100644
--- a/plugins/woocommerce/client/blocks/packages/public-api/block-data/cart/test/thunks.ts
+++ b/plugins/woocommerce/client/blocks/packages/public-api/block-data/cart/test/thunks.ts
@@ -430,13 +430,12 @@ describe( 'applyExtensionCartUpdate', () => {
it( 'should include both addresses when customer data is not dirty', async () => {
const dispatch = createMockDispatch();
- const result = await applyExtensionCartUpdate( {
+ await applyExtensionCartUpdate( {
namespace: 'test',
data: {},
} )( { dispatch } as never );
expect( dispatch.receiveCart ).toHaveBeenCalledWith( mockResponse );
- expect( result ).toBe( mockResponse );
} );
it( 'should set prefersCollection true when the extension response selects local pickup', async () => {
@@ -501,7 +500,7 @@ describe( 'applyExtensionCartUpdate', () => {
mockGetIsCustomerDataDirty.mockReturnValue( true );
const dispatch = createMockDispatch();
- const result = await applyExtensionCartUpdate( {
+ await applyExtensionCartUpdate( {
namespace: 'test',
data: {},
} )( { dispatch } as never );
@@ -510,14 +509,13 @@ describe( 'applyExtensionCartUpdate', () => {
expect( received ).not.toHaveProperty( 'shipping_address' );
expect( received ).not.toHaveProperty( 'billing_address' );
expect( received ).toHaveProperty( 'totals' );
- expect( result ).toBe( mockResponse );
} );
it( 'should strip both addresses when customer data is dirty and overwriteDirtyCustomerData is false', async () => {
mockGetIsCustomerDataDirty.mockReturnValue( true );
const dispatch = createMockDispatch();
- const result = await applyExtensionCartUpdate( {
+ await applyExtensionCartUpdate( {
namespace: 'test',
data: {},
overwriteDirtyCustomerData: false,
@@ -527,14 +525,13 @@ describe( 'applyExtensionCartUpdate', () => {
expect( received ).not.toHaveProperty( 'shipping_address' );
expect( received ).not.toHaveProperty( 'billing_address' );
expect( received ).toHaveProperty( 'totals' );
- expect( result ).toBe( mockResponse );
} );
it( 'should include both addresses when overwriteDirtyCustomerData is true', async () => {
mockGetIsCustomerDataDirty.mockReturnValue( true );
const dispatch = createMockDispatch();
- const result = await applyExtensionCartUpdate( {
+ await applyExtensionCartUpdate( {
namespace: 'test',
data: {},
overwriteDirtyCustomerData: true,
@@ -543,14 +540,13 @@ describe( 'applyExtensionCartUpdate', () => {
const received = dispatch.receiveCart.mock.calls[ 0 ][ 0 ];
expect( received ).toHaveProperty( 'shipping_address' );
expect( received ).toHaveProperty( 'billing_address' );
- expect( result ).toBe( mockResponse );
} );
it( 'should overwrite only shipping_address when specified as object', async () => {
mockGetIsCustomerDataDirty.mockReturnValue( true );
const dispatch = createMockDispatch();
- const result = await applyExtensionCartUpdate( {
+ await applyExtensionCartUpdate( {
namespace: 'test',
data: {},
overwriteDirtyCustomerData: { shipping_address: true },
@@ -562,14 +558,13 @@ describe( 'applyExtensionCartUpdate', () => {
} );
expect( received ).not.toHaveProperty( 'billing_address' );
expect( received ).toHaveProperty( 'totals' );
- expect( result ).toBe( mockResponse );
} );
it( 'should overwrite only billing_address when specified as object', async () => {
mockGetIsCustomerDataDirty.mockReturnValue( true );
const dispatch = createMockDispatch();
- const result = await applyExtensionCartUpdate( {
+ await applyExtensionCartUpdate( {
namespace: 'test',
data: {},
overwriteDirtyCustomerData: { billing_address: true },
@@ -580,14 +575,13 @@ describe( 'applyExtensionCartUpdate', () => {
expect( received.billing_address ).toEqual( {
address_1: '456 Bill Ave',
} );
- expect( result ).toBe( mockResponse );
} );
it( 'should overwrite both addresses when both specified in object', async () => {
mockGetIsCustomerDataDirty.mockReturnValue( true );
const dispatch = createMockDispatch();
- const result = await applyExtensionCartUpdate( {
+ await applyExtensionCartUpdate( {
namespace: 'test',
data: {},
overwriteDirtyCustomerData: {
@@ -603,14 +597,13 @@ describe( 'applyExtensionCartUpdate', () => {
expect( received.billing_address ).toEqual( {
address_1: '456 Bill Ave',
} );
- expect( result ).toBe( mockResponse );
} );
it( 'should strip both addresses when object has explicit false flags', async () => {
mockGetIsCustomerDataDirty.mockReturnValue( true );
const dispatch = createMockDispatch();
- const result = await applyExtensionCartUpdate( {
+ await applyExtensionCartUpdate( {
namespace: 'test',
data: {},
overwriteDirtyCustomerData: {
@@ -623,14 +616,13 @@ describe( 'applyExtensionCartUpdate', () => {
expect( received ).not.toHaveProperty( 'shipping_address' );
expect( received ).not.toHaveProperty( 'billing_address' );
expect( received ).toHaveProperty( 'totals' );
- expect( result ).toBe( mockResponse );
} );
it( 'should overwrite specified address even when customer data is not dirty', async () => {
mockGetIsCustomerDataDirty.mockReturnValue( false );
const dispatch = createMockDispatch();
- const result = await applyExtensionCartUpdate( {
+ await applyExtensionCartUpdate( {
namespace: 'test',
data: {},
overwriteDirtyCustomerData: { shipping_address: true },
@@ -645,14 +637,13 @@ describe( 'applyExtensionCartUpdate', () => {
expect( received.billing_address ).toEqual( {
address_1: '456 Bill Ave',
} );
- expect( result ).toBe( mockResponse );
} );
it( 'should treat null as false (no overwrite)', async () => {
mockGetIsCustomerDataDirty.mockReturnValue( true );
const dispatch = createMockDispatch();
- const result = await applyExtensionCartUpdate( {
+ await applyExtensionCartUpdate( {
namespace: 'test',
data: {},
overwriteDirtyCustomerData:
@@ -662,14 +653,13 @@ describe( 'applyExtensionCartUpdate', () => {
const received = dispatch.receiveCart.mock.calls[ 0 ][ 0 ];
expect( received ).not.toHaveProperty( 'shipping_address' );
expect( received ).not.toHaveProperty( 'billing_address' );
- expect( result ).toBe( mockResponse );
} );
it( 'should treat an array as false (no overwrite)', async () => {
mockGetIsCustomerDataDirty.mockReturnValue( true );
const dispatch = createMockDispatch();
- const result = await applyExtensionCartUpdate( {
+ await applyExtensionCartUpdate( {
namespace: 'test',
data: {},
overwriteDirtyCustomerData: [
@@ -680,14 +670,13 @@ describe( 'applyExtensionCartUpdate', () => {
const received = dispatch.receiveCart.mock.calls[ 0 ][ 0 ];
expect( received ).not.toHaveProperty( 'shipping_address' );
expect( received ).not.toHaveProperty( 'billing_address' );
- expect( result ).toBe( mockResponse );
} );
it( 'should treat non-boolean address fields as false', async () => {
mockGetIsCustomerDataDirty.mockReturnValue( true );
const dispatch = createMockDispatch();
- const result = await applyExtensionCartUpdate( {
+ await applyExtensionCartUpdate( {
namespace: 'test',
data: {},
overwriteDirtyCustomerData: {
@@ -699,14 +688,13 @@ describe( 'applyExtensionCartUpdate', () => {
const received = dispatch.receiveCart.mock.calls[ 0 ][ 0 ];
expect( received ).not.toHaveProperty( 'shipping_address' );
expect( received ).not.toHaveProperty( 'billing_address' );
- expect( result ).toBe( mockResponse );
} );
it( 'should default missing address fields to false', async () => {
mockGetIsCustomerDataDirty.mockReturnValue( true );
const dispatch = createMockDispatch();
- const result = await applyExtensionCartUpdate( {
+ await applyExtensionCartUpdate( {
namespace: 'test',
data: {},
overwriteDirtyCustomerData: {},
@@ -715,25 +703,5 @@ describe( 'applyExtensionCartUpdate', () => {
const received = dispatch.receiveCart.mock.calls[ 0 ][ 0 ];
expect( received ).not.toHaveProperty( 'shipping_address' );
expect( received ).not.toHaveProperty( 'billing_address' );
- expect( result ).toBe( mockResponse );
- } );
-
- it( 'should dispatch and reject the same API error', async () => {
- const dispatch = createMockDispatch();
- const error = {
- code: 'test_error',
- message: 'This is an error with cart context.',
- data: { status: 400, context: 'wc/cart' },
- };
- mockApiFetchWithHeaders.mockRejectedValueOnce( error );
-
- await expect(
- applyExtensionCartUpdate( {
- namespace: 'test',
- data: {},
- } )( { dispatch } as never )
- ).rejects.toBe( error );
-
- expect( dispatch.receiveError ).toHaveBeenCalledWith( error );
} );
} );
diff --git a/plugins/woocommerce/client/blocks/packages/public-api/block-data/utils/test/process-error-response.ts b/plugins/woocommerce/client/blocks/packages/public-api/block-data/utils/test/process-error-response.ts
index 994276d0df1..d153fc25e84 100644
--- a/plugins/woocommerce/client/blocks/packages/public-api/block-data/utils/test/process-error-response.ts
+++ b/plugins/woocommerce/client/blocks/packages/public-api/block-data/utils/test/process-error-response.ts
@@ -49,14 +49,6 @@ const errorResponse: ApiErrorResponse = {
},
};
-const errorResponseWithoutContext: ApiErrorResponse = {
- code: 'woocommerce_rest_cart_extensions_error',
- message: 'There is no such namespace registered: test-plugin.',
- data: {
- status: 400,
- },
-};
-
describe( 'getNoticeContextFromErrorResponse', () => {
it( 'should generate notice contexts and ids for the correct fields/errors', () => {
const result = getNoticeContextFromErrorResponse( errorResponse );
@@ -81,24 +73,9 @@ describe( 'getNoticeContextFromErrorResponse', () => {
);
expect( result[ 0 ].context ).toEqual( 'test_context' );
} );
-
- it( 'should use the cart context for a non-parameter error without a server context', () => {
- expect(
- getNoticeContextFromErrorResponse( errorResponseWithoutContext )
- ).toEqual( [
- {
- id: 'woocommerce_rest_cart_extensions_error',
- context: 'wc/cart',
- },
- ] );
- } );
} );
describe( 'processErrorResponse', () => {
- beforeEach( () => {
- jest.clearAllMocks();
- } );
-
it( 'should dismiss old notices and create new ones', () => {
processErrorResponse( errorResponse );
expect( createNotice ).toHaveBeenCalledTimes( 2 );
@@ -120,18 +97,4 @@ describe( 'processErrorResponse', () => {
}
);
} );
-
- it( 'should create a non-parameter error notice in the cart context by default', () => {
- processErrorResponse( errorResponseWithoutContext );
-
- expect( createNotice ).toHaveBeenCalledTimes( 1 );
- expect( createNotice ).toHaveBeenCalledWith(
- 'error',
- 'There is no such namespace registered: test-plugin.',
- {
- id: 'woocommerce_rest_cart_extensions_error',
- context: 'wc/cart',
- }
- );
- } );
} );
diff --git a/plugins/woocommerce/client/blocks/packages/public-api/blocks-checkout/utils/test/extension-cart-update.ts b/plugins/woocommerce/client/blocks/packages/public-api/blocks-checkout/utils/test/extension-cart-update.ts
deleted file mode 100644
index 3c85acb8609..00000000000
--- a/plugins/woocommerce/client/blocks/packages/public-api/blocks-checkout/utils/test/extension-cart-update.ts
+++ /dev/null
@@ -1,121 +0,0 @@
-/**
- * External dependencies
- */
-import { dispatch } from '@wordpress/data';
-import { processErrorResponse } from '@woocommerce/block-data';
-import type { CartResponse, ExtensionCartUpdateArgs } from '@woocommerce/types';
-
-/**
- * Internal dependencies
- */
-import { extensionCartUpdate } from '../extension-cart-update';
-import { STORE_KEY } from '../../../block-data/cart/constants';
-
-jest.mock( '@wordpress/data', () => ( {
- dispatch: jest.fn(),
-} ) );
-
-jest.mock( '@woocommerce/block-data', () => ( {
- processErrorResponse: jest.fn(),
-} ) );
-
-const mockDispatch = dispatch as jest.MockedFunction< typeof dispatch >;
-const mockProcessErrorResponse = processErrorResponse as jest.MockedFunction<
- typeof processErrorResponse
->;
-const mockApplyExtensionCartUpdate = jest.fn();
-
-describe( 'extensionCartUpdate', () => {
- beforeEach( () => {
- jest.clearAllMocks();
- mockDispatch.mockReturnValue( {
- applyExtensionCartUpdate: mockApplyExtensionCartUpdate,
- } as never );
- } );
-
- it.each< [ string, ExtensionCartUpdateArgs ] >( [
- [
- 'with overwrite omitted',
- { namespace: 'test-extension', data: { value: 'omitted' } },
- ],
- [
- 'with overwrite disabled',
- {
- namespace: 'test-extension',
- data: { value: 'false' },
- overwriteDirtyCustomerData: false,
- },
- ],
- [
- 'with overwrite enabled',
- {
- namespace: 'test-extension',
- data: { value: 'true' },
- overwriteDirtyCustomerData: true,
- },
- ],
- [
- 'with shipping-address overwrite enabled',
- {
- namespace: 'test-extension',
- data: { value: 'shipping' },
- overwriteDirtyCustomerData: { shipping_address: true },
- },
- ],
- [
- 'with billing-address overwrite enabled',
- {
- namespace: 'test-extension',
- data: { value: 'billing' },
- overwriteDirtyCustomerData: { billing_address: true },
- },
- ],
- ] )(
- 'forwards arguments and fulfills with the same cart response %s',
- async ( _, args ) => {
- const response = { items: [] } as CartResponse;
- mockApplyExtensionCartUpdate.mockResolvedValueOnce( response );
-
- const result = await extensionCartUpdate( args );
-
- expect( mockDispatch ).toHaveBeenCalledWith( STORE_KEY );
- expect( mockApplyExtensionCartUpdate ).toHaveBeenCalledWith( args );
- expect( result ).toBe( response );
- }
- );
-
- it( 'rejects the same non-special error without creating a notice', async () => {
- const error = {
- code: 'test_error',
- message: 'This is an extension error.',
- };
- mockApplyExtensionCartUpdate.mockRejectedValueOnce( error );
-
- await expect(
- extensionCartUpdate( {
- namespace: 'test-extension',
- data: {},
- } )
- ).rejects.toBe( error );
-
- expect( mockProcessErrorResponse ).not.toHaveBeenCalled();
- } );
-
- it( 'processes a special cart-extension error once and rejects that same error', async () => {
- const error = {
- code: 'woocommerce_rest_cart_extensions_error',
- message: 'The cart extension could not be processed.',
- };
- mockApplyExtensionCartUpdate.mockRejectedValueOnce( error );
-
- await expect(
- extensionCartUpdate( {
- namespace: 'test-extension',
- data: {},
- } )
- ).rejects.toBe( error );
-
- expect( mockProcessErrorResponse ).toHaveBeenCalledTimes( 1 );
- expect( mockProcessErrorResponse ).toHaveBeenCalledWith( error );
- } );
-} );
diff --git a/plugins/woocommerce/tests/e2e/tests/blocks/cart/cart-checkout-block-extension-callbacks.shopper.block_theme.spec.ts b/plugins/woocommerce/tests/e2e/tests/blocks/cart/cart-checkout-block-extension-callbacks.shopper.block_theme.spec.ts
index 95078213a1b..37cabfe774a 100644
--- a/plugins/woocommerce/tests/e2e/tests/blocks/cart/cart-checkout-block-extension-callbacks.shopper.block_theme.spec.ts
+++ b/plugins/woocommerce/tests/e2e/tests/blocks/cart/cart-checkout-block-extension-callbacks.shopper.block_theme.spec.ts
@@ -1,14 +1,50 @@
/**
* External dependencies
*/
-import { expect, test } from '@woocommerce/e2e-utils';
+import { expect, test as base } from '@woocommerce/e2e-utils';
/**
* Internal dependencies
*/
+import { CheckoutPage } from '../checkout/checkout.page';
import { REGULAR_PRICED_PRODUCT_NAME } from '../checkout/constants';
+const test = base.extend< { checkoutPageObject: CheckoutPage } >( {
+ checkoutPageObject: async ( { page }, use ) => {
+ const pageObject = new CheckoutPage( {
+ page,
+ } );
+ await use( pageObject );
+ },
+} );
+
test.describe( 'Shopper → Cart Extension Callbacks', () => {
+ test( 'Custom error code creates exception', async ( {
+ frontendUtils,
+ requestUtils,
+ page,
+ } ) => {
+ await requestUtils.activatePlugin(
+ 'woocommerce-blocks-test-cart-extensions'
+ );
+
+ await frontendUtils.goToShop();
+ await frontendUtils.addToCart( REGULAR_PRICED_PRODUCT_NAME );
+ await frontendUtils.goToCart();
+
+ await expect(
+ page.evaluate( () =>
+ window.wc.blocksCheckout
+ .extensionCartUpdate( {
+ namespace: 'cart-extensions-test-helper',
+ } )
+ .catch( ( error ) => {
+ throw new Error( error.message );
+ } )
+ )
+ ).rejects.toThrow( 'This is an error with cart context.' );
+ } );
+
test( 'Error code `woocommerce_rest_cart_extensions_error` creates notice', async ( {
frontendUtils,
requestUtils,
@@ -34,4 +70,27 @@ test.describe( 'Shopper → Cart Extension Callbacks', () => {
.getByText( 'This is an error with cart context.' )
).toBeVisible();
} );
+
+ test( 'Invalid callback namespace creates notice', async ( {
+ frontendUtils,
+ page,
+ } ) => {
+ await frontendUtils.goToShop();
+ await frontendUtils.addToCart( REGULAR_PRICED_PRODUCT_NAME );
+ await frontendUtils.goToCart();
+
+ await page.evaluate( () => {
+ window.wc.blocksCheckout.extensionCartUpdate( {
+ namespace: 'invalid-namespace',
+ } );
+ } );
+
+ await expect(
+ page
+ .locator( '.wc-block-components-notice-banner__content' )
+ .getByText(
+ 'There is no such namespace registered: invalid-namespace.'
+ )
+ ).toBeVisible();
+ } );
} );
diff --git a/plugins/woocommerce/tests/e2e/tests/blocks/checkout/checkout-block-extensibility.shopper.block_theme.spec.ts b/plugins/woocommerce/tests/e2e/tests/blocks/checkout/checkout-block-extensibility.shopper.block_theme.spec.ts
index fe772da10ab..e7a05fda2ba 100644
--- a/plugins/woocommerce/tests/e2e/tests/blocks/checkout/checkout-block-extensibility.shopper.block_theme.spec.ts
+++ b/plugins/woocommerce/tests/e2e/tests/blocks/checkout/checkout-block-extensibility.shopper.block_theme.spec.ts
@@ -40,13 +40,51 @@ test.describe( 'Shopper → Extensibility', () => {
await frontendUtils.addToCart( REGULAR_PRICED_PRODUCT_NAME );
await frontendUtils.goToCheckout();
} );
-
test.describe( 'extensionCartUpdate', () => {
- test( 'Cart data can be modified by extensions', async ( {
+ test( 'Response is not undefined in any code path', async ( {
checkoutPageObject,
} ) => {
- const { page } = checkoutPageObject;
+ // With no additional args.
+ let response = await checkoutPageObject.page.evaluate(
+ "wc.blocksCheckout.extensionCartUpdate( { namespace: 'woocommerce-blocks-test-extension-cart-update' } ).then( ( response ) => response );"
+ );
+ let resolvedResponse = await Promise.resolve( response );
+ expect( resolvedResponse ).not.toBeUndefined();
+ expect( resolvedResponse ).toHaveProperty( 'billing_address' );
+
+ // With overwriteDirtyCustomerData true.
+ response = await checkoutPageObject.page.evaluate(
+ "wc.blocksCheckout.extensionCartUpdate( { namespace: 'woocommerce-blocks-test-extension-cart-update', overwriteDirtyCustomerData: true } ).then( ( response ) => response );"
+ );
+ resolvedResponse = await Promise.resolve( response );
+ expect( resolvedResponse ).not.toBeUndefined();
+ expect( resolvedResponse ).toHaveProperty( 'billing_address' );
+
+ // With overwriteDirtyCustomerData false.
+ response = await checkoutPageObject.page.evaluate(
+ "wc.blocksCheckout.extensionCartUpdate( { namespace: 'woocommerce-blocks-test-extension-cart-update', overwriteDirtyCustomerData: false } ).then( ( response ) => response );"
+ );
+ resolvedResponse = await Promise.resolve( response );
+ expect( resolvedResponse ).not.toBeUndefined();
+ expect( resolvedResponse ).toHaveProperty( 'billing_address' );
+ // With a dirty customer object.
+ await checkoutPageObject.page
+ .getByLabel( 'Country/Region' )
+ .selectOption( 'United Kingdom (UK)' );
+ await expect(
+ checkoutPageObject.page.getByLabel( 'Country/Region' )
+ ).toHaveValue( 'GB' );
+ response = await checkoutPageObject.page.evaluate(
+ "wc.blocksCheckout.extensionCartUpdate( { namespace: 'woocommerce-blocks-test-extension-cart-update' } ).then( ( response ) => response );"
+ );
+ resolvedResponse = await Promise.resolve( response );
+ expect( resolvedResponse ).not.toBeUndefined();
+ expect( resolvedResponse ).toHaveProperty( 'billing_address' );
+ } );
+ test( 'Unpushed data is/is not overwritten depending on arg', async ( {
+ checkoutPageObject,
+ } ) => {
// Fill in the address, then wait until it has reached the server. The dirty flag is
// not enough on its own: it is cleared by whichever push finishes first, which can
// be an earlier one that did not carry the address.
@@ -54,7 +92,7 @@ test.describe( 'Shopper → Extensibility', () => {
await expect
.poll(
async () =>
- page.evaluate( async () => {
+ checkoutPageObject.page.evaluate( async () => {
const response = await fetch(
'/wp-json/wc/store/v1/cart'
);
@@ -72,49 +110,54 @@ test.describe( 'Shopper → Extensibility', () => {
.toBe( '90210' );
// A postcode that fails validation is never pushed, so it only exists in the browser.
- // A country change is not usable here: picking one pushes straight away so shipping
- // can be recalculated, which would leave nothing unpushed to overwrite.
- const postcode = page.locator( '#shipping-postcode' );
+ const postcode =
+ checkoutPageObject.page.locator( '#shipping-postcode' );
await postcode.fill( 'ABCDEF' );
await postcode.blur();
- await page.waitForFunction( () => {
- return (
+ await checkoutPageObject.page.waitForFunction(
+ () =>
window.localStorage.getItem(
'WOOCOMMERCE_CHECKOUT_IS_CUSTOMER_DATA_DIRTY'
) === 'true'
- );
- } );
+ );
// Without the arg, the unpushed postcode is kept.
- await page.evaluate( () =>
- window.wc.blocksCheckout.extensionCartUpdate( {
- namespace: 'woocommerce-blocks-test-extension-cart-update',
- } )
+ await checkoutPageObject.page.evaluate(
+ "wc.blocksCheckout.extensionCartUpdate( { namespace: 'woocommerce-blocks-test-extension-cart-update' } )"
);
await expect( postcode ).toHaveValue( 'ABCDEF' );
// With overwriteDirtyCustomerData, the address from the server replaces it.
- const overwriteResponse = await page.evaluate( () =>
- window.wc.blocksCheckout.extensionCartUpdate( {
- namespace: 'woocommerce-blocks-test-extension-cart-update',
- overwriteDirtyCustomerData: true,
- } )
- );
- expect( overwriteResponse.shipping_address.postcode ).toBe(
- '90210'
+ await checkoutPageObject.page.evaluate(
+ "wc.blocksCheckout.extensionCartUpdate( { namespace: 'woocommerce-blocks-test-extension-cart-update', overwriteDirtyCustomerData: true } )"
);
await expect( postcode ).toHaveValue( '90210' );
- await page.evaluate( () =>
- window.wc.blocksCheckout.extensionCartUpdate( {
- namespace: 'woocommerce-blocks-test-extension-cart-update',
- data: { 'test-name-change': true },
- overwriteDirtyCustomerData: true,
- } )
+ await checkoutPageObject.page.evaluate(
+ "wc.blocksCheckout.extensionCartUpdate( { namespace: 'woocommerce-blocks-test-extension-cart-update', overwriteDirtyCustomerData: true } )"
);
- await expect( page.getByLabel( 'First name' ) ).toHaveValue(
- 'Mr. Test'
+ await expect(
+ checkoutPageObject.page.getByLabel( 'Country/Region' )
+ ).toHaveValue( 'US' );
+ await expect( postcode ).toHaveValue( '90210' );
+ } );
+ test( 'Cart data can be modified by extensions', async ( {
+ checkoutPageObject,
+ } ) => {
+ await checkoutPageObject.fillInCheckoutWithTestData();
+ await checkoutPageObject.page.waitForFunction( () => {
+ return (
+ window.localStorage.getItem(
+ 'WOOCOMMERCE_CHECKOUT_IS_CUSTOMER_DATA_DIRTY'
+ ) === 'false'
+ );
+ } );
+ await checkoutPageObject.page.evaluate(
+ "wc.blocksCheckout.extensionCartUpdate( { namespace: 'woocommerce-blocks-test-extension-cart-update', data: { 'test-name-change': true } } )"
);
+ await expect(
+ checkoutPageObject.page.getByLabel( 'First name' )
+ ).toHaveValue( 'Mr. Test' );
} );
} );
} );
diff --git a/plugins/woocommerce/tests/php/src/Blocks/StoreApi/Routes/CartExtensions.php b/plugins/woocommerce/tests/php/src/Blocks/StoreApi/Routes/CartExtensions.php
index 0eacde6b443..79301a7aa0c 100644
--- a/plugins/woocommerce/tests/php/src/Blocks/StoreApi/Routes/CartExtensions.php
+++ b/plugins/woocommerce/tests/php/src/Blocks/StoreApi/Routes/CartExtensions.php
@@ -9,9 +9,6 @@ use Automattic\WooCommerce\Enums\OrderItemType;
use Automattic\WooCommerce\Enums\OrderStatus;
use Automattic\WooCommerce\Tests\Blocks\StoreApi\Routes\ControllerTestCase;
use Automattic\WooCommerce\Tests\Blocks\Helpers\FixtureData;
-use Automattic\WooCommerce\StoreApi\Exceptions\RouteException;
-use Automattic\WooCommerce\StoreApi\Schemas\ExtendSchema;
-use Automattic\WooCommerce\StoreApi\StoreApi;
/**
* Cart Controller Tests.
@@ -51,11 +48,10 @@ class CartExtensions extends ControllerTestCase {
)
);
}
-
/**
- * @testdox Invalid namespace errors expose the mapped Store API response without a context override.
+ * Test getting cart with invalid namespace.
*/
- public function test_invalid_namespace(): void {
+ public function test_invalid_namespace() {
$request = new \WP_REST_Request( 'POST', '/wc/store/v1/cart/extensions' );
$request->set_header( 'Nonce', wp_create_nonce( 'wc_store_api' ) );
$request->set_body_params(
@@ -63,61 +59,10 @@ class CartExtensions extends ControllerTestCase {
'namespace' => 'test-plugin',
)
);
- $response = rest_get_server()->dispatch( $request );
- $data = $response->get_data();
-
- $this->assertSame( 400, $response->get_status(), 'An invalid extension namespace should return HTTP 400.' );
- $this->assertSame( 'woocommerce_rest_cart_extensions_error', $data['code'], 'The response should use the mapped cart-extension error code.' );
- $this->assertSame( 'There is no such namespace registered: test-plugin.', $data['message'], 'The response should identify the missing namespace exactly.' );
- $this->assertSame( 400, $data['data']['status'], 'The response data should preserve the HTTP status.' );
- $this->assertArrayNotHasKey( 'context', $data['data'], 'The invalid-namespace response should leave notice context selection to the client.' );
- }
-
- /**
- * @testdox Extension callback RouteException data passes through the public route unchanged.
- */
- public function test_callback_route_exception_passes_through(): void {
- $extend = StoreApi::container()->get( ExtendSchema::class );
- $original_callback = $extend->get_update_callback( 'valid-test-plugin' );
-
- woocommerce_store_api_register_update_callback(
- array(
- 'namespace' => 'valid-test-plugin',
- 'callback' => function () {
- throw new RouteException(
- 'test_error',
- 'This is an error with cart context.',
- 400,
- array( 'context' => 'wc/cart' )
- );
- },
- )
+ $this->assertAPIResponse(
+ $request,
+ 400
);
-
- try {
- $request = new \WP_REST_Request( 'POST', '/wc/store/v1/cart/extensions' );
- $request->set_header( 'Nonce', wp_create_nonce( 'wc_store_api' ) );
- $request->set_body_params(
- array(
- 'namespace' => 'valid-test-plugin',
- )
- );
- $response = rest_get_server()->dispatch( $request );
- $data = $response->get_data();
-
- $this->assertSame( 400, $response->get_status(), 'The callback RouteException should preserve its HTTP status.' );
- $this->assertSame( 'test_error', $data['code'], 'The callback RouteException should preserve its error code.' );
- $this->assertSame( 'This is an error with cart context.', $data['message'], 'The callback RouteException should preserve its message.' );
- $this->assertSame( 400, $data['data']['status'], 'The callback RouteException response data should preserve its status.' );
- $this->assertSame( 'wc/cart', $data['data']['context'], 'The callback RouteException should preserve its notice context.' );
- } finally {
- woocommerce_store_api_register_update_callback(
- array(
- 'namespace' => 'valid-test-plugin',
- 'callback' => $original_callback,
- )
- );
- }
}
/**