import React from "react"; (globalThis as Record).React = React; import { renderToStaticMarkup } from "react-dom/server"; import { describe, it } from "node:test"; import assert from "node:assert/strict"; import { CoverageMenuBody, CoverageRingDetail, CoverageRingGlyph, ringFill, type SessionCoverage, } from "../components/extraction-coverage.tsx"; /** * The extraction-coverage surfaces (extraction-UX redesign, owner-locked * dispatch 2026-09-24): the sidebar context-menu block (numbers + the * manual Extract affordance) and the chat top bar's ring meter. The pure * folds and the presentational bodies are pinned here; the live fetch * chains (menu-open read, the 2s running poll, the turn-settle bump, the * settings signal) are Playwright's beat. */ function coverage(over: Partial = {}): SessionCoverage { return { totalMessages: 12, coveredCount: 7, uncoveredCount: 5, coveredTokens: 30_000, uncoveredTokens: 2_048, running: false, lastFoldedAt: null, ...over, }; } describe("ringFill (the donut's fold, pure)", () => { it("fills uncovered/chunk, clamped to [0,1]", () => { assert.equal(ringFill(0, 4096), 0); assert.equal(ringFill(2048, 4096), 0.5); assert.equal(ringFill(4096, 4096), 1); assert.equal(ringFill(999_999, 4096), 1, "past the threshold reads full, never >1"); }); it("a non-positive threshold reads zero (never NaN, never a fake full)", () => { assert.equal(ringFill(2048, 0), 0); assert.equal(ringFill(2048, -5), 0); }); }); describe("CoverageMenuBody — the context-menu block", () => { it("renders the uncovered numbers + the Extract affordance", () => { const html = renderToStaticMarkup( {}} />, ); assert.ok(html.includes('data-testid="ctx-coverage"'), "the block carries its testid"); assert.match(html, /2k uncovered/); assert.match(html, /5 messages unextracted/); assert.ok(html.includes('data-testid="ctx-extract"'), "the Extract affordance"); assert.ok(!html.includes('disabled=""'), "an uncovered session can extract (the disabled: utilities alone don't count)"); }); it("fully extracted: the quiet line, Extract disabled (never a fake run)", () => { const html = renderToStaticMarkup( {}} />, ); assert.match(html, /fully extracted/); assert.ok(html.includes("disabled"), "nothing to run — the button rests"); }); it("running: the pulse line + 'Running', not the numbers (motion is the state)", () => { const html = renderToStaticMarkup( {}} />, ); assert.ok(html.includes('data-testid="ctx-coverage-running"')); assert.match(html, /extracting…/); assert.ok(html.includes(">Running"), "the affordance reads Running while in flight"); assert.ok(html.includes("disabled"), "no double-fire"); }); it("optimistic (click-pending, server not yet saying running): same running shape", () => { const html = renderToStaticMarkup( {}} />, ); assert.ok(html.includes('data-testid="ctx-coverage-running"'), "the optimistic state shows at once"); assert.match(html, />Running { it("half fill: the arc covers half the circumference", () => { const html = renderToStaticMarkup(); const C = 2 * Math.PI * 6; assert.ok(html.includes(`stroke-dasharray="${0.5 * C} ${C}"`), "fill = uncovered share of the ring"); assert.ok(html.includes("rotate(-90"), "the arc starts at 12 o'clock"); assert.ok(!html.includes("animate-pulse"), "steady state is still"); }); it("empty fill renders the bare track (no arc beyond a hairline)", () => { const html = renderToStaticMarkup(); const C = 2 * Math.PI * 6; assert.ok(html.includes(`stroke-dasharray="0 ${C}"`)); }); it("running: the whole ring pulses (motion = the working-state signal)", () => { const html = renderToStaticMarkup(); assert.ok(html.includes("animate-pulse"), "the implementer's visual call: pulse, not a spinner"); }); }); describe("CoverageRingDetail — the popover's exact numbers", () => { it("carries covered/uncovered tokens, messages, the threshold, the last fold", () => { const html = renderToStaticMarkup( , ); assert.match(html, /Uncovered.*2k tokens/s); assert.match(html, /Covered.*30k tokens/s); assert.match(html, /7 \/ 12/); assert.match(html, /Chunk threshold.*4\.1k tokens/s); assert.match(html, /Last extraction/); assert.ok(!html.includes('data-testid="coverage-ring-running"'), "idle: no status line"); }); it("no fold yet renders '—' (never a fake timestamp)", () => { const html = renderToStaticMarkup(); assert.match(html, /Last extraction.*—/s); }); it("running: the extracting… status line", () => { const html = renderToStaticMarkup( , ); assert.ok(html.includes('data-testid="coverage-ring-running"')); assert.match(html, /extracting…/); }); });