|
1 | 1 | import type { Writable } from 'node:stream' |
2 | 2 | import type { Vitest } from '../../core' |
3 | 3 | import { stripVTControlCharacters } from 'node:util' |
4 | | -import restoreCursor from 'restore-cursor' |
5 | 4 |
|
6 | 5 | const DEFAULT_RENDER_INTERVAL = 16 |
7 | 6 |
|
@@ -49,9 +48,9 @@ export class WindowRenderer { |
49 | 48 | this.cleanups.push( |
50 | 49 | this.interceptStream(process.stdout, 'output'), |
51 | 50 | this.interceptStream(process.stderr, 'error'), |
| 51 | + this.addProcessExitListeners(), |
52 | 52 | ) |
53 | 53 |
|
54 | | - restoreCursor() |
55 | 54 | this.write(HIDE_CURSOR, 'output') |
56 | 55 |
|
57 | 56 | this.start() |
@@ -175,6 +174,32 @@ export class WindowRenderer { |
175 | 174 | private write(message: string, type: 'output' | 'error' = 'output') { |
176 | 175 | (this.streams[type] as Writable['write'])(message) |
177 | 176 | } |
| 177 | + |
| 178 | + private addProcessExitListeners() { |
| 179 | + const onExit = (signal?: string | number, exitCode?: number) => { |
| 180 | + // Write buffered content on unexpected exits, e.g. direct `process.exit()` calls |
| 181 | + this.flushBuffer() |
| 182 | + this.stop() |
| 183 | + |
| 184 | + // Interrupted signals don't set exit code automatically. |
| 185 | + // Use same exit code as node: https://nodejs.org/api/process.html#signal-events |
| 186 | + if (process.exitCode === undefined) { |
| 187 | + process.exitCode = exitCode !== undefined ? (128 + exitCode) : Number(signal) |
| 188 | + } |
| 189 | + |
| 190 | + process.exit() |
| 191 | + } |
| 192 | + |
| 193 | + process.once('SIGINT', onExit) |
| 194 | + process.once('SIGTERM', onExit) |
| 195 | + process.once('exit', onExit) |
| 196 | + |
| 197 | + return function cleanup() { |
| 198 | + process.off('SIGINT', onExit) |
| 199 | + process.off('SIGTERM', onExit) |
| 200 | + process.off('exit', onExit) |
| 201 | + } |
| 202 | + } |
178 | 203 | } |
179 | 204 |
|
180 | 205 | /** Calculate the actual row count needed to render `rows` into `stream` */ |
|
0 commit comments