render() never set `interactive`, so the runtime derived it as
`!isInCi && Boolean(stdout.isTTY)`. `is-in-ci` is evaluated once at module
import, so consumers running @vue-tui/testing in CI silently got a
non-interactive app: `terminal.resize()` emitted but never re-laid-out (the
resize handler is registered only when interactive), and the lifetime
raw-mode hold never engaged (`terminal.rawMode.current` stayed false) —
breaking both APIs the README advertises.
Pin `interactive: options.interactive ?? true` in the mount options so the
harness is deterministic and independent of ambient CI/TTY detection, and
expose `interactive?: boolean` on RenderOptions so non-interactive behavior
stays testable. Runtime behavior is unchanged.
Add a subprocess test (runtime-tests, sequential — depends on the
process-global CI env baked into the child at import time) that spawns the
BUILT dist with CI=true vs CI=false, renders a bordered Box that fills the
columns, resizes 40→12, and asserts the re-layout happened and raw mode is
held. It fails on origin/main (resize ignored under CI=true) and passes with
the fix.
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Fifth CI run failed on ~15 resize/throttle/flush tests that pass locally. Root
cause: the GitHub runner sets CI=true, and vue-tui computes
`interactive = !isInCi && isTTY`. With CI=true, interactive is false, so the
resize listener, cursor control, and ANSI erases are never wired up — exactly
the behavior those tests assert. Locally CI is unset, so they passed (the
local-vs-CI trap, reproducible with `CI=true vp test run`).
Set env CI:"false" in both vitest configs. The PTY child helpers already force
CI=false per-spawn for this reason; the in-process suite (and the testing
harness's render()) needs the same. Verified: `CI=true vp run ci` on a fresh
checkout (no dist) now exits 0 with all 756 + 110 tests passing.
The fourth CI run failed broadly: ~15 timing-sensitive tests (throttle, flush,
resize clear-counts, rapid-input ordering) failed under sequence.concurrent on
the 4-core ubuntu runner. These assert render/commit counts driven by the
~32ms commit throttle; in-file concurrency starves them of wall-clock when many
share few cores. It passed locally only because dev machines have more cores —
the classic "works on my 12-core mac" trap.
Remove sequence.concurrent from both the main and PTY configs; keep
fileParallelism (pool: forks), which is the proven, stable win (PTY suite still
~3x faster than serial). The it.sequential/describe.sequential markers and
context-local expect become harmless no-ops under serial in-file execution.
Verified cold (no dist): vp run ci exits 0, 0 lint warnings, all tests pass.
Enable sequence.concurrent: true in vite.config.ts so the non-PTY suite runs
concurrently like the PTY suite. Stress-verified stable (8/8 at maxForks=4);
the suite drops from ~13s to ~4-5s.
Three test patterns were incompatible with concurrency; handled per cause:
- Inline snapshots (background-color, borders): the module-level `expect`
loses snapshot test context under concurrency. Fixed in place by using the
context-local `expect` (async ({ expect }) => ...), so they stay concurrent.
- Process-global state (throttle/animation-scheduler use fake timers; leak
asserts on process exit/SIGINT listener counts and live yoga nodes): a
concurrent sibling clobbers the shared global mid-test. These genuinely
require serial execution, so they move to *.sequential.test.* files with
it.sequential / describe.sequential and a header explaining why.
`vp run ready` passes.
The PTY suite now runs file-parallel (see vitest.pty.config.ts), so the comment
claiming "no parallelism" was wrong. The real constraint is node-pty's forks
pool, not serial execution.
The root vite.config.ts lint/fmt settings cascade into every workspace
package, and a package-level lint block merges with — rather than replaces —
the root options. So the `lint.options { typeAware, typeCheck }` and the empty
`fmt: {}` repeated in runtime, testing, and runtime-tests only restated what
each package already inherits.
Remove them. runtime-tests keeps just its `ignorePatterns` (the one genuine
per-package override); typeAware/typeCheck now come from root via the merge.
Verified with `vp check`: no lint or typecheck regression, and the PTY
fixtures stay excluded from lint.
`lint.exclude` is not a property of OxlintConfig (the correct key is
`ignorePatterns`). The invalid property failed defineConfig overload
resolution, which surfaced as a TS2769 plus a TS2321 excessive-stack-depth
error against the recursive vitest-augmented UserConfig. Using
`ignorePatterns` excludes the PTY fixtures from lint as intended and clears
both config type errors.
Fixture files use jsx: react-jsx (via their own tsconfig) and have
expected children type differences. Exclude from package-level checks.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Ink tests use chalk level 3 (24-bit) for hex/rgb/ansi256 colors.
Level 1 (basic 16-color) caused different ANSI codes than expected.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Tests must exercise the same ANSI code paths users see. Without
FORCE_COLOR, chalk disables all color in non-TTY test environments,
making style bugs invisible to the test suite.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
21 test files covering components, composables, focus, lifecycle,
and scheduler through the public render() API.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>