@@ -10,6 +10,7 @@ import {
1010 loadRunConfig ,
1111 preExec ,
1212 prepareNpmEnv ,
13+ runWithStdoutWatchdog ,
1314 zip ,
1415} from 'sauce-testrunner-utils' ;
1516
@@ -321,31 +322,46 @@ async function runTestCafe(
321322 'testcafe-with-v8-flag-filter.js' ,
322323 ) ;
323324
325+ // stdio is piped (not inherited) so the no-progress watchdog can observe
326+ // TestCafe's output. Chunks are still echoed to the parent's stdout/stderr
327+ // by runWithStdoutWatchdog, preserving existing log behavior.
324328 const testcafeProc = spawn (
325329 nodeBin ,
326330 [ testcafeBin , ...( tcCommandLine as string [ ] ) ] ,
327331 {
328- stdio : 'inherit' ,
332+ stdio : [ 'inherit' , 'pipe' , 'pipe' ] ,
329333 cwd : projectPath ,
330334 env : process . env ,
331335 } ,
332336 ) ;
333337
338+ const noProgressTimeoutSecs = Math . max (
339+ 1 ,
340+ parseInt (
341+ process . env . SAUCE_TESTCAFE_NO_PROGRESS_TIMEOUT_SECS ?? '180' ,
342+ 10 ,
343+ ) || 180 ,
344+ ) ;
345+
334346 const timeoutPromise = new Promise < boolean > ( ( resolve ) => {
335347 setTimeout ( ( ) => {
336348 console . error ( `Job timed out after ${ timeout } seconds` ) ;
337349 resolve ( false ) ;
338350 } , timeout * 1000 ) ;
339351 } ) ;
340352
341- const testcafePromise = new Promise < boolean > ( ( resolve ) => {
342- testcafeProc . on ( 'close' , ( code /*, ...args*/ ) => {
343- resolve ( code === 0 ) ;
344- } ) ;
353+ const watchdogPromise = runWithStdoutWatchdog ( testcafeProc , {
354+ noProgressTimeoutSecs,
355+ tag : 'Sauce TestCafe Runner' ,
356+ } ) . then ( ( { exitCode, watchdogFired } ) => {
357+ if ( watchdogFired ) {
358+ return false ;
359+ }
360+ return exitCode === 0 ;
345361 } ) ;
346362
347363 try {
348- return Promise . race ( [ timeoutPromise , testcafePromise ] ) ;
364+ return Promise . race ( [ timeoutPromise , watchdogPromise ] ) ;
349365 } catch ( e ) {
350366 console . error ( `Failed to run TestCafe: ${ e } ` ) ;
351367 }
0 commit comments