UNPKG

@stryker-mutator/tap-runner

Version:

A plugin to use the TAP (test anything protocol) test runner in Stryker, the JavaScript mutation testing framework

76 lines (61 loc) 2.72 kB
import os from 'os'; import { ChildProcessWithoutNullStreams } from 'child_process'; import { glob } from 'glob'; import * as tap from 'tap-parser'; import { TapParser } from './tap-parser-factory.js'; export function findTestyLookingFiles(globPatterns: string[]): Promise<string[]> { return glob(globPatterns, { ignore: ['**/node_modules/**'], posix: true }); } export interface TapResult { result: tap.FinalResults; failedTests: tap.TapError[]; } function parseTap(tapProcess: ChildProcessWithoutNullStreams, forceBail: boolean) { return new Promise<TapResult>((resolve) => { const failedTests: tap.TapError[] = []; const config = { bail: forceBail }; const parser = TapParser.Parser(config, (result) => { resolve({ result, failedTests }); }); parser.on('bailout', () => { // Bailout within a test file is not supported on windows, because when the process is killed the exit handler which saves the file with the result does not run. if (os.platform() !== 'win32') { tapProcess.kill(); } }); parser.on('fail', (reason: tap.TapError) => { failedTests.push(reason); }); tapProcess.stdout.pipe(parser); }); } export async function captureTapResult(tapProcess: ChildProcessWithoutNullStreams, disableBail: boolean): Promise<TapResult> { const exitAsPromised = new Promise<number>((resolve) => tapProcess.on('exit', resolve)); const stderrOutput: Buffer[] = []; tapProcess.stderr.on('data', (chunk: Buffer) => { stderrOutput.push(chunk); }); const [exitCodeResult, tapResult] = await Promise.all([exitAsPromised, parseTap(tapProcess, disableBail)]); if (exitCodeResult !== 0 && !tapResult.failedTests.length) { // The tap process errored, but we don't have any failed tests. This is probably a syntax error in the test file. throw new Error( `Tap process exited with code ${exitCodeResult}. To reproduce it yourself, use the following command: cd "${process.cwd()}" ${tapProcess.spawnargs.map((arg, index) => (index === 0 ? arg : `"${arg}"`)).join(' ')} Stderr output: ${stderrOutput.join('')}`, ); } return tapResult; } export function buildArguments(args: string[], hookFile: string, testFile: string): string[] { const hookFilePlaceholder = '{{hookFile}}'; const testFilePlaceholder = '{{testFile}}'; if (!args.some((arg) => arg.includes(hookFilePlaceholder))) { args = ['-r', hookFilePlaceholder, ...args]; } if (!args.some((arg) => arg.includes(testFilePlaceholder))) { args = [...args, testFilePlaceholder]; } return args.map((arg) => arg.replaceAll(testFilePlaceholder, testFile).replaceAll(hookFilePlaceholder, hookFile)); }