UNPKG

playwright-flake-checker

Version:

A tool to check for flaky Playwright tests by running them multiple times and analyzing results.

112 lines 4.41 kB
import { log } from './logger.js'; import { spawn } from 'child_process'; /** * Cleans up event listeners from both the process and child object. * * @param proc - The Node.js process object from which to remove listeners * @param child - An object with removeListener method, typically a child process * @param handlers - Object containing event handler references * @param handlers.error - Error event handler to be removed * @param handlers.exit - Exit/close event handler to be removed * @param handlers.ctrlC - SIGINT event handler to be removed * @returns {void} */ export const cleanup = (proc, child, handlers) => { proc.removeListener('SIGINT', handlers.ctrlC); child.removeListener('exit', handlers.exit); child.removeListener('close', handlers.exit); child.removeListener('error', handlers.error); }; /** * Creates a command executor function that runs shell commands as child processes * * @returns A function that executes commands and returns their results * - `command` The command to execute * - `args` Optional array of command arguments * - `env` Optional environment variables to add to the process environment * - `silent` If true, suppresses command output to stdout/stderr * - `captureOutput` If true, captures and returns command output */ export const createCommandExecutor = () => { return (command, args = [], env = {}, silent = false, captureOutput = false) => new Promise((resolve, reject) => { const fullCommand = command + (args.length > 0 ? ` ${args.join(' ')}` : ''); let stdioOption; if (silent && !captureOutput) { stdioOption = 'ignore'; } else if (captureOutput) { stdioOption = 'pipe'; } else { stdioOption = 'inherit'; } const child = spawn(command, args, { stdio: stdioOption, env: { ...process.env, ...env }, shell: true, }); let stdoutData = ''; let stderrData = ''; if (captureOutput) { child.stdout?.on('data', (data) => { stdoutData += data.toString(); if (!silent) process.stdout.write(data); }); child.stderr?.on('data', (data) => { stderrData += data.toString(); if (!silent) process.stderr.write(data); }); } const handlers = { error: (err) => { cleanup(process, child, handlers); log().red(`Error executing command: ${fullCommand}`); reject(err); }, exit: (code, signal) => { cleanup(process, child, handlers); const output = stdoutData + stderrData; if (signal === 'SIGINT' || code === 130) { log().yellow('Command interrupted by user.'); reject(new Error('Command interrupted by user.')); } else if (code !== 0) { log().red(`Command failed: ${fullCommand} (exit code ${code}, signal ${signal})`); resolve({ code: code ?? 0, signal: signal ?? '', output, success: false }); } else { resolve({ code: code ?? 0, signal: signal ?? '', output, success: true }); } }, ctrlC: () => { log().yellow('\nCtrl+C pressed. Terminating child process...'); child.kill('SIGINT'); } }; process.once('SIGINT', handlers.ctrlC); child.once('exit', handlers.exit); child.once('error', handlers.error); }); }; /** * Executes commands using the command executor created by `createCommandExecutor`. * This function likely runs shell commands or similar operations. * * @returns The result of the executed command, type determined by the underlying executor * * @see `createCommandExecutor` For information about the underlying implementation */ export const runCommand = createCommandExecutor(); //# sourceMappingURL=command.js.map