88 ArrayPrototypePush,
99 ArrayPrototypeReduce,
1010 ArrayPrototypeSome,
11+ JSONParse,
1112 MathFloor,
1213 MathMax,
1314 MathMin,
@@ -28,9 +29,10 @@ const {
2829
2930const { AsyncResource } = require ( 'async_hooks' ) ;
3031const { relative, sep, resolve } = require ( 'path' ) ;
31- const { createWriteStream } = require ( 'fs' ) ;
32+ const { createWriteStream, readFileSync } = require ( 'fs' ) ;
3233const { pathToFileURL } = require ( 'internal/url' ) ;
3334const { getOptionValue } = require ( 'internal/options' ) ;
35+ const { reportReruns } = require ( 'internal/test_runner/reporter/rerun' ) ;
3436const { green, yellow, red, white, shouldColorize } = require ( 'internal/util/colors' ) ;
3537
3638const {
@@ -40,7 +42,7 @@ const {
4042 } ,
4143 kIsNodeError,
4244} = require ( 'internal/errors' ) ;
43- const { compose } = require ( 'stream' ) ;
45+ const { compose, PassThrough } = require ( 'stream' ) ;
4446const {
4547 validateInteger,
4648 validateFunction,
@@ -150,6 +152,20 @@ function shouldColorizeTestFiles(destinations) {
150152 } ) ;
151153}
152154
155+ function parsePreviousRuns ( rerunFilePath ) {
156+ let data ;
157+ try {
158+ data = readFileSync ( rerunFilePath , 'utf8' ) ;
159+ } catch ( err ) {
160+ if ( err . code === 'ENOENT' ) {
161+ data = '[]' ;
162+ } else {
163+ throw err ;
164+ }
165+ }
166+ return JSONParse ( data ) ;
167+ }
168+
153169async function getReportersMap ( reporters , destinations ) {
154170 return SafePromiseAllReturnArrayLike ( reporters , async ( name , i ) => {
155171 const destination = kBuiltinDestinations . get ( destinations [ i ] ) ??
@@ -202,6 +218,7 @@ function parseCommandLine() {
202218 const updateSnapshots = getOptionValue ( '--test-update-snapshots' ) ;
203219 const watch = getOptionValue ( '--watch' ) ;
204220 const timeout = getOptionValue ( '--test-timeout' ) || Infinity ;
221+ const rerunFilePath = getOptionValue ( '--test-rerun' ) ;
205222 const isChildProcess = process . env . NODE_TEST_CONTEXT === 'child' ;
206223 const isChildProcessV8 = process . env . NODE_TEST_CONTEXT === 'child-v8' ;
207224 let globalSetupPath ;
@@ -308,8 +325,24 @@ function parseCommandLine() {
308325 validateInteger ( functionCoverage , '--test-coverage-functions' , 0 , 100 ) ;
309326 }
310327
328+ let previousRuns ;
329+ if ( rerunFilePath ) {
330+ validatePath ( rerunFilePath , '--test-rerun' ) ;
331+ previousRuns = parsePreviousRuns ( rerunFilePath ) ;
332+ if ( previousRuns === null ) {
333+ throw new ERR_INVALID_ARG_VALUE ( '--test-rerun' , rerunFilePath , 'is not a valid rerun file' ) ;
334+ }
335+ }
336+
311337 const setup = reporterScope . bind ( async ( rootReporter ) => {
312338 const reportersMap = await getReportersMap ( reporters , destinations ) ;
339+ if ( previousRuns && rerunFilePath ) {
340+ ArrayPrototypePush ( reportersMap , {
341+ __proto__ : null ,
342+ reporter : reportReruns ( previousRuns , rerunFilePath ) ,
343+ destination : new PassThrough ( ) ,
344+ } ) ;
345+ }
313346
314347 for ( let i = 0 ; i < reportersMap . length ; i ++ ) {
315348 const { reporter, destination } = reportersMap [ i ] ;
@@ -343,6 +376,8 @@ function parseCommandLine() {
343376 timeout,
344377 updateSnapshots,
345378 watch,
379+ rerunFilePath,
380+ previousRuns,
346381 } ;
347382
348383 return globalTestOptions ;
@@ -637,4 +672,5 @@ module.exports = {
637672 shouldColorizeTestFiles,
638673 getCoverageReport,
639674 setupGlobalSetupTeardownFunctions,
675+ parsePreviousRuns,
640676} ;
0 commit comments