Commit 5e9c4f38151 for woocommerce
commit 5e9c4f38151e732b8745223cd688339b6a41d589
Author: Adrian Moldovan <3854374+adimoldovan@users.noreply.github.com>
Date: Tue Jul 7 23:54:15 2026 +0300
e2e tests: reorganize analytics specs across serial and parallel pools (#66388)
diff --git a/plugins/woocommerce/changelog/dev-testops-210-analytics-e2e-pools b/plugins/woocommerce/changelog/dev-testops-210-analytics-e2e-pools
new file mode 100644
index 00000000000..a502afc30e3
--- /dev/null
+++ b/plugins/woocommerce/changelog/dev-testops-210-analytics-e2e-pools
@@ -0,0 +1,4 @@
+Significance: patch
+Type: dev
+
+E2E: reorganize the analytics specs across the core-serial/core-parallel pools — move analytics (with the Overview manual-import-trigger tests folded in) and analytics-overview to core-parallel, keep only analytics-settings serial, and drop the redundant analytics-access smoke test.
diff --git a/plugins/woocommerce/tests/e2e/playwright.config.ts b/plugins/woocommerce/tests/e2e/playwright.config.ts
index 20344f92adf..70f35dce557 100644
--- a/plugins/woocommerce/tests/e2e/playwright.config.ts
+++ b/plugins/woocommerce/tests/e2e/playwright.config.ts
@@ -120,19 +120,17 @@ export const setupProjects = [
* `core-parallel` by default, except the other-project folders in `nonCoreSpecs`.
*/
const serialRunSpecs = [
- // Forces immediate analytics-import mode by flipping the global
- // `woocommerce_analytics_scheduled_import` option, and needs it to stay
- // immediate while it creates orders and drains their imports. In
- // `core-parallel` that would race `analytics-settings.spec.ts` — which runs in
- // that pool and toggles the same option — over the shared store and Action
- // Scheduler queue. Its numeric assertions are scoped to its own products, so
- // they no longer depend on store-wide totals.
- '**/tests/analytics/analytics-data.spec.ts',
- // Asserts store-wide `$0.00 / Orders 0`, polluted by concurrent orders.
- '**/tests/analytics/analytics-access.spec.ts',
- // Mutates the shared admin's `woocommerce_meta.dashboard_sections` and flips the
- // global `woocommerce_analytics_scheduled_import` option (racing analytics-settings).
- '**/tests/analytics/analytics-overview.spec.ts',
+ // Toggles the global `woocommerce_analytics_scheduled_import` option to
+ // exercise the Settings-page scheduled/immediate switch. Kept serial because,
+ // as a standalone file, running it in `core-parallel` would race
+ // `analytics.spec.ts` — which also toggles that option — across workers.
+ // (The other analytics specs are parallel: `analytics` owns its own
+ // import-mode toggles plus the Overview manual-trigger tests in one file, so
+ // those serialise within a single worker; `analytics-overview` only mutates
+ // the admin's own `dashboard_sections` meta. No other parallel spec depends on
+ // the order-import mode, and this serial job never runs concurrently with the
+ // parallel one.)
+ '**/tests/analytics/analytics-settings.spec.ts',
// Flips the global `woocommerce_default_customer_address` (geolocation) and
// `woocommerce_enable_ajax_add_to_cart` settings, which change add-to-cart
// behavior for every other worker. (`cart.spec.ts` runs in core-parallel — it
diff --git a/plugins/woocommerce/tests/e2e/tests/analytics/analytics-access.spec.ts b/plugins/woocommerce/tests/e2e/tests/analytics/analytics-access.spec.ts
deleted file mode 100644
index 2121bd6efde..00000000000
--- a/plugins/woocommerce/tests/e2e/tests/analytics/analytics-access.spec.ts
+++ /dev/null
@@ -1,85 +0,0 @@
-/**
- * External dependencies
- */
-import { test, expect } from '@playwright/test';
-
-/**
- * Internal dependencies
- */
-import { tags } from '../../fixtures/fixtures';
-import { ADMIN_STATE_PATH } from '../../playwright.config';
-
-test.describe( 'WooCommerce Home', () => {
- test.use( { storageState: ADMIN_STATE_PATH } );
-
- test(
- 'Can access Analytics Reports from Stats Overview',
- { tag: [ tags.NOT_E2E ] },
- async ( { page } ) => {
- await test.step( 'Navigate to the WooCommerce Home page', async () => {
- await page.goto( 'wp-admin/admin.php?page=wc-admin' );
- await expect(
- page.getByText( 'Stats overview' )
- ).toBeVisible();
- await expect(
- page.getByRole( 'menuitem', {
- name: 'Total sales $0.00 No change',
- } )
- ).toBeVisible();
- await expect(
- page.getByRole( 'link', { name: 'View detailed stats' } )
- ).toBeVisible();
- } );
-
- await test.step( 'Navigate to Revenue Report', async () => {
- await page
- .getByRole( 'menuitem', {
- name: 'Total sales $0.00 No change',
- } )
- .click();
- await expect(
- page.getByRole( 'heading', { name: 'Revenue' } ).first()
- ).toBeVisible();
- await expect( page.url() ).toContain(
- 'admin.php?page=wc-admin&chart=total_sales&period=today&compare=previous_period&path=%2Fanalytics%2Frevenue'
- );
- } );
-
- await test.step( 'Navigate to Orders Report', async () => {
- await page.goto( 'wp-admin/admin.php?page=wc-admin' );
- await expect(
- page.getByRole( 'menuitem', {
- name: 'Orders 0 No change from',
- } )
- ).toBeVisible();
- await page
- .getByRole( 'menuitem', {
- name: 'Orders 0 No change from',
- } )
- .click();
- await expect(
- page.getByRole( 'heading', { name: 'Orders' } ).first()
- ).toBeVisible();
- await expect( page.url() ).toContain(
- 'admin.php?page=wc-admin&chart=orders_count&period=today&compare=previous_period&path=%2Fanalytics%2Forders'
- );
- } );
-
- await test.step( 'Navigate to Analytics Overview', async () => {
- await page.goto( 'wp-admin/admin.php?page=wc-admin' );
- await expect(
- page.getByRole( 'link', { name: 'View detailed stats' } )
- ).toBeVisible();
- await page
- .getByRole( 'link', { name: 'View detailed stats' } )
- .click();
- await expect(
- page.getByRole( 'heading', { name: 'Overview' } ).first()
- ).toBeVisible();
- await expect( page.url() ).toContain(
- 'admin.php?page=wc-admin&path=%2Fanalytics%2Foverview'
- );
- } );
- }
- );
-} );
diff --git a/plugins/woocommerce/tests/e2e/tests/analytics/analytics-overview.spec.ts b/plugins/woocommerce/tests/e2e/tests/analytics/analytics-overview.spec.ts
index 7d72cf41c36..e49a6ea617b 100644
--- a/plugins/woocommerce/tests/e2e/tests/analytics/analytics-overview.spec.ts
+++ b/plugins/woocommerce/tests/e2e/tests/analytics/analytics-overview.spec.ts
@@ -1,7 +1,7 @@
/**
* External dependencies
*/
-import { test, expect, request } from '@playwright/test';
+import { test, expect } from '@playwright/test';
import type { Page, Locator } from '@playwright/test';
/**
@@ -10,7 +10,6 @@ import type { Page, Locator } from '@playwright/test';
import { admin } from '../../test-data/data';
import { tags } from '../../fixtures/fixtures';
import { ADMIN_STATE_PATH } from '../../playwright.config';
-import { setOption } from '../../utils/options';
const EXPECTED_SECTION_HEADERS = [ 'Performance', 'Charts', 'Leaderboards' ];
@@ -303,89 +302,3 @@ test.describe(
} );
}
);
-
-test.describe(
- 'Analytics Overview - Manual Import Trigger',
- { tag: [ tags.PAYMENTS, tags.SERVICES ] },
- () => {
- test.use( { storageState: ADMIN_STATE_PATH } );
-
- test.beforeAll( async ( { browser } ) => {
- page = await browser.newPage();
- } );
-
- test.beforeEach( async () => {
- await test.step( `Go to Analytics > Overview`, async () => {
- await page.goto(
- 'wp-admin/admin.php?page=wc-admin&path=%2Fanalytics%2Foverview'
- );
- } );
- } );
-
- test.afterAll( async () => {
- await page.close();
- } );
-
- test( 'should show manual update trigger in scheduled mode', async ( {
- baseURL,
- } ) => {
- // Set to scheduled mode
- await setOption(
- request,
- baseURL,
- 'woocommerce_analytics_scheduled_import',
- 'yes'
- );
-
- // Reload the page
- await page.reload();
-
- // Verify import status bar is visible
- await expect( page.getByText( 'Data status' ) ).toBeVisible();
- // Verify "Update now" button is visible
- const updateButton = page.getByRole( 'button', {
- name: 'Manually trigger analytics data import',
- } );
- await expect( updateButton ).toBeVisible();
-
- // Click "Update now" button
- const responsePromise = page.waitForResponse(
- ( response ) =>
- response
- .url()
- .includes( '/wc-analytics/imports/trigger' ) &&
- response.ok()
- );
-
- await updateButton.click();
-
- // Verify button shows loading state (isBusy)
- // After clicking, the aria-label changes to "Analytics data import in progress"
- const busyButton = page.getByRole( 'button', {
- name: 'Analytics data import in progress',
- } );
- await expect( busyButton ).toBeDisabled();
-
- // Wait for API response
- await responsePromise;
- } );
-
- test( 'should hide manual update trigger in immediate mode', async ( {
- baseURL,
- } ) => {
- // Set to immediate mode
- await setOption(
- request,
- baseURL,
- 'woocommerce_analytics_scheduled_import',
- 'no'
- );
-
- // Reload the page
- await page.reload();
-
- // Verify import status bar wrapper is NOT rendered
- await expect( page.getByText( 'Data status' ) ).toBeHidden();
- } );
- }
-);
diff --git a/plugins/woocommerce/tests/e2e/tests/analytics/analytics-data.spec.ts b/plugins/woocommerce/tests/e2e/tests/analytics/analytics.spec.ts
similarity index 87%
rename from plugins/woocommerce/tests/e2e/tests/analytics/analytics-data.spec.ts
rename to plugins/woocommerce/tests/e2e/tests/analytics/analytics.spec.ts
index 7041d85e6dd..415569b7ffd 100644
--- a/plugins/woocommerce/tests/e2e/tests/analytics/analytics-data.spec.ts
+++ b/plugins/woocommerce/tests/e2e/tests/analytics/analytics.spec.ts
@@ -1,7 +1,7 @@
/**
* External dependencies
*/
-import type { Page } from '@playwright/test';
+import { request as apiRequest, type Page } from '@playwright/test';
import {
WC_ADMIN_API_PATH,
WC_API_PATH,
@@ -12,6 +12,7 @@ import {
*/
import { expect, tags, test as baseTest } from '../../fixtures/fixtures';
import { ADMIN_STATE_PATH } from '../../playwright.config';
+import { setOption } from '../../utils/options';
/**
* Escape a string for literal use inside a RegExp.
@@ -632,3 +633,85 @@ test(
).toBeVisible();
}
);
+
+// Overview manual-import trigger. Folded in here so its `scheduled_import`
+// toggle serialises with the data suite's within one core-parallel worker.
+test.describe(
+ 'manual import trigger',
+ { tag: [ tags.PAYMENTS, tags.SERVICES ] },
+ () => {
+ test.beforeEach( async ( { page } ) => {
+ await page.goto(
+ 'wp-admin/admin.php?page=wc-admin&path=%2Fanalytics%2Foverview'
+ );
+ } );
+
+ test( 'shows the manual update trigger in scheduled mode', async ( {
+ page,
+ baseURL,
+ } ) => {
+ // Switch to scheduled mode, where the manual "Update now" trigger is
+ // offered.
+ await setOption(
+ apiRequest,
+ baseURL,
+ 'woocommerce_analytics_scheduled_import',
+ 'yes'
+ );
+
+ // Enabling scheduled mode schedules a recurring batch import whose
+ // first run is "now" (OrdersScheduler::schedule_recurring_batch_processor
+ // → as_schedule_recurring_action( time(), … )). Until that batch runs,
+ // the status bar renders its busy "in progress" state instead of the
+ // "Update now" trigger, and wp-env has no cron to run it. So drain the
+ // Action Scheduler queue via ?process-waiting-actions — exactly as this
+ // spec's data setup does — until the batch clears and the button
+ // settles to idle. Poll because the reload races the drain.
+ const updateButton = page.getByRole( 'button', {
+ name: 'Manually trigger analytics data import',
+ } );
+ await expect( async () => {
+ await page.request.get( '?process-waiting-actions' );
+ await page.reload();
+ await expect( page.getByText( 'Data status' ) ).toBeVisible();
+ await expect( updateButton ).toBeVisible( { timeout: 2_000 } );
+ } ).toPass( {
+ timeout: 30_000,
+ intervals: [ 1_000, 2_000, 3_000 ],
+ } );
+
+ // Clicking it fires the import and flips the button to a busy state.
+ const responsePromise = page.waitForResponse(
+ ( response ) =>
+ response
+ .url()
+ .includes( '/wc-analytics/imports/trigger' ) &&
+ response.ok()
+ );
+ await updateButton.click();
+
+ const busyButton = page.getByRole( 'button', {
+ name: 'Analytics data import in progress',
+ } );
+ await expect( busyButton ).toBeDisabled();
+ await responsePromise;
+ } );
+
+ test( 'hides the manual update trigger in immediate mode', async ( {
+ page,
+ baseURL,
+ } ) => {
+ // In immediate mode there is no batch import to trigger, so the
+ // status bar (and its button) are not rendered.
+ await setOption(
+ apiRequest,
+ baseURL,
+ 'woocommerce_analytics_scheduled_import',
+ 'no'
+ );
+ await page.reload();
+
+ await expect( page.getByText( 'Data status' ) ).toBeHidden();
+ } );
+ }
+);