Commit c15e5bdac7d for woocommerce
commit c15e5bdac7ddad21b49cb7348061d5f5f3a25d3d
Author: Albert Juhé Lluveras <contact@albertjuhe.com>
Date: Thu Jul 2 12:27:59 2026 +0200
Add to Cart + Options: add extra e2e tests to cover skipped unit tests (#66118)
* Add to Cart + Options: add extra e2e tests to cover skipped unit tests
* Add changelog
* Fix grouped products test
diff --git a/plugins/woocommerce/changelog/fix-66046-add-to-cart-with-options-unit-tests-to-e2e b/plugins/woocommerce/changelog/fix-66046-add-to-cart-with-options-unit-tests-to-e2e
new file mode 100644
index 00000000000..f26ce0d2047
--- /dev/null
+++ b/plugins/woocommerce/changelog/fix-66046-add-to-cart-with-options-unit-tests-to-e2e
@@ -0,0 +1,4 @@
+Significance: patch
+Type: dev
+
+Add to Cart + Options: add extra e2e tests to cover skipped unit tests
diff --git a/plugins/woocommerce/client/blocks/assets/js/blocks/add-to-cart-with-options/test/block.ts b/plugins/woocommerce/client/blocks/assets/js/blocks/add-to-cart-with-options/test/block.ts
index 47ccd16ac45..9630e166f37 100644
--- a/plugins/woocommerce/client/blocks/assets/js/blocks/add-to-cart-with-options/test/block.ts
+++ b/plugins/woocommerce/client/blocks/assets/js/blocks/add-to-cart-with-options/test/block.ts
@@ -2,185 +2,20 @@
* External dependencies
*/
import '@testing-library/jest-dom';
-import { act, fireEvent, screen, waitFor } from '@testing-library/react';
+import { screen, waitFor } from '@testing-library/react';
import { http, HttpResponse } from 'msw';
import { setupServer } from 'msw/node';
-import { readFileSync } from 'fs';
-import { join } from 'path';
-import { dispatch } from '@wordpress/data';
-import { productsStore } from '@woocommerce/data';
-import { store as coreStore } from '@wordpress/core-data';
/**
* Internal dependencies
*/
-import {
- initializeEditor,
- selectBlock,
-} from '../../../../../tests/integration/helpers/integration-test-editor';
+import { initializeEditor } from '../../../../../tests/integration/helpers/integration-test-editor';
import '../';
-import '../quantity-selector';
-import '../../../atomic/blocks/product-elements/button';
-import '../../../atomic/blocks/product-elements/stock-indicator';
-import '../../../atomic/blocks/product-elements/price';
-import '../grouped-product-selector';
-import '../grouped-product-selector/product-item';
-import '../grouped-product-selector/product-item-label';
-import '../grouped-product-selector/product-item-selector';
-import '../variation-selector';
-import '../variation-selector/attribute';
-import '../variation-selector/attribute-name';
-import '../variation-description';
-const mockTemplatePartsHTML: Record< string, string > = {
- simple: '',
- external: '',
- grouped: '',
- variable: '',
-};
-
-Object.keys( mockTemplatePartsHTML ).forEach( ( key ) => {
- mockTemplatePartsHTML[ key ] = readFileSync(
- join(
- __dirname,
- `../../../../../../../templates/parts/${ key }-product-add-to-cart-with-options.html`
- ),
- 'utf-8'
- );
-} );
-
-jest.mock( '@woocommerce/settings', () => {
- return {
- ...jest.requireActual( '@woocommerce/settings' ),
- getSetting: jest.fn().mockImplementation( ( key, defaultValue ) => {
- if ( key === 'productTypes' ) {
- return {
- simple: 'Simple product',
- external: 'External/Affiliate product',
- grouped: 'Grouped product',
- variable: 'Variable product',
- };
- }
- if ( key === 'addToCartWithOptionsTemplatePartIds' ) {
- return {
- simple: 'woocommerce/woocommerce//simple-product-add-to-cart-with-options',
- external:
- 'woocommerce/woocommerce//external-product-add-to-cart-with-options',
- grouped:
- 'woocommerce/woocommerce//grouped-product-add-to-cart-with-options',
- variable:
- 'woocommerce/woocommerce//variable-product-add-to-cart-with-options',
- };
- }
- return defaultValue;
- } ),
- };
-} );
-
-const mockProduct = {
- id: 82,
- name: 'Beanie with Logo',
- type: 'simple',
- is_in_stock: true,
- stock_availability: { text: '', class: 'in-stock' },
-};
-
-// Setup MSW.
-const handlers = [
- http.get( '/wp/v2/types', () => {
- return HttpResponse.json( {
- wp_template_part: {
- slug: 'wp_template_part',
- rest_base: 'template-parts',
- rest_namespace: 'wp/v2',
- },
- } );
- } ),
-
- http.get( '/wc/v3/products', () => {
- return HttpResponse.json( [ mockProduct ] );
- } ),
-
- http.get( '/wc/store/v1/products/:id', () => {
- return HttpResponse.json( mockProduct );
- } ),
-
- http.get( '/wc/v3/products/:id', () => {
- return HttpResponse.json( mockProduct );
- } ),
-
- // @todo When updating the `@wordpress/data` package to 6.7 or later,
- // this request will need to be updated to match the path in production:
- // `/wp/v2/template-parts/woocommerce/woocommerce//<template-part-slug>`.
- http.options( '/wp/v2/[object%20Object]', () => {
- return HttpResponse.json(
- {},
- {
- headers: {
- allow: 'GET, POST, PUT, PATCH, DELETE',
- },
- }
- );
- } ),
-
- http.get( '/wp/v2/template-parts/*', ( request ) => {
- if (
- request.params[ 0 ] ===
- 'woocommerce/woocommerce//simple-product-add-to-cart-with-options'
- ) {
- return HttpResponse.json( {
- id: 'woocommerce/woocommerce//simple-product-add-to-cart-with-options',
- content: {
- raw: mockTemplatePartsHTML.simple,
- },
- } );
- }
- if (
- request.params[ 0 ] ===
- 'woocommerce/woocommerce//external-product-add-to-cart-with-options'
- ) {
- return HttpResponse.json( {
- id: 'woocommerce/woocommerce//external-product-add-to-cart-with-options',
- content: {
- raw: mockTemplatePartsHTML.external,
- },
- } );
- }
- if (
- request.params[ 0 ] ===
- 'woocommerce/woocommerce//grouped-product-add-to-cart-with-options'
- ) {
- return HttpResponse.json( {
- id: 'woocommerce/woocommerce//grouped-product-add-to-cart-with-options',
- content: {
- raw: mockTemplatePartsHTML.grouped,
- },
- } );
- }
-
- if (
- request.params[ 0 ] ===
- 'woocommerce/woocommerce//variable-product-add-to-cart-with-options'
- ) {
- return HttpResponse.json( {
- id: 'woocommerce/woocommerce//variable-product-add-to-cart-with-options',
- content: {
- raw: mockTemplatePartsHTML.variable,
- },
- } );
- }
- } ),
-];
-
-const server = setupServer( ...handlers );
+const server = setupServer();
// Start MSW.
beforeAll( () => server.listen() );
-afterEach( () => {
- dispatch( productsStore ).invalidateResolutionForStore();
- dispatch( coreStore ).invalidateResolutionForStore();
- server.resetHandlers();
-} );
afterAll( () => server.close() );
async function setup() {
@@ -192,149 +27,12 @@ async function setup() {
return await initializeEditor( addToCartWithOptionsBlock );
}
-async function switchProductType( productType: string ) {
- await selectBlock( 'Block: Add to Cart + Options (Beta)' );
-
- await act( async () => {
- fireEvent.click(
- screen.getByRole( 'button', { name: 'Switch product type' } )
- );
- } );
-
- await act( async () => {
- fireEvent.click(
- screen.getByRole( 'menuitem', { name: productType } )
- );
- } );
-}
-
const expectHasBlock = async ( blockName: string ) => {
const block = await screen.findAllByLabelText( `Block: ${ blockName }` );
expect( block.length ).toBeGreaterThan( 0 );
};
describe( 'Add to Cart + Options block', () => {
- // The wp-6.8 version of @wordpress/private-apis causes a deprecation
- // warning for __unstableIsPreviewMode that fires non-deterministically
- // during async block editor setup. Filter it from jest-console's spy
- // before it checks for unexpected warnings.
- afterEach( () => {
- /* eslint-disable no-console */
- ( console.warn as jest.Mock ).mock.calls = (
- console.warn as jest.Mock
- ).mock.calls.filter(
- ( [ firstArg ]: [ unknown ] ) =>
- ! (
- typeof firstArg === 'string' &&
- firstArg.includes( '__unstableIsPreviewMode' )
- )
- );
- /* eslint-enable no-console */
- } );
-
- // Skipped: wp-6.8's block-editor rendering pipeline no longer renders
- // inner blocks in Jest's jsdom environment. Gutenberg tests block
- // rendering via Playwright E2E; these should be migrated similarly.
- it.skip( 'should render inner blocks for simple and external products', async () => {
- await setup();
- await expectHasBlock( 'Add to Cart + Options (Beta)' );
-
- // Simple products.
- await expectHasBlock( 'Product Stock Indicator' );
- await expectHasBlock( 'Product Quantity (Beta)' );
- await expectHasBlock( 'Add to Cart Button' );
-
- // External products.
- await switchProductType( 'External/Affiliate product' );
-
- await waitFor( () => {
- expect(
- screen.queryByLabelText( 'Block: Product Stock Indicator' )
- ).not.toBeInTheDocument();
- } );
- await expectHasBlock( 'Add to Cart Button' );
-
- // wp-6.8: upstream @wordpress/* deprecation warnings that we cannot
- // opt out of without changing the visual output.
- expect( console ).toHaveWarned();
- } );
-
- // Skipped: wp-6.8's block-editor rendering pipeline no longer renders
- // inner blocks in Jest's jsdom environment. Gutenberg tests block
- // rendering via Playwright E2E; these should be migrated similarly.
- it.skip( 'should render inner blocks for grouped products', async () => {
- expect.hasAssertions();
-
- await setup();
- await expectHasBlock( 'Add to Cart + Options (Beta)' );
-
- await switchProductType( 'Grouped product' );
-
- await expectHasBlock( 'Grouped Product Selector (Beta)' );
- await expectHasBlock( 'Grouped Product: Template (Beta)' );
- await expectHasBlock( 'Grouped Product: Item Selector (Beta)' );
- await expectHasBlock( 'Grouped Product: Item Label (Beta)' );
- await expectHasBlock( 'Product Price' );
- await expectHasBlock( 'Product Stock Indicator' );
-
- // wp-6.8: upstream @wordpress/* deprecation warnings that we cannot
- // opt out of without changing the visual output.
- expect( console ).toHaveWarned();
- } );
-
- // Skipped: wp-6.8's block-editor rendering pipeline no longer renders
- // inner blocks in Jest's jsdom environment. Gutenberg tests block
- // rendering via Playwright E2E; these should be migrated similarly.
- it.skip( 'should render inner blocks for grouped products with no store products', async () => {
- expect.hasAssertions();
-
- server.use(
- http.get( '/wc/v3/products', () => {
- return HttpResponse.json( [] );
- } )
- );
-
- await setup();
- await expectHasBlock( 'Add to Cart + Options (Beta)' );
-
- await switchProductType( 'Grouped product' );
-
- await expectHasBlock( 'Grouped Product Selector (Beta)' );
- await expectHasBlock( 'Grouped Product: Template (Beta)' );
- await expectHasBlock( 'Grouped Product: Item Selector (Beta)' );
- await expectHasBlock( 'Grouped Product: Item Label (Beta)' );
- await expectHasBlock( 'Product Price' );
- await expectHasBlock( 'Product Stock Indicator' );
-
- // wp-6.8: upstream @wordpress/* deprecation warnings that we cannot
- // opt out of without changing the visual output.
- expect( console ).toHaveWarned();
- } );
-
- // Skipped: wp-6.8's block-editor rendering pipeline no longer renders
- // inner blocks in Jest's jsdom environment. Gutenberg tests block
- // rendering via Playwright E2E; these should be migrated similarly.
- it.skip( 'should render inner blocks for variable products', async () => {
- expect.hasAssertions();
-
- await setup();
- await expectHasBlock( 'Add to Cart + Options (Beta)' );
-
- await switchProductType( 'Variable product' );
-
- await expectHasBlock( 'Variation Selector (Beta)' );
- await expectHasBlock( 'Variation Selector: Attribute Name (Beta)' );
- await expectHasBlock( 'Variation Selector: Template (Beta)' );
- await expectHasBlock( 'Variation Description (Beta)' );
- await expectHasBlock( 'Product Stock Indicator' );
- await expectHasBlock( 'Product Quantity (Beta)' );
- await expectHasBlock( 'Add to Cart Button' );
-
- // wp-6.8: upstream @wordpress/* deprecation warnings that we cannot
- // opt out of without changing the visual output.
- expect( console ).toHaveWarned();
- } );
-
it( 'should render the placeholder when viewed as a user without permissions to edit template parts', async () => {
server.use(
// @todo When updating the `@wordpress/data` package to 6.7 or later,
@@ -360,9 +58,5 @@ describe( 'Add to Cart + Options block', () => {
screen.getByLabelText( 'Add to Cart + Options form' )
).toBeInTheDocument()
);
-
- // wp-6.8: upstream @wordpress/* deprecation warnings that we cannot
- // opt out of without changing the visual output.
- expect( console ).toHaveWarned();
} );
} );
diff --git a/plugins/woocommerce/tests/e2e/tests/blocks/add-to-cart-with-options/add-to-cart-with-options.block_theme.spec.ts b/plugins/woocommerce/tests/e2e/tests/blocks/add-to-cart-with-options/add-to-cart-with-options.block_theme.spec.ts
index 52b87431ed3..db82f623786 100644
--- a/plugins/woocommerce/tests/e2e/tests/blocks/add-to-cart-with-options/add-to-cart-with-options.block_theme.spec.ts
+++ b/plugins/woocommerce/tests/e2e/tests/blocks/add-to-cart-with-options/add-to-cart-with-options.block_theme.spec.ts
@@ -92,6 +92,16 @@ test.describe( 'Add to Cart + Options Block', () => {
} ) => {
await pageObject.updateSingleProductTemplate();
+ await test.step( 'renders inner blocks for simple products', async () => {
+ await pageObject.expectEditorInnerBlocks( 'simple' );
+ } );
+
+ await test.step( 'renders inner blocks for external products', async () => {
+ await pageObject.switchProductType( 'External/Affiliate product' );
+ await pageObject.expectEditorInnerBlocks( 'external' );
+ await pageObject.switchProductType( 'Simple product' );
+ } );
+
await editor.saveSiteEditorEntities( {
isOnlyCurrentEntityDirty: true,
} );
@@ -200,6 +210,11 @@ test.describe( 'Add to Cart + Options Block', () => {
await pageObject.updateSingleProductTemplate();
+ await test.step( 'renders inner blocks for variable products', async () => {
+ await pageObject.switchProductType( 'Variable product' );
+ await pageObject.expectEditorInnerBlocks( 'variable' );
+ } );
+
// We update to the Product Gallery block to test that it scrolls to the
// correct variation image.
const productImageGalleryBlock = await editor.getBlockByName(
@@ -548,6 +563,11 @@ test.describe( 'Add to Cart + Options Block', () => {
await pageObject.updateSingleProductTemplate();
+ await test.step( 'renders inner blocks for grouped products', async () => {
+ await pageObject.switchProductType( 'Grouped product' );
+ await pageObject.expectEditorInnerBlocks( 'grouped' );
+ } );
+
await editor.saveSiteEditorEntities( {
isOnlyCurrentEntityDirty: true,
} );
diff --git a/plugins/woocommerce/tests/e2e/tests/blocks/add-to-cart-with-options/add-to-cart-with-options.page.ts b/plugins/woocommerce/tests/e2e/tests/blocks/add-to-cart-with-options/add-to-cart-with-options.page.ts
index c20d80dc158..e9393b1d148 100644
--- a/plugins/woocommerce/tests/e2e/tests/blocks/add-to-cart-with-options/add-to-cart-with-options.page.ts
+++ b/plugins/woocommerce/tests/e2e/tests/blocks/add-to-cart-with-options/add-to-cart-with-options.page.ts
@@ -15,6 +15,30 @@ class AddToCartWithOptionsPage {
private editor: Editor;
BLOCK_SLUG = 'woocommerce/add-to-cart-with-options';
BLOCK_NAME = 'Add to Cart + Options (Beta)';
+ EDITOR_INNER_BLOCKS = {
+ simple: [
+ 'Product Stock Indicator',
+ 'Product Quantity (Beta)',
+ 'Add to Cart Button',
+ ],
+ external: [ 'Add to Cart Button' ],
+ variable: [
+ 'Variation Selector (Beta)',
+ 'Variation Selector: Attribute Name (Beta)',
+ 'Variation Selector: Template (Beta)',
+ 'Variation Description (Beta)',
+ 'Product Stock Indicator',
+ 'Product Quantity (Beta)',
+ 'Add to Cart Button',
+ ],
+ grouped: [
+ 'Grouped Product Selector (Beta)',
+ 'Grouped Product: Template (Beta)',
+ 'Grouped Product: Item Selector (Beta)',
+ 'Grouped Product: Item Label (Beta)',
+ 'Product Price',
+ ],
+ };
constructor( {
page,
@@ -56,11 +80,25 @@ class AddToCartWithOptionsPage {
state: 'hidden',
} );
- await addToCartWithOptionsBlock
- .locator( '.components-spinner' )
- .waitFor( {
- state: 'hidden',
- } );
+ await expect(
+ addToCartWithOptionsBlock.locator( '.components-spinner' )
+ ).toHaveCount( 0 );
+ }
+
+ async expectEditorInnerBlocks(
+ productType: 'simple' | 'external' | 'grouped' | 'variable'
+ ) {
+ const blockNames = this.EDITOR_INNER_BLOCKS[ productType ];
+ const addToCartWithOptionsBlock = await this.editor.getBlockByName(
+ this.BLOCK_SLUG
+ );
+ for ( const blockName of blockNames ) {
+ await expect(
+ addToCartWithOptionsBlock
+ .getByLabel( `Block: ${ blockName }` )
+ .first()
+ ).toBeVisible();
+ }
}
async insertParagraphInTemplatePart( content: string ) {