fix(runtime): align debug-mode unmount byte stream to Ink (#142)
* fix(runtime): align debug-mode unmount byte stream to Ink In DEBUG mode (non-interactive) vue-tui's teardown emitted neither a final-frame re-emit nor a trailing newline, while Ink emits both (ink.tsx:749-762 settleThrottle re-emit + ink.tsx:812-819 `debug ? '\n' : lastOutput + '\n'`). So for a debug app that renders "Hello" once, Ink's byte stream is "HelloHello\n" but vue-tui's was just "Hello" — a divergence that matters when porting Ink debug snapshots / CI logs. - Fire the final-frame re-emit `mountedCommit()` for debug too (was interactive-only). - In the non-interactive teardown write, emit a bare "\n" for debug (Ink parity), keeping the non-debug `lastFrame + "\n"` branch byte-identical. Because the @vue-tui/testing render() helper captures debug commits via an internal frame sink, gate the debug commit's two `frameSink?.(...)` forwards on `!teardownStarted` so the teardown re-emit (a stdout byte-parity FLUSH, not a render) does not append a spurious entry to the helper's live `frames[]`. `teardownStarted` is set at the top of teardown() before the re-emit, so this covers EVERY teardown route (unmount / cleanup / exit / Ctrl+C / signal / process.exit). Both `stdout.write` calls stay unconditional, preserving byte parity. Adds a PTY byte-parity test (asserts "HelloHello\r\n") and a testing-helper test covering all teardown routes (frames.length stable, incl. <Static>). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * test: drop CI-fragile exitOnCtrlC frames-teardown case The Ctrl+C case timed out in CI (waitUntilExit never resolved — stdin/raw-mode timing is environment-fragile), while passing locally. Ctrl+C routes through the SAME exit-driven teardown path as programmatic useApp().exit() (emitInput → appContext.exit() → teardown()), which the remaining exit() cases already cover, so removing it loses no teardown-route coverage of the !teardownStarted frame-sink gate. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -31,3 +31,19 @@ it("debug after exit", async () => {
|
||||
expect(clean).toContain("Hello");
|
||||
expect(clean).toContain("DONE");
|
||||
});
|
||||
|
||||
// Byte-level Ink parity for the DEBUG + non-interactive (CI=true) unmount stream.
|
||||
// Ink (ink.tsx @ v7.0.4): the debug onRender writes `fullStaticOutput + output`
|
||||
// per render with NO trailing newline (550-558); at unmount settleThrottle leaves
|
||||
// shouldRenderFinalFrame=true for debug (throttledOnRender is undefined → 749-762),
|
||||
// so a final onRender RE-EMITS the last frame; then finishUnmount writes a single
|
||||
// trailing "\n" for the non-interactive+debug case (812-819). For the single
|
||||
// static-free "Hello" render (fullStaticOutput="" , lastOutput="Hello") the exact
|
||||
// stdout byte stream is "Hello" + "Hello" + "\n". The PTY translates the lone "\n"
|
||||
// to "\r\n", so the raw capture must end with exactly "HelloHello\r\n".
|
||||
// The ci-debug-bytes fixture uses a function slot so no Vue dev warning is
|
||||
// interleaved — the raw stream is exactly the debug frames.
|
||||
it("debug mode in CI re-emits the final frame and writes a trailing newline (Ink byte parity)", async () => {
|
||||
const output = await run("ci-debug-bytes", { env: { CI: "true" }, columns: 0 });
|
||||
expect(output).toBe("HelloHello\r\n");
|
||||
});
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
import { createApp, Text } from "@vue-tui/runtime";
|
||||
import { defineComponent, h } from "vue";
|
||||
|
||||
// Function-slot form avoids Vue's dev-mode "Non-function value encountered for
|
||||
// default slot" warning, so the captured byte stream is exactly the debug
|
||||
// frames vue-tui writes (no warning noise interleaved). Renders "Hello" once.
|
||||
const App = defineComponent(() => () => h(Text, () => "Hello"));
|
||||
|
||||
const app = createApp(App);
|
||||
app.mount({ debug: true });
|
||||
Reference in New Issue
Block a user