diff --git a/e2e/a11y.spec.ts b/e2e/a11y.spec.ts index 64787e12a..048c116fd 100644 --- a/e2e/a11y.spec.ts +++ b/e2e/a11y.spec.ts @@ -70,7 +70,11 @@ test.describe("axe-core authenticated surfaces", () => { // need fully-painted DOM, and a flaky API would otherwise stall the // analyse() call until the 30s test timeout. test.beforeEach(async ({ page }) => { - await page.route("**/api/analytics", (route) => + // v1.4.39.3 — match `/api/analytics` AND any sliced variant + // (`?slice=summaries`); the v1.4.39.2 dashboard split fires both + // in parallel and the literal string glob misses the query- + // string form. + await page.route(/\/api\/analytics(\?|$)/, (route) => route.fulfill({ status: 200, contentType: "application/json", diff --git a/e2e/chart-overlay-controls.spec.ts b/e2e/chart-overlay-controls.spec.ts index dec64dd30..c3bf48ca6 100644 --- a/e2e/chart-overlay-controls.spec.ts +++ b/e2e/chart-overlay-controls.spec.ts @@ -21,7 +21,13 @@ test.describe("chart overlay controls", () => { test.beforeEach(async ({ page }) => { // Mock analytics + measurements so the dashboard paints at least // one chart card. Same seed shape the dashboard.spec.ts uses. - await page.route("**/api/analytics", (route) => + // + // v1.4.39.3 — match `/api/analytics` AND any sliced variant + // (`?slice=summaries`). See the comment on dashboard.spec.ts for + // the underlying minimatch-vs-query-string gap; the regex form + // catches both the thick and slim slice URLs the dashboard now + // mounts in parallel. + await page.route(/\/api\/analytics(\?|$)/, (route) => route.fulfill({ status: 200, contentType: "application/json", diff --git a/e2e/charts-mobile.spec.ts b/e2e/charts-mobile.spec.ts index 7c890bcc6..b21fca257 100644 --- a/e2e/charts-mobile.spec.ts +++ b/e2e/charts-mobile.spec.ts @@ -33,7 +33,13 @@ test.describe("charts — mobile-viewport regression", () => { // Mock analytics + measurements so the chart wrappers all clear // their data-floor gates. Same pattern as `dashboard.spec.ts`. - await page.route("**/api/analytics", (route) => + // + // v1.4.39.3 — match `/api/analytics` AND any sliced variant + // (`?slice=summaries`). The v1.4.39.2 dashboard split mounts the + // slim slice in parallel; the literal `**/api/analytics` glob + // misses the query-string form and dropped the request through to + // the real route, blanking the tile strip + chart cards. + await page.route(/\/api\/analytics(\?|$)/, (route) => route.fulfill({ status: 200, contentType: "application/json", diff --git a/e2e/dashboard.spec.ts b/e2e/dashboard.spec.ts index 944b6ac39..60e54b87c 100644 --- a/e2e/dashboard.spec.ts +++ b/e2e/dashboard.spec.ts @@ -23,7 +23,18 @@ test.describe("authenticated dashboard render", () => { // Mock analytics with a populated weight summary so the weight tile // and chart render. `count` must be >0 for the tile to clear the // data-floor gate in `src/app/page.tsx`. - await page.route("**/api/analytics", (route) => + // + // v1.4.39.3 — match `/api/analytics` AND any sliced variant + // (`?slice=summaries`). The v1.4.39.2 dashboard split mounts two + // parallel `useAnalyticsQuery` calls; the slim variant carries a + // `?slice=summaries` query string that the literal string glob + // `**/api/analytics` (Playwright minimatch) refuses to match, + // dropping the request to the real route. The seeded test user has + // no measurements so the real route returns empty summaries, and + // the dashboard's slim-first merge then blanked the tile strip. + // The same trap bit `onboarding-flicker` and `mobile-viewport` in + // v1.4.37 W-CI; the regex form is the durable fix. + await page.route(/\/api\/analytics(\?|$)/, (route) => route.fulfill({ status: 200, contentType: "application/json", diff --git a/e2e/measurement-flow.spec.ts b/e2e/measurement-flow.spec.ts index e23e194a3..904095a1f 100644 --- a/e2e/measurement-flow.spec.ts +++ b/e2e/measurement-flow.spec.ts @@ -74,7 +74,14 @@ test.describe("add measurement flow", () => { // Dashboard's analytics fetch — empty summaries are fine; we only // need the page to render so we can click "Add". - await page.route("**/api/analytics", (route) => + // + // v1.4.39.3 — match `/api/analytics` AND any sliced variant + // (`?slice=summaries`). The v1.4.39.2 dashboard split fires both + // requests in parallel; the previous string glob missed the slim + // variant which then fell through to the real route and slowed + // the page paint enough that the post-mutation list query never + // surfaced inside the 10 s window. + await page.route(/\/api\/analytics(\?|$)/, (route) => route.fulfill({ status: 200, contentType: "application/json", diff --git a/e2e/onboarding-tour-passthrough.spec.ts b/e2e/onboarding-tour-passthrough.spec.ts index 5e94b9237..558967f53 100644 --- a/e2e/onboarding-tour-passthrough.spec.ts +++ b/e2e/onboarding-tour-passthrough.spec.ts @@ -69,7 +69,9 @@ test.describe("v1.4.33 F2 — onboarding tour passes clicks through to the page" }), ); - await page.route("**/api/analytics", (route) => + // v1.4.39.3 — regex form matches the slim slice the v1.4.39.2 + // dashboard split fires alongside the thick request. + await page.route(/\/api\/analytics(\?|$)/, (route) => route.fulfill({ status: 200, contentType: "application/json", diff --git a/e2e/v1427-coach-launch.spec.ts b/e2e/v1427-coach-launch.spec.ts index 71b667f1f..1baae5fb9 100644 --- a/e2e/v1427-coach-launch.spec.ts +++ b/e2e/v1427-coach-launch.spec.ts @@ -31,7 +31,9 @@ test.describe("v1.4.27 — Coach reachability on insights sub-pages", () => { // Populated analytics so each sub-page paints the data branch // (`hasMetricData` true) — the Coach button is mounted at the // bottom of the data tree. - await page.route("**/api/analytics", (route) => + // v1.4.39.3 — regex form matches the slim slice the v1.4.39.2 + // dashboard split fires alongside the thick request. + await page.route(/\/api\/analytics(\?|$)/, (route) => route.fulfill({ status: 200, contentType: "application/json", diff --git a/e2e/v1427-insights-empty-state.spec.ts b/e2e/v1427-insights-empty-state.spec.ts index a3f51915f..cd30003cf 100644 --- a/e2e/v1427-insights-empty-state.spec.ts +++ b/e2e/v1427-insights-empty-state.spec.ts @@ -24,7 +24,9 @@ test.describe("v1.4.27 — insights empty-state with metric gating", () => { test.beforeEach(async ({ page }) => { // Zero-count summaries — every gated sub-page short-circuits to // its EmptyState branch. - await page.route("**/api/analytics", (route) => + // v1.4.39.3 — regex form matches the slim slice the v1.4.39.2 + // dashboard split fires alongside the thick request. + await page.route(/\/api\/analytics(\?|$)/, (route) => route.fulfill({ status: 200, contentType: "application/json", diff --git a/e2e/v1427-measurements-add-param.spec.ts b/e2e/v1427-measurements-add-param.spec.ts index 41d7321c6..e208345e8 100644 --- a/e2e/v1427-measurements-add-param.spec.ts +++ b/e2e/v1427-measurements-add-param.spec.ts @@ -25,7 +25,9 @@ test.describe("v1.4.27 — /measurements?add= consumer", () => { test.use({ storageState: STORAGE_STATE_PATH }); test.beforeEach(async ({ page }) => { - await page.route("**/api/analytics", (route) => + // v1.4.39.3 — regex form matches the slim slice the v1.4.39.2 + // dashboard split fires alongside the thick request. + await page.route(/\/api\/analytics(\?|$)/, (route) => route.fulfill({ status: 200, contentType: "application/json", diff --git a/e2e/v1427-responsive-sheet.spec.ts b/e2e/v1427-responsive-sheet.spec.ts index 90a83edcc..b3e83e391 100644 --- a/e2e/v1427-responsive-sheet.spec.ts +++ b/e2e/v1427-responsive-sheet.spec.ts @@ -22,7 +22,9 @@ test.describe("v1.4.27 — ResponsiveSheet branch", () => { test.beforeEach(async ({ page }) => { // Empty analytics + list keeps the page fast and deterministic. - await page.route("**/api/analytics", (route) => + // v1.4.39.3 — regex form matches `/api/analytics` AND any sliced + // variant (`?slice=summaries`) the v1.4.39.2 dashboard split fires. + await page.route(/\/api\/analytics(\?|$)/, (route) => route.fulfill({ status: 200, contentType: "application/json",