71e7d7e2f0
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>
40 lines
1.7 KiB
JavaScript
40 lines
1.7 KiB
JavaScript
// Subprocess fixture for testing-render-ci.sequential.test.ts.
|
|
//
|
|
// Imports the BUILT, PUBLISHED dist of @vue-tui/testing (the artifact consumers
|
|
// install) and exercises the two interactive-only APIs render() advertises:
|
|
// - terminal.resize() → layout-driven components must re-lay-out
|
|
// - terminal.rawMode → the lifetime raw-mode hold must engage
|
|
//
|
|
// The parent test spawns this with CI=true vs CI=false to prove render() pins
|
|
// `interactive` deterministically instead of inheriting the ambient CI/TTY-
|
|
// derived default (which silently disabled both APIs for consumers in CI).
|
|
//
|
|
// Plain ESM with h() (no JSX/tsx) so `node <file>` runs it directly, matching
|
|
// how the published consumer would call the dist.
|
|
import { render } from "@vue-tui/testing";
|
|
import { Box, Text } from "@vue-tui/runtime";
|
|
import { h } from "vue";
|
|
|
|
// Width of the box's top border line, ANSI-stripped. A bordered <Box> with no
|
|
// explicit width fills the terminal columns, so this tracks the laid-out width.
|
|
function topBorderWidth(frame) {
|
|
const line = (frame ?? "").split("\n").find((l) => l.includes("╭") || l.includes("┌")) ?? "";
|
|
// Control-char class is required to strip terminal SGR escapes byte-faithfully.
|
|
// eslint-disable-next-line no-control-regex
|
|
return line.replace(/\x1b\[[0-9;]*m/g, "").trim().length;
|
|
}
|
|
|
|
const App = () => h(Box, { borderStyle: "round" }, () => h(Text, () => "x"));
|
|
|
|
const r = await render(App, { columns: 40, rows: 10 });
|
|
const before = topBorderWidth(r.lastFrame());
|
|
|
|
await r.terminal.resize(12, 6);
|
|
const after = topBorderWidth(r.lastFrame());
|
|
|
|
// Single machine-readable line the parent test parses.
|
|
process.stdout.write(JSON.stringify({ before, after, rawMode: r.terminal.rawMode.current }) + "\n");
|
|
|
|
r.unmount();
|
|
process.exit(0);
|