Compare commits

...

1 Commits

Author SHA1 Message Date
Charles Kerr
604a7dde05 test: set timeout limit for ESM fixture processes 2026-05-01 10:31:42 -05:00
2 changed files with 81 additions and 22 deletions

View File

@@ -2,35 +2,22 @@ import { BrowserWindow } from 'electron';
import { expect } from 'chai';
import * as cp from 'node:child_process';
import * as fs from 'node:fs';
import * as os from 'node:os';
import * as path from 'node:path';
import { pathToFileURL } from 'node:url';
import { stripVTControlCharacters } from 'node:util';
import { spawnAndWait } from './lib/spec-helpers';
const fixtureTimeout = 20000;
const fixtureKillTimeout = 5000;
const runFixture = async (appPath: string, args: string[] = []) => {
const result = cp.spawn(process.execPath, [appPath, ...args], {
stdio: 'pipe'
return await spawnAndWait(process.execPath, [appPath, ...args], {
timeout: fixtureTimeout,
killTimeout: fixtureKillTimeout,
stripOutput: true
});
const stdout: Buffer[] = [];
const stderr: Buffer[] = [];
result.stdout.on('data', (chunk) => stdout.push(chunk));
result.stderr.on('data', (chunk) => stderr.push(chunk));
const [code, signal] = await new Promise<[number | null, NodeJS.Signals | null]>((resolve) => {
result.on('close', (code, signal) => {
resolve([code, signal]);
});
});
return {
code,
signal,
stdout: stripVTControlCharacters(Buffer.concat(stdout).toString().trim()),
stderr: stripVTControlCharacters(Buffer.concat(stderr).toString().trim())
};
};
const fixturePath = path.resolve(__dirname, 'fixtures', 'esm');

View File

@@ -11,6 +11,7 @@ import * as net from 'node:net';
import * as path from 'node:path';
import { setTimeout } from 'node:timers/promises';
import * as url from 'node:url';
import { stripVTControlCharacters } from 'node:util';
import * as v8 from 'node:v8';
const addOnly = <T>(fn: Function): T => {
@@ -109,6 +110,77 @@ export async function startRemoteControlApp(extraArgs: string[] = [], options?:
return new RemoteControlApp(appProcess, port);
}
export interface SpawnAndWaitResult {
code: number | null;
signal: NodeJS.Signals | null;
stdout: string;
stderr: string;
}
export interface SpawnAndWaitOptions extends childProcess.SpawnOptionsWithoutStdio {
timeout: number;
killTimeout?: number;
stripOutput?: boolean;
}
function formatSpawnOutput(stdout: Buffer[], stderr: Buffer[], stripOutput = false) {
const normalize = (chunks: Buffer[]) => {
const output = Buffer.concat(chunks).toString().trim();
return stripOutput ? stripVTControlCharacters(output) : output;
};
return {
stdout: normalize(stdout),
stderr: normalize(stderr)
};
}
export async function spawnAndWait(
command: string,
args: string[],
options: SpawnAndWaitOptions
): Promise<SpawnAndWaitResult> {
const { timeout, killTimeout = 5000, stripOutput, ...spawnOptions } = options;
const child = childProcess.spawn(command, args, spawnOptions);
const stdout: Buffer[] = [];
const stderr: Buffer[] = [];
child.stdout.on('data', (chunk) => stdout.push(chunk));
child.stderr.on('data', (chunk) => stderr.push(chunk));
let timedOut = false;
let killTimeoutId: NodeJS.Timeout | undefined;
const timeoutId = globalThis.setTimeout(() => {
timedOut = true;
child.kill();
killTimeoutId = globalThis.setTimeout(() => {
child.kill('SIGKILL');
}, killTimeout);
}, timeout);
const [code, signal] = await new Promise<[number | null, NodeJS.Signals | null]>((resolve, reject) => {
child.on('error', reject);
child.on('close', (code, signal) => {
resolve([code, signal]);
});
}).finally(() => {
globalThis.clearTimeout(timeoutId);
if (killTimeoutId) globalThis.clearTimeout(killTimeoutId);
});
const output = formatSpawnOutput(stdout, stderr, stripOutput);
if (timedOut) {
throw new Error(
`Timed out after ${timeout}ms waiting for ${command} ${args.join(' ')} to exit. Process closed with code ${code} and signal ${signal}.\n\nstdout:\n${output.stdout}\n\nstderr:\n${output.stderr}`
);
}
return {
code,
signal,
...output
};
}
export function waitUntil(callback: () => boolean | Promise<boolean>, opts: { rate?: number; timeout?: number } = {}) {
const { rate = 10, timeout = 10000 } = opts;
return (async () => {