Commit fffbbffe543 for woocommerce

commit fffbbffe543ae2b8df61f6caf7b63c60b58296ab
Author: Vlad Olaru <vlad.olaru@automattic.com>
Date:   Tue Oct 6 12:21:17 2026 +0300

    [tests] Stabilise variable product and variation bulk edit specs (#68654)

    * test(e2e): Stabilise variable product and variation bulk edit specs

    Two specs, no titles removed from either, and no coverage moved
    between layers. Both changes are stabilization carried from the
    migration branch. Two of them need a decision, and that is why this
    is its own pull request rather than part of the grouped products
    migration it started with.

    **One: the cart total is no longer checked against a computed sum.**

    product-variable.spec.ts used to compute the expected total from the
    selected variations' prices and assert the rendered value contained
    it. It now asserts only that the Estimated total row shows a value
    matching `$NN.NN`.

    The reasoning in the migration branch is sound as far as it goes. The
    old assertion took the last totals value as the product sum, which
    picked up shipping when a parallel test configured it, and it assumed
    a pre-tax sum that the configured Cart does not render. Both produced
    false failures with every variation correctly present.

    But the replacement no longer checks the number. A wrong price, a
    double-counted variation or a $0.00 total would now pass. That is a
    looser assertion, which this campaign's rules put in the same
    sentence as retries and waits. Worth asking whether a tax- and
    shipping-aware expected value is reachable here, rather than
    dropping value checking entirely.

    **Two: an explicit 45 second timeout.**

    update-variations.spec.ts waits for the product data panel's blockUI
    overlay to clear after selecting a bulk action:

        await expect(
            page.locator( '#woocommerce-product-data .blockUI.blockOverlay' )
        ).toBeHidden( { timeout: 45_000 } );

    The wait itself is the right shape — a condition, not a sleep. The
    ceiling is the question. Measured on this checkout across three runs
    the overlay clears in 798, 805 and 802 milliseconds. The project
    default is 10 seconds locally and 20 in CI, so 45 seconds is about 56
    times the observed duration. Removing the override entirely also
    passes here. This same file waits on the same overlay twice more,
    at lines 680 and 752, both on the default.

    An independent review of this branch read that as timeout inflation
    that should simply come off, with no incident cited to justify the
    figure. I have kept the migration branch's version rather than
    editing it, because the number may be answering something in CI that
    this checkout does not reproduce. If it is not, it should come off
    and the assertion should stand on the default like its two siblings.

    Carries the mega-branch commits:
    - 65ae912cde test(e2e): Assert rendered cart estimated total
    - 985538898c test(e2e): Fix variable product total assertion
    - 4471e83c98 fix(e2e): synchronize Core admin interactions

    Refs TESTOPS-288
    Refs #68046

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

    * test(product): Assert a real cart total for variable products

    The Estimated total check had been reduced to a currency pattern,
    /^\$\d+\.\d{2}$/, which $0.00 satisfies, so a Cart block totals
    regression passed. The locator fix that came with it was right and is
    kept; only the value check was missing.

    Assert a floor of the summed variation prices rather than an exact
    figure. Estimated total is cart->get_total(), which carries shipping and
    tax on top of the line items, and this describe block resets neither, so
    an upper bound would fail whenever the suite 20% tax rate and $10 flat
    rate stack with nothing actually broken.

    Proved by mutation: forcing total_price to 0 in CartSchema.php fails the
    floor with "Expected: >= 81.64, Received: 0". The previous pattern passed.

    Also drop a 45s timeout override on a blockOverlay assertion measured at
    roughly 800ms against a 10s local default, and scope its sibling to
    #woocommerce-product-data so it cannot be satisfied by an unrelated
    overlay elsewhere on the page.

    Refs TESTOPS-288

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

    * test(product): Assert exact cart prices for variable products

    The add-to-cart test checked the Estimated total against a floor of
    the summed variation prices. That catches a $0.00 total, but passes
    any inflated one: a wrong line price, an extra fee, or tax applied
    where none should be.

    The floor assumed a 20% tax rate and a $10 flat rate could stack on
    the total. Neither applies in core-parallel. Site setup deletes every
    standard-rate tax rate, displays prices ex-tax, and attaches free
    shipping to the fallback zone, so untaxed totals stay deterministic.
    Specs that need a rate scope it to their own tax class, and the
    global-rate specs run in core-serial or blocks-chromium, which CI runs
    as separate jobs on separate sites. product-grouped and
    product-create-simple in the same project already assert exact
    block-cart totals.

    Assert each row's line total and the Estimated total exactly, with
    retrying assertions. Rows are matched by index because they share the
    product name and "Large" is a substring of "XLarge".

    Proved by mutation: adding $1.00 through woocommerce_calculated_total
    fails at the total ($82.64 vs $81.64) where the floor passed, and
    pricing one cart line at $99.00 fails at that row.

    Refs TESTOPS-288

    ---------

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

diff --git a/plugins/woocommerce/changelog/testops-288-variable-and-variations-sync b/plugins/woocommerce/changelog/testops-288-variable-and-variations-sync
new file mode 100644
index 00000000000..a7bc57dfe66
--- /dev/null
+++ b/plugins/woocommerce/changelog/testops-288-variable-and-variations-sync
@@ -0,0 +1,4 @@
+Significance: patch
+Type: dev
+Comment: Assert the rendered cart estimated total in the variable product E2E spec, and wait for the product data overlay to clear before bulk editing variations.
+
diff --git a/plugins/woocommerce/tests/e2e/tests/product/product-variable.spec.ts b/plugins/woocommerce/tests/e2e/tests/product/product-variable.spec.ts
index 29fa7c99ded..4ae6b7e01d4 100644
--- a/plugins/woocommerce/tests/e2e/tests/product/product-variable.spec.ts
+++ b/plugins/woocommerce/tests/e2e/tests/product/product-variable.spec.ts
@@ -244,25 +244,43 @@ test.describe(

 			await page.getByRole( 'link', { name: 'View cart' } ).click();

-			const rowsLocator = 'tr.wc-block-cart-items__row';
+			const rows = page.locator( 'tr.wc-block-cart-items__row' );

-			await expect( page.locator( rowsLocator ) ).toHaveCount( 4 );
+			await expect( rows ).toHaveCount( variations1.length );

-			for ( const row of await page.locator( rowsLocator ).all() ) {
+			// Cart rows keep the order the variations were added in. Match by
+			// index: every row shares the product name, and the size options
+			// overlap as text ("Large" is inside "XLarge").
+			for ( let i = 0; i < variations1.length; i++ ) {
+				const row = rows.nth( i );
 				await expect( row ).toContainText( variableProductName );
 				await expect(
 					row.getByRole( 'spinbutton', { name: 'Quantity' } )
 				).toHaveValue( '1' );
+				await expect(
+					row.locator( 'td.wc-block-cart-item__total' )
+				).toHaveText(
+					`$${ parseFloat( variations1[ i ].regular_price ).toFixed(
+						2
+					) }`
+				);
 			}

-			const expectedTotal = variations1.reduce( ( sum, variation ) => {
-				const price = parseFloat( variation.regular_price );
-				return sum + price;
-			}, 0 );
+			// Site setup leaves core-parallel with no standard tax rate and
+			// free fallback shipping, so the total is the plain sum.
+			const expectedTotal = variations1.reduce(
+				( sum, variation ) =>
+					sum + parseFloat( variation.regular_price ),
+				0
+			);

 			await expect(
-				page.locator( '.wc-block-components-totals-item__value' ).last()
-			).toContainText( expectedTotal.toString() );
+				page
+					.getByRole( 'main' )
+					.locator( '.wc-block-components-totals-item' )
+					.filter( { hasText: 'Estimated total' } )
+					.locator( '.wc-block-components-totals-item__value' )
+			).toHaveText( `$${ expectedTotal.toFixed( 2 ) }` );
 		} );

 		test( 'should be able to remove variation products from the cart', async ( {
diff --git a/plugins/woocommerce/tests/e2e/tests/product/update-variations.spec.ts b/plugins/woocommerce/tests/e2e/tests/product/update-variations.spec.ts
index 87f3220cc58..cfe1bb52a28 100644
--- a/plugins/woocommerce/tests/e2e/tests/product/update-variations.spec.ts
+++ b/plugins/woocommerce/tests/e2e/tests/product/update-variations.spec.ts
@@ -378,6 +378,11 @@ test.describe( 'Update variations', { tag: tags.GUTENBERG }, () => {
 			await page
 				.locator( '#field_to_edit' )
 				.selectOption( 'toggle_downloadable' );
+			await expect(
+				page.locator(
+					'#woocommerce-product-data .blockUI.blockOverlay'
+				)
+			).toBeHidden();
 		} );

 		await test.step( 'Expand all variations.', async () => {
@@ -744,7 +749,11 @@ test.describe( 'Update variations', { tag: tags.GUTENBERG }, () => {
 		await gotToVariationsTab( page );

 		await test.step( 'Wait for block overlay to disappear.', async () => {
-			await expect( page.locator( '.blockOverlay' ) ).toBeHidden();
+			await expect(
+				page.locator(
+					'#woocommerce-product-data .blockUI.blockOverlay'
+				)
+			).toBeHidden();
 		} );

 		await test.step( 'Select variation defaults', async () => {