blob: 102f7f2b4c59de37c18f35f02e5993ffd0996848 [file]
import assert from 'node:assert/strict';
import { test } from 'node:test';
import { PtyProcessDriver, type PtyProcessExit } from '../pty-process-driver.js';
import { loadPtyStack } from '../pty-stack.js';
const TEST_TIMEOUT_MS = 5_000;
test('PTY driver exposes the live child PID and acknowledges forced exit', async () => {
const stack = await loadPtyStack();
let resolveReady!: () => void;
let resolveExit!: (exit: PtyProcessExit) => void;
let rejectInvariant!: (error: Error) => void;
const ready = new Promise<void>((resolve) => {
resolveReady = resolve;
});
const invariantFailure = new Promise<never>((_, reject) => {
rejectInvariant = reject;
});
const exited = new Promise<PtyProcessExit>((resolve) => {
resolveExit = resolve;
});
const driver = new PtyProcessDriver({
stack,
file: process.execPath,
args: ['-e', "process.stdout.write('READY\\n'); setInterval(() => {}, 1000)"],
cwd: process.cwd(),
env: process.env,
cols: 80,
rows: 24,
onData: (data) => {
if (data.includes('READY')) resolveReady();
},
onExit: resolveExit,
onInvariantFailure: rejectInvariant,
});
try {
await withTimeout(Promise.race([ready, invariantFailure]), 'PTY child did not become ready');
assert.ok(Number.isSafeInteger(driver.pid) && driver.pid > 0);
driver.kill('SIGKILL');
await withTimeout(
Promise.race([exited, invariantFailure]),
'PTY child did not acknowledge exit',
);
} finally {
try {
driver.kill('SIGKILL');
} catch {
// The PTY may already have closed after acknowledging exit.
}
driver.dispose();
}
});
function withTimeout<T>(promise: Promise<T>, message: string): Promise<T> {
return Promise.race([
promise,
new Promise<never>((_, reject) => {
const timer = setTimeout(() => reject(new Error(message)), TEST_TIMEOUT_MS);
timer.unref();
}),
]);
}