test(ui): fix 3 pre-existing failures — match deliberate design changes

Three test failures had accumulated since the iter-30/iter-32 design
iterations. Each fix follows the dispatch rule: prefer fixing the code
when the test describes intended product behavior, rewrite the test
only when the original assertion is genuinely stale. All three are the
latter — production behavior is the deliberate intent; tests captured
the rejected alternative.

1. p5-3-activity-ring-hot-potato.test.tsx — 'source scan keeps
   activity and packet layers production-reachable'
   Assertion: TopologyTableView source must match /group-hover:opacity-100/
   Root cause: slice 14 walk-item 16 deliberately REMOVED the
   hover-gated `opacity-0` + `group-hover:!opacity-100` chain from
   action-column buttons — operators kept missing the cmux launcher
   when it was hidden off-mouse. The comment at
   TopologyTableView.tsx:80-83 documents the removal.
   Fix: replace the hover-class match with a positive assertion that
   the cmux action button data-testid is present (the actual
   production-reachability claim).

2. p5-topology-terminal.test.tsx — 'globals.css honors
   prefers-reduced-motion for terminal-card-active'
   Assertion: a @media (prefers-reduced-motion: reduce) block must
   include .terminal-card-active.
   Root cause: TEST BUG, not code regression. globals.css has multiple
   reduced-motion blocks (one per animation cluster); .terminal-card-
   active IS inside one of them (line 539). The prior single-match
   regex picked the FIRST block (vellum-scroll-x only) and failed.
   Fix: scan ALL reduced-motion blocks via matchAll + Array.some;
   assert that any block contains .terminal-card-active.

3. p5-slice-scope.test.tsx — 'default landing tab is story; mounts
   TimelineTab with events + phaseDefinitions'
   Assertion: project-tab-story has data-active='true' on initial
   load.
   Root cause: slice 12 walk-item 1 deliberately changed the default
   tab from 'story' to 'overview' so the first thing the operator
   sees on a slice is its README (current step + readiness), not a
   metric grid. The comment at ScopePages.tsx:1189-1192 documents
   the rationale.
   Fix: rename the test + assert overview is the default; verify
   story tab still activates TimelineTab when clicked (preserved
   coverage of the navigation path).

Verification:
- Each test file: green individually
- Full UI suite: 112 files / 1106 passing / 1 skipped / 0 failures
  (was 1093 passing + 3 failing on baseline; +13 net green, no new
  failures uncovered)
- tsc --noEmit: clean on touched files

Each fix carries an inline comment with the slice + walk-item that
made the design change, so future archeology stays cheap.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
This commit is contained in:
mvschwarzandClaude Opus 4.7 committed 2026-05-14 22:23:34 -07:00
1 parent 72b0a910ec
commit 1e0152f0ee
3 files changed
+32 -8

No files matched your search

@@ -311,7 +311,13 @@ describe("P5.3 ActivityRing and HotPotatoEdge", () => {
expect(css).not.toMatch(/background-color: rgba\(255, 255, 255, 0\.96\)/);
expect(rigGraph).toMatch(/activityRing/);
expect(table).toMatch(/ActivityRing/);
expect(table).toMatch(/group-hover:opacity-100/);
// 0.3.1 slice 14 walk-item 16 deliberately removed the hover-
// gated `opacity-0` + `group-hover:opacity-100` pattern from
// action-column buttons — operators kept missing the cmux
// launcher when it was hidden off-mouse. The test now asserts
// the action button is wired in (data-testid present) instead
// of asserting the rejected hover-reveal chain.
expect(table).toMatch(/data-testid=\{`topology-table-cmux-/);
expect(ring).not.toMatch(/StatusPip/);
expect(edge).toMatch(/animateMotion/);
expect(activity).toMatch(/TOPOLOGY_NODE_ACTIVITY_TTL_MS/);
+13 -4
View File
@@ -149,16 +149,25 @@ describe("SliceScopePage P5-2 tab content piping", () => {
expect(await findByTestId("slice-scope-error")).toBeTruthy();
});
it("default landing tab is 'story'; mounts TimelineTab with events + phaseDefinitions", async () => {
it("default landing tab is 'overview' (slice 12 walk-item 1: README before metric grid); story tab still mounts TimelineTab when activated", async () => {
const { container, findByTestId } = renderSliceScope({
sliceId: "idea-ledger",
detail: makeDetail(),
});
// ScopeShell mounts; project-tab-nav rendered.
await findByTestId("project-tab-nav");
// Story is the default active tab.
const storyTab = container.querySelector("[data-testid='project-tab-story']");
expect(storyTab?.getAttribute("data-active")).toBe("true");
// V0.3.1 slice 12 walk-item 1 — default tab was changed from
// 'story' to 'overview' so the first thing the operator sees on
// a slice is its README (current step + readiness), not a metric
// grid. Test now reflects the deliberate landing-tab choice.
const overviewTab = container.querySelector("[data-testid='project-tab-overview']");
const storyTabBefore = container.querySelector("[data-testid='project-tab-story']");
expect(overviewTab?.getAttribute("data-active")).toBe("true");
expect(storyTabBefore?.getAttribute("data-active")).toBe("false");
// Clicking the story tab still activates the TimelineTab panel.
fireEvent.click(storyTabBefore!);
const storyTabAfter = container.querySelector("[data-testid='project-tab-story']");
expect(storyTabAfter?.getAttribute("data-active")).toBe("true");
});
it("progress tab mounts AcceptanceTab (FOLDED per code-map)", async () => {
+12 -3
View File
@@ -272,8 +272,17 @@ describe("globals.css pulsing-ring CSS contract (ritual #7 pseudo-element-paint)
const src = readFileSync(cssPath, "utf8");
// Reduced-motion block must include .terminal-card-active so the pulse
// animation is suppressed for users with motion-sensitivity preferences.
const reducedMotion = src.match(/@media \(prefers-reduced-motion: reduce\)\s*\{[\s\S]*?\}\s*\}/);
expect(reducedMotion).not.toBeNull();
expect(reducedMotion![0]).toMatch(/\.terminal-card-active/);
//
// globals.css has multiple @media (prefers-reduced-motion: reduce)
// blocks (one per animation cluster — vellum drift, activity rings,
// terminal cards, etc). Scan ALL of them — the prior single-match
// regex picked the first block (vellum-scroll-x) which doesn't
// include .terminal-card-active even though a later block does.
const blocks = Array.from(
src.matchAll(/@media \(prefers-reduced-motion: reduce\)\s*\{[\s\S]*?\}\s*\}/g),
);
expect(blocks.length).toBeGreaterThan(0);
const anyBlockHasTerminal = blocks.some((m) => /\.terminal-card-active/.test(m[0]));
expect(anyBlockHasTerminal).toBe(true);
});
});