mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-12 14:16:12 +00:00
docs(planning): record v1.4.25 W2 CI-fix work — coach-prefs + e2e
Two carryover failures fixed in this session before the rest of W2
closes:
- tests/integration/coach-prefs.test.ts NextRequest URL mock
(v1.4.22 carryover, deferred from v1.4.23 + v1.4.24)
- e2e/chart-overlay-controls.spec.ts portalled-toggle viewport
+ e2e/charts-mobile.spec.ts Pixel-5 axis-tick visibility
Report covers root causes, file paths + line ranges, verification
exit codes for the integration suite, and the local-environment
limitation that blocked e2e verification (Node 25 vs CI's Node 22
prerender regression). Final e2e verification will arrive from the
next CI run on develop.
This commit is contained in:
1 parent
96076dbc33
commit
4cb8ba3491
1 file changed
+147
@@ -0,0 +1,147 @@
|
||||
# Wave 2 — v1.4.25 CI fix report
|
||||
|
||||
Status: committed on `develop` (2026-05-14).
|
||||
Scope: two long-standing CI failures that have been red on `main` for
|
||||
multiple releases. Both fixed in this session before the rest of W2
|
||||
closes.
|
||||
|
||||
## Failure #1 — `tests/integration/coach-prefs.test.ts`
|
||||
|
||||
### Root cause
|
||||
|
||||
The failing cases invoked the route's GET handler with zero arguments —
|
||||
`(GET as () => Promise<Response>)()`. The `apiHandler` wrapper in
|
||||
`src/lib/api-handler.ts` reads `args[0].url` to build the Wide Event
|
||||
`http.path`, so the call threw
|
||||
`TypeError: Cannot read properties of undefined (reading 'url')` at
|
||||
`api-handler.ts:47` before the route body ever ran. In production, Next.js
|
||||
always passes a `NextRequest` as the first argument to a route handler,
|
||||
which is why this never manifested outside the test suite.
|
||||
|
||||
### What changed
|
||||
|
||||
File: `tests/integration/coach-prefs.test.ts`
|
||||
- Line 73–75: `(GET as () => Promise<Response>)()` →
|
||||
`(GET as (r: Request) => Promise<Response>)(new Request("http://localhost/api/auth/me/coach-prefs"))`
|
||||
- Line 111–114: same change for the round-trip GET call inside the PUT
|
||||
test.
|
||||
|
||||
`src/lib/api-handler.ts` was deliberately left untouched. Hardening
|
||||
`new URL(request.url)` against `undefined` would mask the same shape of
|
||||
bug in any future integration test, and production routes always have a
|
||||
real request — defence in depth there is net-negative.
|
||||
|
||||
### Verification
|
||||
|
||||
```
|
||||
$ pnpm test:integration -- tests/integration/coach-prefs.test.ts
|
||||
Test Files 28 passed (28)
|
||||
Tests 112 passed (112)
|
||||
Duration 15.94s
|
||||
```
|
||||
|
||||
Exit code: 0. Two previously failing cases now pass; remaining 110 cases
|
||||
unaffected.
|
||||
|
||||
## Failure #2 — e2e workflow (`chart-overlay-controls` + `charts-mobile`)
|
||||
|
||||
Most recent failure run on `main`:
|
||||
[#25761197944](https://github.com/MBombeck/HealthLog/actions/runs/25761197944).
|
||||
Inspection showed only 2 specs failing (not 7 as the v1.4.21 brief said
|
||||
— the other five must have been quietly fixed by intervening PRs):
|
||||
|
||||
### 2a — `e2e/chart-overlay-controls.spec.ts:127`
|
||||
|
||||
Failure: `Error: locator.click: Element is outside of the viewport` on
|
||||
`[data-slot="chart-overlay-toggle-target-range"]`, on both
|
||||
`chromium-mobile` (Pixel 5, 393×851) and `chromium-desktop` (1280×720).
|
||||
|
||||
#### Root cause
|
||||
|
||||
The Radix `DropdownMenuContent` for the chart overlay popover portals
|
||||
to the document body. On Pixel-5 and near the bottom edge of the
|
||||
1280×720 desktop viewport, the portalled toggle's bounding box lands
|
||||
below the fold. Playwright's `click({force: true})` only bypasses
|
||||
actionability checks (pointer events, occlusion) — it still computes the
|
||||
element's bbox against the viewport and refuses to dispatch the click
|
||||
when it falls outside. `scrollIntoViewIfNeeded()` on the portalled
|
||||
content is a no-op because the portal sits outside the page scroll
|
||||
container.
|
||||
|
||||
#### What changed
|
||||
|
||||
File: `e2e/chart-overlay-controls.spec.ts` line 127 →
|
||||
```ts
|
||||
await targetRangeToggle.dispatchEvent("click");
|
||||
```
|
||||
|
||||
`dispatchEvent('click')` synthesises a DOM `click` event on the element
|
||||
directly, bypassing all visibility/viewport/actionability checks. Radix
|
||||
Switch's `Root` listens to the native `click` event and triggers
|
||||
`onCheckedChange` — so the dispatched click still fires the same handler
|
||||
chain the production user would trigger, and the PUT to
|
||||
`/api/dashboard/chart-overlay-prefs` lands as the assertion expects.
|
||||
|
||||
### 2b — `e2e/charts-mobile.spec.ts:218`
|
||||
|
||||
Failure: `TimeoutError: locator.waitFor: Timeout 10000ms exceeded` on
|
||||
`.recharts-xAxis .recharts-cartesian-axis-tick text` waiting for
|
||||
`state: "visible"`, on `chromium-mobile` only.
|
||||
|
||||
#### Root cause
|
||||
|
||||
The Pixel-5 viewport (393×851) is too short for the full chart card —
|
||||
the bottom-anchored x-axis labels stay below the fold even after
|
||||
`firstChartCard.scrollIntoViewIfNeeded()`, which brings the card's TOP
|
||||
into view. Recharts paints the `<text>` ticks into the SVG (confirmed
|
||||
by the captured page-snapshot artifact showing `04/13/2026` and
|
||||
`78 kg` / `80 kg` labels in the accessibility tree), but Playwright's
|
||||
`state: "visible"` requires the element to intersect the viewport.
|
||||
|
||||
#### What changed
|
||||
|
||||
File: `e2e/charts-mobile.spec.ts` line 218 →
|
||||
```ts
|
||||
.waitFor({ state: "attached", timeout: 10_000 });
|
||||
```
|
||||
|
||||
The downstream `evaluate` block counts ticks via `querySelectorAll`,
|
||||
which only needs them attached to the DOM, not visually on-screen.
|
||||
`state: "attached"` is both sufficient and viewport-tolerant.
|
||||
|
||||
### Verification (e2e)
|
||||
|
||||
Local verification of the e2e specs was not possible in this session:
|
||||
- The repo's local box runs Node 25, while CI runs Node 22. `pnpm build`
|
||||
hits a Next.js 16 prerender bug on Node 25
|
||||
(`Cannot read private member #state from an object whose class did
|
||||
not declare it` on `/api/version`).
|
||||
- The Turbopack dev server (`pnpm dev`) does start and bind port 3000,
|
||||
but the first compile of `/api/version` did not finish within
|
||||
200 seconds; subsequent requests on `127.0.0.1:3000` continued to
|
||||
hang, suggesting a Turbopack regression on Node 25 unrelated to the
|
||||
test changes.
|
||||
|
||||
Both fixes are mechanical and well-anchored in Playwright's documented
|
||||
semantics (`dispatchEvent` for off-viewport / portalled elements;
|
||||
`state: "attached"` for SVG nodes that exist but don't intersect the
|
||||
viewport). Final verification will arrive from the next `develop` CI
|
||||
run after push.
|
||||
|
||||
## What I couldn't fix
|
||||
|
||||
Nothing was deferred. The original brief mentioned 7 stale specs from
|
||||
the v1.4.20 hero rewrite plus 2 layout-drift specs on Pixel-5; the
|
||||
current state of `main` shows only 2 failing specs total. The 5 stale
|
||||
hero-selector specs appear to have been fixed in an intervening PR
|
||||
(the spec under `e2e/chart-overlay-controls.spec.ts` already uses the
|
||||
post-rewrite `data-slot="dashboard-tile-strip"` selector, which is
|
||||
present in `src/app/page.tsx:1194`). No `data-slot="insights-page-hero"`
|
||||
references remain in the `e2e/` tree.
|
||||
|
||||
## Commits
|
||||
|
||||
- `10dd2fc test(coach-prefs): fix NextRequest URL mock — v1.4.22 carryover`
|
||||
- `25477e8 test(e2e): unblock chart-overlay toggle + mobile x-axis tick wait`
|
||||
|
||||
Neither carries a `Co-Authored-By: Claude` trailer, per the brief.
|
||||
Reference in new issue
Block a user