From 85ca9fe461f3276a1e0ddcd4491ad4660e24894e Mon Sep 17 00:00:00 2001 From: gsxdsm Date: Thu, 30 Jul 2026 18:09:20 -0700 Subject: [PATCH] =?UTF-8?q?fix(tests):=20agent-detail=20mobile=20padding?= =?UTF-8?q?=20=E2=80=94=20jsdom=20cannot=20compute=20an=20unparsed=20short?= =?UTF-8?q?hand=20(#2910)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## The last failure in `app:backfill 1/4` ``` AgentDetailView mobile scroll regression (FN-4231) > adds mobile row gaps to the overview hero for long health and skills metadata (FN-7958) AssertionError: expected '0' to be 'var(--space-md)' ``` **Not a style regression — the CSS is unchanged.** jsdom does not substitute `var()`, and what it does *instead* changed at the **27 → 29** bump (`4819c2634`): a directly-declared **longhand** still echoes its raw text, while a **shorthand** fails to parse and computes to the initial value. Same cause as the TaskCard failures fixed in #2782. **The asymmetry is visible three lines above the failure** — `rowGap` and `columnGap` assert the same kind of token and still pass, because they are declared as longhands. Only `padding` broke, which is why this read as a one-property regression rather than a jsdom behaviour change. ## `paddingTop` does not rescue it That was my first attempt, and it still returns `'0'` — measured, not assumed. jsdom cannot derive a longhand from a shorthand it failed to parse, so **computed style cannot answer this at all**. ## The fix Assert the **declared rule**, which is the pattern this file already uses for its desktop counterpart: ```ts expect(loadAllAppCssBaseOnly()).toContain("padding: var(--space-md) calc(...);"); ``` One difference that matters: the **full** sheet is needed rather than the base-only one. This padding is a mobile override inside `@media (max-width: 480px)` (`AgentDetailView.css:2129-2131`), and `loadAllAppCssBaseOnly` strips at-rules by design — so the obvious copy of the neighbouring assertion would have silently matched nothing. ## Evidence | | result | |---|---| | the file | **7/7** (was 1 failed) | | mutation: mobile card padding `md → xl` | **1 failed** | The mutation is the important one here: a regex that merely found the `@media` block would pass regardless. It tracks the actual declaration. `pnpm lint` clean. Test-only; `AgentDetailView.css` restored clean. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 5 (1M context) --- .../AgentDetailView.mobile-scroll.test.tsx | 25 ++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/packages/dashboard/app/components/__tests__/AgentDetailView.mobile-scroll.test.tsx b/packages/dashboard/app/components/__tests__/AgentDetailView.mobile-scroll.test.tsx index f1a68cf35a..642f42d2d5 100644 --- a/packages/dashboard/app/components/__tests__/AgentDetailView.mobile-scroll.test.tsx +++ b/packages/dashboard/app/components/__tests__/AgentDetailView.mobile-scroll.test.tsx @@ -215,7 +215,30 @@ describe("AgentDetailView mobile scroll regression (FN-4231)", () => { expect(metaStyle.flexWrap).toBe("wrap"); expect(metaStyle.rowGap).toBe("var(--space-lg)"); expect(metaStyle.columnGap).toBe("var(--space-sm)"); - expect(cardStyle.padding).toBe("var(--space-md)"); + /* + FNXC:AgentDetailMobile 2026-07-31-19:15: + DECLARED, NOT COMPUTED — jsdom cannot answer this one at all. + + This read `getComputedStyle(card).padding` and expected the raw token text. jsdom does not + substitute `var()`, and what it does INSTEAD changed at the 27 -> 29 bump (4819c2634): a + directly-declared LONGHAND still echoes its raw text, but a SHORTHAND fails to parse and + computes to the initial value. Hence `expected '0' to be 'var(--space-md)'` with the CSS + untouched. Same cause as the TaskCard failures fixed in #2782. + + The asymmetry is visible three lines up: `rowGap` and `columnGap` are declared as longhands and + still pass against the same kind of token. `paddingTop` does NOT rescue it — measured — because + jsdom cannot derive a longhand from a shorthand it failed to parse. + + So the declared rule is asserted instead, which is what this file already does for the desktop + counterpart above (`expect(loadAllAppCssBaseOnly()).toContain("padding: ...")`). The full sheet + is needed rather than the base-only one: this padding is a MOBILE override inside + `@media (max-width: 480px)` (AgentDetailView.css:2129-2131), and `loadAllAppCssBaseOnly` strips + at-rules by design. + */ + expect(loadAllAppCss()).toContain("@media (max-width: 480px)"); + expect(loadAllAppCss()).toMatch( + /@media \(max-width: 480px\)[\s\S]*?\.dashboard-summary-card\s*\{[^}]*padding:\s*var\(--space-md\);/, + ); expect(healthStyle.overflowWrap).toBe("anywhere"); expect(screen.getAllByText(/Paused: heartbeat-model-unavailable/).length).toBeGreaterThanOrEqual(1); if (metadata.skills.length > 0) {