Commit eee57322335 for woocommerce
commit eee573223351ed34b246fe6c4cc6f7d064b2bfc9
Author: Albert Juhé Lluveras <contact@albertjuhe.com>
Date: Thu Apr 9 14:37:27 2026 +0200
Unify Add to Cart + Options e2e test utils (#64083)
* Add to Cart + Options: unify e2e tests utils
* Add changelog
* Minor enhancements
* Linting
* Fix test
* Typo
* Improve block selection
* Use 'options' instead of 'attributes' for frontend options to make naming aligned with other utils
* Use disabled class when checking if button is enabled
diff --git a/plugins/woocommerce/changelog/update-add-to-cart-with-options-e2e-tests-unify-utils b/plugins/woocommerce/changelog/update-add-to-cart-with-options-e2e-tests-unify-utils
new file mode 100644
index 00000000000..5f00f94d4f1
--- /dev/null
+++ b/plugins/woocommerce/changelog/update-add-to-cart-with-options-e2e-tests-unify-utils
@@ -0,0 +1,5 @@
+Significance: patch
+Type: dev
+Comment: Unify Add to Cart + Options e2e test utils
+
+
diff --git a/plugins/woocommerce/client/blocks/tests/e2e/tests/add-to-cart-with-options/add-to-cart-with-options.block_theme.spec.ts b/plugins/woocommerce/client/blocks/tests/e2e/tests/add-to-cart-with-options/add-to-cart-with-options.block_theme.spec.ts
index 80716f09bb6..fcf0bc52b33 100644
--- a/plugins/woocommerce/client/blocks/tests/e2e/tests/add-to-cart-with-options/add-to-cart-with-options.block_theme.spec.ts
+++ b/plugins/woocommerce/client/blocks/tests/e2e/tests/add-to-cart-with-options/add-to-cart-with-options.block_theme.spec.ts
@@ -1,7 +1,7 @@
/**
* External dependencies
*/
-import { test as base, expect, wpCLI, Editor } from '@woocommerce/e2e-utils';
+import { test as base, expect, wpCLI } from '@woocommerce/e2e-utils';
/**
* Internal dependencies
@@ -464,20 +464,20 @@ test.describe( 'Add to Cart + Options Block', () => {
exact: true,
} );
- await expect( petitOption ).not.toBeDisabled();
- await expect( grandOption ).not.toBeDisabled();
+ await expect( petitOption ).toBeEnabled();
+ await expect( grandOption ).toBeEnabled();
await petitOption.click();
- await expect( addToCartButton ).not.toBeDisabled();
+ await expect( addToCartButton ).not.toHaveClass( /\bdisabled\b/ );
await addToCartButton.click();
await expect( page.getByText( '1 in cart' ) ).toBeVisible();
} );
await test.step( 'when in dropdown mode', async () => {
await pageObject.updateSingleProductTemplate();
-
- await pageObject.switchToDropdownMode();
-
+ await pageObject.setVariationSelectorAttributes( {
+ optionStyle: 'dropdown',
+ } );
await editor.saveSiteEditorEntities();
await page.goto( '/product/custom-slug-variable/' );
@@ -499,11 +499,11 @@ test.describe( 'Add to Cart + Options Block', () => {
exact: true,
} );
- await expect( petitOption ).not.toBeDisabled();
- await expect( grandOption ).not.toBeDisabled();
+ await expect( petitOption ).toBeEnabled();
+ await expect( grandOption ).toBeEnabled();
await select.selectOption( { label: 'Petit' } );
- await expect( addToCartButton ).not.toBeDisabled();
+ await expect( addToCartButton ).not.toHaveClass( /\bdisabled\b/ );
await addToCartButton.click();
await expect( page.getByText( '2 in cart' ) ).toBeVisible();
} );
@@ -805,9 +805,9 @@ test.describe( 'Add to Cart + Options Block', () => {
editor,
} ) => {
await pageObject.updateSingleProductTemplate();
-
- await pageObject.switchToDropdownMode();
-
+ await pageObject.setVariationSelectorAttributes( {
+ optionStyle: 'dropdown',
+ } );
await editor.saveSiteEditorEntities();
await page.goto( '/product/hoodie/' );
@@ -1427,86 +1427,6 @@ test.describe( 'Add to Cart + Options Block', () => {
},
];
- async function setAddToCartWithOptionsBlockAttributes(
- pageObject: AddToCartWithOptionsPage,
- editor: Editor,
- {
- optionStyle = 'Pills',
- autoselect = false,
- disabledAttributesAction = 'disable',
- }: {
- optionStyle?: 'Pills' | 'Dropdown';
- autoselect?: boolean;
- disabledAttributesAction?: 'disable' | 'hide';
- } = {}
- ) {
- const page = editor.page;
- let isOnlyCurrentEntityDirty = true;
-
- await pageObject.switchProductType( 'Variable product' );
- await page.getByRole( 'tab', { name: 'Block' } ).click();
- const addToCartWithOptionsBlock = editor.canvas.getByLabel(
- 'Block: Add to Cart + Options'
- );
- await addToCartWithOptionsBlock.click();
- await addToCartWithOptionsBlock
- .getByLabel( 'Block: Variation Selector: Attribute Options' )
- .first()
- .click();
-
- const optionStyleInput = page.getByRole( 'radio', {
- name: optionStyle,
- exact: true,
- } );
- if ( ! ( await optionStyleInput.isChecked() ) ) {
- isOnlyCurrentEntityDirty = false;
- await optionStyleInput.click();
- }
-
- const autoselectInput = page.getByRole( 'checkbox', {
- name: 'Auto-select when only one option is available',
- } );
- const invalidOptionsLabel =
- disabledAttributesAction === 'disable'
- ? 'Grayed-out'
- : 'Hidden';
- const invalidOptionsRadio = page
- .getByLabel( 'Invalid options' )
- .getByRole( 'radio', { name: invalidOptionsLabel } );
-
- const isAutoselectChecked = await autoselectInput.isChecked();
- const isInvalidOptionSelected =
- ( await invalidOptionsRadio.getAttribute( 'aria-checked' ) ) ===
- 'true';
-
- if (
- isAutoselectChecked !== autoselect ||
- ! isInvalidOptionSelected
- ) {
- isOnlyCurrentEntityDirty = false;
- }
-
- await autoselectInput.setChecked( autoselect );
- if ( ! isInvalidOptionSelected ) {
- await invalidOptionsRadio.click();
- }
- if (
- await page
- .getByRole( 'region', {
- name: 'Editor top bar',
- } )
- .getByRole( 'button', {
- name: 'Save',
- exact: true,
- } )
- .isEnabled()
- ) {
- await editor.saveSiteEditorEntities( {
- isOnlyCurrentEntityDirty,
- } );
- }
- }
-
test.beforeEach( async () => {
const cliOutput = await wpCLI(
`wc product create --user=1 --slug="${ productSlug }" --name="${ productName }" --type="variable" --attributes='${ JSON.stringify(
@@ -1536,9 +1456,9 @@ test.describe( 'Add to Cart + Options Block', () => {
}
} );
- for ( const optionStyle of [ 'Pills', 'Dropdown' ] as (
- | 'Pills'
- | 'Dropdown'
+ for ( const optionStyle of [ 'pills', 'dropdown' ] as (
+ | 'pills'
+ | 'dropdown'
)[] ) {
// eslint-disable-next-line playwright/expect-expect
test( `${ optionStyle }: Test the autoselect block attribute`, async ( {
@@ -1547,16 +1467,22 @@ test.describe( 'Add to Cart + Options Block', () => {
editor,
} ) => {
await pageObject.updateSingleProductTemplate();
- await setAddToCartWithOptionsBlockAttributes(
- pageObject,
- editor,
- { optionStyle }
- );
+
+ if ( optionStyle === 'pills' ) {
+ await editor.saveSiteEditorEntities( {
+ isOnlyCurrentEntityDirty: true,
+ } );
+ } else {
+ await pageObject.setVariationSelectorAttributes( {
+ optionStyle,
+ } );
+ await editor.saveSiteEditorEntities();
+ }
await test.step( `${ optionStyle }: Expect NOTHING to be auto-selected (on page load)`, async () => {
await page.goto( productPermalink );
- await pageObject.expectSelectedAttributes(
+ await pageObject.expectVariationSelectorOptions(
productAttributes,
{ Type: '', Color: '', Size: '' },
optionStyle
@@ -1566,14 +1492,14 @@ test.describe( 'Add to Cart + Options Block', () => {
await test.step( `${ optionStyle }: Expect attributes to NOT auto-select when user selects something`, async () => {
await page.goto( productPermalink );
- await pageObject.selectVariationSelectorOptionsBlockAttribute(
+ await pageObject.selectVariationSelectorOptions(
'Color',
'Blue',
optionStyle
);
// Expect nothing to be auto-selected
- await pageObject.expectSelectedAttributes(
+ await pageObject.expectVariationSelectorOptions(
productAttributes,
{ Type: '', Color: 'Blue', Size: '' },
optionStyle
@@ -1582,18 +1508,18 @@ test.describe( 'Add to Cart + Options Block', () => {
await test.step( `${ optionStyle }: Set the autoselect setting to true`, async () => {
await pageObject.updateSingleProductTemplate();
- await setAddToCartWithOptionsBlockAttributes(
- pageObject,
- editor,
- { optionStyle, autoselect: true }
- );
+ await pageObject.setVariationSelectorAttributes( {
+ optionStyle,
+ autoselect: true,
+ } );
+ await editor.saveSiteEditorEntities();
} );
await test.step( `${ optionStyle }: Expect only the Type attribute to be auto-selected (on page load)`, async () => {
await page.goto( productPermalink );
// Expect the Type attribute to be auto-selected (on page load) to "T-shirt", the rest of the attributes should not be selected.
- await pageObject.expectSelectedAttributes(
+ await pageObject.expectVariationSelectorOptions(
productAttributes,
{ Type: 'T-shirt', Color: '', Size: '' },
optionStyle
@@ -1604,13 +1530,13 @@ test.describe( 'Add to Cart + Options Block', () => {
await page.goto( productPermalink );
// By setting the Color to "Blue", we expect the Type attribute to be auto-selected to "T-shirt", and the Size to "XL".
- await pageObject.selectVariationSelectorOptionsBlockAttribute(
+ await pageObject.selectVariationSelectorOptions(
'Color',
'Blue',
optionStyle
);
- await pageObject.expectSelectedAttributes(
+ await pageObject.expectVariationSelectorOptions(
productAttributes,
{ Type: 'T-shirt', Color: 'Blue', Size: 'XL' },
optionStyle
@@ -1624,20 +1550,23 @@ test.describe( 'Add to Cart + Options Block', () => {
} ) => {
await test.step( `${ optionStyle }: Set the disabledAttributesAction block attribute to "disable"`, async () => {
await pageObject.updateSingleProductTemplate();
- await setAddToCartWithOptionsBlockAttributes(
- pageObject,
- editor,
- {
+
+ if ( optionStyle === 'pills' ) {
+ await editor.saveSiteEditorEntities( {
+ isOnlyCurrentEntityDirty: true,
+ } );
+ } else {
+ await pageObject.setVariationSelectorAttributes( {
optionStyle,
- disabledAttributesAction: 'disable',
- }
- );
+ } );
+ await editor.saveSiteEditorEntities();
+ }
} );
await test.step( `${ optionStyle }: Expect invalid options to be disabled (by prop) and visible`, async () => {
await page.goto( productPermalink );
// By setting the Color to "Blue", the only possible Size remaining is "XL".
- await pageObject.selectVariationSelectorOptionsBlockAttribute(
+ await pageObject.selectVariationSelectorOptions(
'Color',
'Blue',
optionStyle
@@ -1657,20 +1586,17 @@ test.describe( 'Add to Cart + Options Block', () => {
await test.step( `${ optionStyle }: Set the disabledAttributesAction block attribute to "hide"`, async () => {
await pageObject.updateSingleProductTemplate();
- await setAddToCartWithOptionsBlockAttributes(
- pageObject,
- editor,
- {
- optionStyle,
- disabledAttributesAction: 'hide',
- }
- );
+ await pageObject.setVariationSelectorAttributes( {
+ optionStyle,
+ disabledAttributesAction: 'hide',
+ } );
+ await editor.saveSiteEditorEntities();
} );
- await test.step( `${ optionStyle }: Expect invalid options to be isabled (by prop) and hidden`, async () => {
+ await test.step( `${ optionStyle }: Expect invalid options to be disabled (by prop) and hidden`, async () => {
await page.goto( productPermalink );
// By setting the Color to "Blue", the only possible Size remaining is "XL".
- await pageObject.selectVariationSelectorOptionsBlockAttribute(
+ await pageObject.selectVariationSelectorOptions(
'Color',
'Blue',
optionStyle
@@ -1701,27 +1627,24 @@ test.describe( 'Add to Cart + Options Block', () => {
await pageObject.updateSingleProductTemplate();
await test.step( `${ optionStyle }: Set the disabledAttributesAction block attribute to "${ disabledAttributesAction }"`, async () => {
- await setAddToCartWithOptionsBlockAttributes(
- pageObject,
- editor,
- {
- autoselect: true,
- optionStyle,
- disabledAttributesAction,
- }
- );
+ await pageObject.setVariationSelectorAttributes( {
+ autoselect: true,
+ optionStyle,
+ disabledAttributesAction,
+ } );
+ await editor.saveSiteEditorEntities();
} );
await test.step( `disabledAttributesAction === ${ disabledAttributesAction }: Expect options to be properly auto-selected`, async () => {
await page.goto( productPermalink );
// By selecting the Color to "Blue", the only possible Size remaining is "XL".
- await pageObject.selectVariationSelectorOptionsBlockAttribute(
+ await pageObject.selectVariationSelectorOptions(
'Color',
'Blue',
optionStyle
);
// Now, we deselect the Color.
- await pageObject.selectVariationSelectorOptionsBlockAttribute(
+ await pageObject.selectVariationSelectorOptions(
'Color',
'',
optionStyle
@@ -1732,7 +1655,7 @@ test.describe( 'Add to Cart + Options Block', () => {
// Size: XL
// Because the Size is XL, the only Colors possible are Red and Blue.
// Now if we select Size: S, the Color should auto-select to Green.
- await pageObject.selectVariationSelectorOptionsBlockAttribute(
+ await pageObject.selectVariationSelectorOptions(
'Size',
'S',
optionStyle
@@ -1742,7 +1665,7 @@ test.describe( 'Add to Cart + Options Block', () => {
// Color: Green
// Size: S
- await pageObject.expectSelectedAttributes(
+ await pageObject.expectVariationSelectorOptions(
productAttributes,
{ Type: 'T-shirt', Color: 'Green', Size: 'S' },
optionStyle
@@ -1758,26 +1681,27 @@ test.describe( 'Add to Cart + Options Block', () => {
editor,
} ) => {
await pageObject.updateSingleProductTemplate();
- await setAddToCartWithOptionsBlockAttributes( pageObject, editor, {
- optionStyle: 'Pills',
+ await pageObject.setVariationSelectorAttributes( {
+ optionStyle: 'pills',
autoselect: true,
} );
+ await editor.saveSiteEditorEntities();
await test.step( 'Add the Blue/XL variation to cart', async () => {
await page.goto( productPermalink );
// Select Blue and XL to match the T-shirt, Blue, XL variation
- await pageObject.selectVariationSelectorOptionsBlockAttribute(
+ await pageObject.selectVariationSelectorOptions(
'Color',
'Blue',
- 'Pills'
+ 'pills'
);
// Type and Size should auto-select to T-shirt and XL
- await pageObject.expectSelectedAttributes(
+ await pageObject.expectVariationSelectorOptions(
productAttributes,
{ Type: 'T-shirt', Color: 'Blue', Size: 'XL' },
- 'Pills'
+ 'pills'
);
// Add to cart
@@ -1801,10 +1725,10 @@ test.describe( 'Add to Cart + Options Block', () => {
// Now select Blue - this should auto-select Size to XL
// (since Blue only has one valid size: XL)
- await pageObject.selectVariationSelectorOptionsBlockAttribute(
+ await pageObject.selectVariationSelectorOptions(
'Color',
'Blue',
- 'Pills'
+ 'pills'
);
// After auto-selection completes, the button should show "1 in cart"
diff --git a/plugins/woocommerce/client/blocks/tests/e2e/tests/add-to-cart-with-options/add-to-cart-with-options.page.ts b/plugins/woocommerce/client/blocks/tests/e2e/tests/add-to-cart-with-options/add-to-cart-with-options.page.ts
index 0a3b19b60ac..175c43752ce 100644
--- a/plugins/woocommerce/client/blocks/tests/e2e/tests/add-to-cart-with-options/add-to-cart-with-options.page.ts
+++ b/plugins/woocommerce/client/blocks/tests/e2e/tests/add-to-cart-with-options/add-to-cart-with-options.page.ts
@@ -109,10 +109,19 @@ class AddToCartWithOptionsPage {
await this.updateAddToCartWithOptionsBlock();
}
- async switchToDropdownMode() {
- await this.switchProductType( 'Variable product' );
+ async setVariationSelectorAttributes( {
+ optionStyle,
+ autoselect,
+ disabledAttributesAction,
+ }: {
+ optionStyle?: 'pills' | 'dropdown';
+ autoselect?: boolean;
+ disabledAttributesAction?: 'disable' | 'hide';
+ } = {} ) {
+ const page = this.editor.page;
- await this.page.getByRole( 'tab', { name: 'Block' } ).click();
+ await this.switchProductType( 'Variable product' );
+ await page.getByRole( 'tab', { name: 'Block' } ).click();
// Verify inner blocks have loaded.
await expect(
@@ -128,7 +137,33 @@ class AddToCartWithOptionsPage {
);
await this.editor.selectBlocks( attributeOptionsBlock.first() );
- await this.page.getByRole( 'radio', { name: 'Dropdown' } ).click();
+ // Option style attribute.
+ if ( optionStyle ) {
+ const optionStyleInput = page.getByRole( 'radio', {
+ name: optionStyle,
+ } );
+ await optionStyleInput.click();
+ }
+
+ // Auto-select attribute.
+ if ( typeof autoselect === 'boolean' ) {
+ const autoselectInput = page.getByRole( 'checkbox', {
+ name: 'Auto-select when only one option is available',
+ } );
+ await autoselectInput.setChecked( autoselect );
+ }
+
+ // Invalid options attribute.
+ if ( disabledAttributesAction ) {
+ const invalidOptionsLabel =
+ disabledAttributesAction === 'disable'
+ ? 'Grayed-out'
+ : 'Hidden';
+ const invalidOptionsRadio = page
+ .getByLabel( 'Invalid options' )
+ .getByRole( 'radio', { name: invalidOptionsLabel } );
+ await invalidOptionsRadio.click();
+ }
}
async createPostWithProductBlock( product: string, variation?: string ) {
@@ -157,31 +192,29 @@ class AddToCartWithOptionsPage {
await this.editor.publishAndVisitPost();
}
- async selectVariationSelectorOptionsBlockAttribute(
+ async selectVariationSelectorOptions(
attributeName: string,
attributeValue: string,
- optionStyle: 'Pills' | 'Dropdown'
+ optionStyle: 'pills' | 'dropdown'
) {
- if ( optionStyle === 'Dropdown' ) {
+ if ( optionStyle === 'dropdown' ) {
await this.page
.getByLabel( attributeName )
.selectOption( attributeValue );
- return;
- }
- if ( attributeValue !== '' ) {
+ } else if ( attributeValue !== '' ) {
await this.page
.getByLabel( attributeName )
.getByText( attributeValue )
.click();
- return;
+ } else {
+ await this.page
+ .getByLabel( attributeName )
+ .locator( 'label:has(:checked)' )
+ .click();
}
- await this.page
- .getByLabel( attributeName )
- .locator( 'label:has(:checked)' )
- .click();
}
- async expectSelectedAttributes(
+ async expectVariationSelectorOptions(
productAttributes: {
name: string;
options: string[];
@@ -189,7 +222,7 @@ class AddToCartWithOptionsPage {
visible: boolean;
}[],
expectedValues: Record< string, string | RegExp > = {},
- optionStyle: 'Pills' | 'Dropdown'
+ optionStyle: 'pills' | 'dropdown'
) {
for ( let {
name: attributeName,
@@ -198,7 +231,7 @@ class AddToCartWithOptionsPage {
const attributeNameLocator = this.page.getByLabel( attributeName, {
exact: true,
} );
- if ( optionStyle === 'Dropdown' ) {
+ if ( optionStyle === 'dropdown' ) {
let expectedValue: string | RegExp;
if (
attributeName in expectedValues &&
@@ -211,7 +244,7 @@ class AddToCartWithOptionsPage {
await expect( attributeNameLocator ).toHaveValue(
expectedValue
);
- return;
+ continue;
}
if (
attributeName in expectedValues &&