Summary
Add an optional PTY-backed parity test suite for the interactive parts of node:tty that cannot be validated reliably in the normal CI-safe parity suite.
Background
The regular node:tty parity suite should stay deterministic and runnable in non-interactive CI, where stdin, stdout, and stderr are usually pipes rather than a real terminal. Some TTY behavior depends on host terminal state and is therefore flaky unless the process is executed inside a controlled pseudo-terminal.
Node covers part of this area with internal mocks. Deno covers real-terminal behavior by spawning helpers under script(1) and skipping gracefully when a PTY is unavailable. Perry should follow the Deno-style approach because it does not expose Node's internal tty_wrap mocking surface.
Proposed work
Create a separate optional suite, for example:
test-parity/node-suite/tty/interactive/
The suite should be skipped by default and only run when one of these is true:
- an explicit environment variable is set, e.g.
PERRY_RUN_TTY_INTERACTIVE_TESTS=1; or
- the parity runner has a dedicated PTY mode/job.
Suggested harness
Use a controlled pseudo-terminal to run Perry and Node/Deno reference commands, preferably through script(1) when available.
The harness should:
- detect whether
script(1) is available;
- support macOS and Linux
script argument differences;
- skip gracefully when a PTY cannot be allocated;
- avoid polluting normal snapshot output with raw ANSI sequences;
- make the PTY size explicit where possible.
Candidate coverage
Add PTY-backed tests for behavior that is intentionally not covered by the normal CI-safe suite:
tty.isatty(0/1/2) returning true when run inside the PTY;
process.stdin.isTTY, process.stdout.isTTY, and process.stderr.isTTY under a real PTY;
new tty.ReadStream(fd) and new tty.WriteStream(fd) with a real TTY fd;
readStream.setRawMode(true/false) if supported by Perry;
writeStream.columns and writeStream.rows with controlled terminal dimensions;
writeStream.getWindowSize();
writeStream.cursorTo(), moveCursor(), clearLine(), and clearScreenDown() without corrupting parity output;
resize event behavior if the harness can change PTY dimensions deterministically;
- stream lifecycle behavior such as destroy/close if Perry supports it.
Acceptance criteria
- The default parity suite remains deterministic and does not require an interactive terminal.
- Interactive TTY tests are isolated from the normal
node:tty suite.
- The interactive suite can be enabled explicitly in local runs or in a dedicated CI job.
- Tests skip with a clear reason when PTY support is unavailable.
- The implementation documents platform differences between macOS and Linux
script(1).
Summary
Add an optional PTY-backed parity test suite for the interactive parts of
node:ttythat cannot be validated reliably in the normal CI-safe parity suite.Background
The regular
node:ttyparity suite should stay deterministic and runnable in non-interactive CI, wherestdin,stdout, andstderrare usually pipes rather than a real terminal. Some TTY behavior depends on host terminal state and is therefore flaky unless the process is executed inside a controlled pseudo-terminal.Node covers part of this area with internal mocks. Deno covers real-terminal behavior by spawning helpers under
script(1)and skipping gracefully when a PTY is unavailable. Perry should follow the Deno-style approach because it does not expose Node's internal tty_wrap mocking surface.Proposed work
Create a separate optional suite, for example:
test-parity/node-suite/tty/interactive/The suite should be skipped by default and only run when one of these is true:
PERRY_RUN_TTY_INTERACTIVE_TESTS=1; orSuggested harness
Use a controlled pseudo-terminal to run Perry and Node/Deno reference commands, preferably through
script(1)when available.The harness should:
script(1)is available;scriptargument differences;Candidate coverage
Add PTY-backed tests for behavior that is intentionally not covered by the normal CI-safe suite:
tty.isatty(0/1/2)returningtruewhen run inside the PTY;process.stdin.isTTY,process.stdout.isTTY, andprocess.stderr.isTTYunder a real PTY;new tty.ReadStream(fd)andnew tty.WriteStream(fd)with a real TTY fd;readStream.setRawMode(true/false)if supported by Perry;writeStream.columnsandwriteStream.rowswith controlled terminal dimensions;writeStream.getWindowSize();writeStream.cursorTo(),moveCursor(),clearLine(), andclearScreenDown()without corrupting parity output;resizeevent behavior if the harness can change PTY dimensions deterministically;Acceptance criteria
node:ttysuite.script(1).