Something went wrong. Try again.
Monorepo for the nibling.run platform
Something went wrong. Try again.
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061// process.stdin over a pipe. The goldens feed Node and the runtime the same bytes and// close stdin (tests/goldens/stdin-*, recorded by `node scripts/golden.mjs`). Whether an open stdin// holds a process is recorded from Node by `node scripts/stdin-liveness.mjs`, over the// cases in tests/fixtures/stdin-liveness.mjs.import { test, expect } from "@playwright/test";import { goldenSuite } from "./guest";import { BIG_INPUT_BYTES, CLOSE_AFTER_MS, INPUT, LIVENESS_CASES } from "./fixtures/stdin-liveness.mjs";
goldenSuite(["stdin-"]);
const NODE_LIVENESS = [ { name: "untouched", held: false, code: 0, stdout: "function\n" }, { name: "flowing", held: true, code: 0, stdout: "data chunk\nend\n" }, { name: "readableOnce", held: true, code: 0, stdout: "readable chunk\n" }, { name: "unref", held: false, code: 0, stdout: "timer\n" }, { name: "pausedBeforeData", held: false, code: 0, stdout: "timer 0\n" }, { name: "pausedInDataHandler", held: true, code: 0, stdout: "got \"chunk\\n\"\n" }, { name: "pausedLater", held: false, code: 0, stdout: "paused\n" }, { name: "fullBuffer", held: false, code: 0, stdout: "buffered true\n" },];
for (const expected of NODE_LIVENESS) { test(`open stdin, ${expected.name}: ${expected.held ? "held until EOF" : "exits"} as in Node`, async ({ page }) => { await page.goto("/demo/fixture.html"); await page.waitForFunction(() => window.__runtime !== undefined, undefined, { timeout: 20_000 }); const source = LIVENESS_CASES[expected.name as keyof typeof LIVENESS_CASES]; const input = expected.name === "fullBuffer" ? { repeat: "x", times: BIG_INPUT_BYTES } : { repeat: INPUT, times: 1 }; const result = await page.evaluate(async ({ source, input, closeAfterMs }) => { const runtime = window.__runtime!; runtime.writeTree({ "/app/main.cjs": source }); const proc = runtime.exec("/app/main.cjs"); const started = performance.now(); let firstOutput: number | undefined; let stdout = ""; const dec = new TextDecoder(); const writer = proc.stdin.getWriter(); let closed = false; let timer: ReturnType<typeof setTimeout> | undefined; const piped = proc.stdout.pipeTo(new WritableStream({ write(c) { firstOutput ??= performance.now() - started; stdout += dec.decode(c); timer ??= setTimeout(() => { closed = true; void writer.close(); }, closeAfterMs); }, })); void writer.write(new TextEncoder().encode(input.repeat.repeat(input.times))); const code = await proc.exited; const exited = performance.now() - started; clearTimeout(timer); await piped; return { held: closed, code, stdout, timing: `first output at ${Math.round(firstOutput ?? -1)}ms, exit at ${Math.round(exited)}ms` }; }, { source, input, closeAfterMs: CLOSE_AFTER_MS }); // The timing tells a stall (late first output) from a real hold (exit long after it). const { timing, ...observed } = result; expect({ name: expected.name, ...observed }, timing).toEqual(expected); });}