* test(cli,tui): add in-process source coverage gates (#1484) CLI and TUI source had no coverage gate: CLI tests spawned the built binary out-of-process (coverage never saw clients/cli/src) and the TUI had only two smoke tests. Regressions there were invisible to CI. CLI: - Rewrite __tests__/helpers/cli-runner.ts to invoke runCli() in-process (capture process.std*.write, map thrown errors to an exit code), preserving the CliResult shape so all existing tests run unchanged and clients/cli/src is now measured under v8 instrumentation. - cli.ts: program.exitOverride() so a commander usage error throws (catchable in-process) instead of tearing down the worker; --help / --version still exit cleanly. Drop the dead, never-imported main(). - Add a thin out-of-process e2e.test.ts that spawns the built binary for the shebang / process.exit paths the in-process runner can't reach. - Add @vitest/coverage-v8, a per-file gate (90/85/80/50) excluding only src/index.ts (binary bootstrap), and pool: 'forks' for capture isolation. cli.ts lands at ~98% lines / 100% functions. TUI: - Add @vitest/coverage-v8 and an interim per-file gate over the non-React logic (logger.ts, components/tabsConfig.ts, utils/*); the Ink components, App.tsx, and hooks/ are excluded with a documented follow-up (#1501). Add tests covering the included modules (100%). Wiring + docs: - CI runs each client's test:coverage; root test:cli / test:tui (used by validate) and root test:coverage now enforce the gates. - gitignore clients/**/coverage; update AGENTS.md and client READMEs. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(cli): clarify in-process runner footguns from PR #1502 review Review notes on the in-process CLI test runner (no behavior change): - Warn in runCli's docblock that --help/--version must NOT go through the in-process runner: exitOverride only re-throws non-zero exits, so exitCode 0 falls through to process.exit(0) and would kill the vitest worker. Those belong in the out-of-process e2e.test.ts layer. - Document that a timeout orphans the uncancellable invokeCli promise (its stdio subprocess stays alive; later writes hit the restored stdout) — a known, acceptable trade-off on the hang-only failure path. - Fix a stale reference to the removed main() (errors now route through index.ts). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(cli): fix remaining stale main() reference in vitest exclusion comment PR #1502 re-review caught a second stale `main()` mention (the first was fixed in 52c23e41). src/index.ts inlines the bootstrap as runCli(process.argv).then(...).catch(handleError) — there is no main(). Comment-only; no behavior change. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * chore: compose root test:coverage from per-client scripts Replace the brittle inline cd-chain with a composition of the existing test:cli / test:tui scripts plus a new matching test:web. Behavior is unchanged (web → cli → tui coverage gates) but there's a single source of truth for each client's coverage invocation. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
53 lines
2.2 KiB
TypeScript
53 lines
2.2 KiB
TypeScript
import path from 'node:path';
|
|
import { fileURLToPath } from 'node:url';
|
|
import { defineConfig } from 'vitest/config';
|
|
import { vitestSharedPaths } from '../../vitest.shared.mts';
|
|
|
|
const dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
const { projectResolve } = vitestSharedPaths(dirname);
|
|
|
|
export default defineConfig({
|
|
resolve: projectResolve,
|
|
test: {
|
|
globals: false,
|
|
environment: 'node',
|
|
include: ['__tests__/**/*.test.ts'],
|
|
coverage: {
|
|
provider: 'v8',
|
|
reporter: ['text', 'html', 'json-summary'],
|
|
// INTERIM SCOPE (#1484). The TUI's UI is ~16 Ink/React components plus a
|
|
// 1878-line App.tsx that need an Ink renderer (ink-testing-library) to
|
|
// exercise — a large, separate effort tracked in its own follow-up issue.
|
|
// For now the gate covers the feasibly-unit-testable, non-React logic:
|
|
// server resolution (tui-servers.ts), the file logger (logger.ts), the
|
|
// tab metadata (components/tabsConfig.ts), and the form/URL helpers
|
|
// (utils/*). New non-React logic added under src/ is automatically held
|
|
// to the gate; the React surface is explicitly excluded below until the
|
|
// component-coverage follow-up (#1501) lands.
|
|
include: ['src/**/*.{ts,tsx}'],
|
|
exclude: [
|
|
// Pure re-export + type alias of core's server resolver (no runtime
|
|
// statements of its own — the logic is measured in core via the web
|
|
// suite). tui-servers.test.ts still exercises it behaviorally; it's
|
|
// excluded here only so it doesn't surface as a misleading 0/0 row.
|
|
'src/tui-servers.ts',
|
|
'src/App.tsx',
|
|
// All Ink components (*.tsx). The sibling tabsConfig.ts (plain data,
|
|
// no JSX) stays in scope because this only excludes .tsx files.
|
|
'src/components/**/*.tsx',
|
|
// useSelectableList is a React hook — needs a renderer like the
|
|
// components above. Folded into the interim React exclusion.
|
|
'src/hooks/**',
|
|
'**/*.test.ts',
|
|
'**/*.d.ts',
|
|
],
|
|
thresholds: {
|
|
perFile: true,
|
|
lines: 90,
|
|
statements: 85,
|
|
functions: 80,
|
|
branches: 50,
|
|
},
|
|
},
|
|
},
|
|
});
|