Skip to content

test(tui): extend coverage gate to Ink components + App.tsx (closes #1501)#1538

Open
cliffhall wants to merge 8 commits into
v2/mainfrom
tui/1501-ink-component-coverage
Open

test(tui): extend coverage gate to Ink components + App.tsx (closes #1501)#1538
cliffhall wants to merge 8 commits into
v2/mainfrom
tui/1501-ink-component-coverage

Conversation

@cliffhall

Copy link
Copy Markdown
Member

Closes #1501.

Summary

Lifts the interim React-surface coverage exclusion in the TUI client (the follow-up to #1484 / #1532). The whole clients/tui/src tree now clears the uniform 90/90/90/90 per-file gate with no React-surface exclusions — App.tsx, every Ink component, and the useSelectableList hook are all exercised under coverage.

Test-only change: no source files were modified.

How it's tested

Added ink-testing-library and renderer-based tests that mount components in-process and drive keypresses through stdin. Two shared passthrough doubles in __tests__/helpers/ make the components mountable under the non-TTY test renderer:

  • inkScrollViewMock.tsx — the real ScrollView renders a placeholder minimap and never mounts its children in a non-TTY env; the double renders children directly and stubs the imperative ref API (scrollBy/scrollTo/getViewportHeight).
  • inkFormMock.tsx — the real ink-form Form is hard to drive field-by-field; the double fires onSubmit on Enter.

Per-component approach:

  • Tabs + hook (Info/Auth/Resources/Prompts/Tools/Notifications/History/Requests, useSelectableList, SelectableItem, Tabs): assert on rendered frame text and drive list navigation / scroll keys.
  • Modals (Tool/Resource/Prompt test modals, DetailsModal): these render position="absolute", which produces an empty frame under the renderer, so their tests assert on behavior — injected InspectorClient fakes being called, onClose, and state transitions — while the passthrough ScrollView still mounts the inner JSX for coverage.
  • App.tsx (~1885 lines): mounts against a controllable mock of the entire @inspector/core surface (InspectorClient, the 7 managed-state classes, the 8 react hooks, transport, auth) plus the callback server. 67 tests drive the keyboard state machine, per-tab content, modal-open flows, OAuth (guided/quick/clear, success + error), and connect/disconnect. Each render is unmounted in afterEach (concurrent ink mounts share raw-mode stdin and interfere with useInput).

Verification

  • clients/tui npm run validate — clean (format / lint / build / test).
  • clients/tui npm run test:coveragegreen, 260 tests, every file ≥90 on all four dimensions, no ERROR lines. App.tsx: 94.6 stmts / 90.6 branch / 94.5 funcs / 96.6 lines.

Config

clients/tui/vitest.config.ts: removed all React-surface entries from the coverage exclude (only the pure re-export tui-servers.ts and test/type globs remain) and widened the include glob to *.test.tsx. The interim-scope comment from #1484 is updated to reflect the completed lift.

🤖 Generated with Claude Code

cliffhall and others added 7 commits June 27, 2026 17:34
Add ink-testing-library and renderer-based tests for useSelectableList,
SelectableItem, and Tabs. Widen the vitest include glob to .test.tsx and
lift these files from the interim React-surface coverage exclusion. The
blanket src/components/**/*.tsx exclude is expanded into an explicit
per-file list so remaining components can be lifted incrementally.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…1501)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…1501)

Add ink-testing-library tests for the 12 Ink components (InfoTab, AuthTab,
ResourcesTab, PromptsTab, ToolsTab, NotificationsTab, HistoryTab,
RequestsTab, and the Tool/Resource/Prompt test modals + DetailsModal),
mounting them through the ink-scroll-view / ink-form passthrough doubles
and driving keypresses via stdin. Modal components render position:absolute
(empty frame under the test renderer) so their tests assert on behavior —
injected InspectorClient fakes and onClose — while the passthrough
ScrollView still mounts the inner JSX for coverage.

Lift these 12 components from the interim React-surface exclusion in
vitest.config.ts; only App.tsx remains excluded. All files clear the
uniform 90/90/90/90 per-file gate.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Mock the full @inspector/core surface (InspectorClient, the 7 managed-state
classes, the 8 react hooks, transport + auth) behind a controllable harness,
plus the ink-scroll-view/ink-form passthroughs, so App renders under
ink-testing-library and its keyboard state machine can be driven via stdin.
Concurrent ink mounts share raw-mode stdin, so each render is unmounted in
afterEach. Foundation covers server-list nav, tab accelerators, connect/
disconnect, OAuth-tab gating, and connected-status rendering (~50% baseline).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…xclusion (#1501)

Extend App.test.tsx to 67 tests driving the keyboard state machine, tab
content, modals, OAuth flows, and connect/disconnect across the controllable
@inspector/core mock. App.tsx now clears the 90/90/90/90 per-file gate
(94.6/90.6/94.5/96.6).

Remove the last React-surface exclusion (src/App.tsx) from
clients/tui/vitest.config.ts. The whole clients/tui/src tree is now under
the uniform per-file coverage gate with no React-surface exclusions,
completing the interim-scope lift from #1484.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…1501)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@cliffhall cliffhall added the v2 Issues and PRs for v2 label Jun 27, 2026
@cliffhall cliffhall linked an issue Jun 28, 2026 that may be closed by this pull request
3 tasks
…ns (#1501)

Add targeted App.tsx tests for the OAuth handlers' non-Error throw arms
(quick onCallback, guided start/advance, run-to-completion) and a re-entrant
quick-auth guard, lifting App.tsx branch coverage 90.6% -> 91.48% for a
safer margin above the 90 gate.

Harden the App renderer tests against the heavier v8 coverage instrumentation,
where React+ink's multi-macrotask render scheduling races fixed ticks:
- press() now settles two ticks per key so focus/tab changes flush before the
  next key is routed (ink re-subscribes useInput on re-render);
- expectFrame()/waitUntil() poll for frame content and async flow state
  (callbackServer opts) instead of asserting after a single fixed tick;
- ResourcesTab's content-clear test polls for fetched content likewise.

Plain 'npm test' (the CI path) was already stable; this makes the local
coverage gate stable too (13/13 clean runs vs ~2/8 flaky before).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@cliffhall

Copy link
Copy Markdown
Member Author

Follow-up: bumped App.tsx branch coverage from 90.6% → 91.48% for a safer margin above the 90 gate — added tests for the OAuth handlers' non-Error throw arms (quick onCallback, guided start/advance, run-to-completion) and a re-entrant quick-auth guard.

Also hardened the App renderer tests against the heavier v8 coverage instrumentation (where React+ink's multi-macrotask render scheduling races fixed ticks): press() now settles two ticks per key, and frame/async-state assertions poll via expectFrame/waitUntil instead of asserting after a single tick. Plain npm test (the CI path) was already stable; this makes the local coverage gate stable too — 13/13 clean runs vs ~2/8 flaky before.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

v2 Issues and PRs for v2

Projects

None yet

Development

Successfully merging this pull request may close these issues.

TUI: extend coverage gate to Ink components (lift interim exclusion)

1 participant