@@ -24,10 +24,9 @@ const baselineAccept = require("./scripts/build/baselineAccept");
2424const cmdLineOptions = require ( "./scripts/build/options" ) ;
2525const exec = require ( "./scripts/build/exec" ) ;
2626const browserify = require ( "./scripts/build/browserify" ) ;
27- const debounce = require ( "./scripts/build/debounce" ) ;
2827const prepend = require ( "./scripts/build/prepend" ) ;
2928const { removeSourceMaps } = require ( "./scripts/build/sourcemaps" ) ;
30- const { CancelSource , CancelError } = require ( "./scripts/build/cancellation " ) ;
29+ const { CancellationTokenSource , CancelError, delay , Semaphore } = require ( "prex " ) ;
3130const { libraryTargets, generateLibs } = require ( "./scripts/build/lib" ) ;
3231const { runConsoleTests, cleanTestDirs, writeTestConfigFile, refBaseline, localBaseline, refRwcBaseline, localRwcBaseline } = require ( "./scripts/build/tests" ) ;
3332
@@ -556,35 +555,61 @@ gulp.task(
556555 "Watches for changes to the build inputs for built/local/run.js, then executes runtests-parallel." ,
557556 [ "build-rules" , "watch-runner" , "watch-services" , "watch-lssl" ] ,
558557 ( ) => {
559- /** @type {CancelSource | undefined } */
560- let runTestsSource ;
561-
562- const fn = debounce ( ( ) => {
563- runTests ( ) . catch ( error => {
564- if ( error instanceof CancelError ) {
558+ const runTestsSemaphore = new Semaphore ( 1 ) ;
559+ const fn = async ( ) => {
560+ try {
561+ // Ensure only one instance of the test runner is running at any given time.
562+ if ( runTestsSemaphore . count > 0 ) {
563+ await runTestsSemaphore . wait ( ) ;
564+ try {
565+ // Wait for any concurrent recompilations to complete...
566+ try {
567+ await delay ( 100 ) ;
568+ while ( project . hasRemainingWork ( ) ) {
569+ await project . waitForWorkToComplete ( ) ;
570+ await delay ( 500 ) ;
571+ }
572+ }
573+ catch ( e ) {
574+ if ( e instanceof CancelError ) return ;
575+ throw e ;
576+ }
577+
578+ // cancel any pending or active test run if a new recompilation is triggered
579+ const runTestsSource = new CancellationTokenSource ( ) ;
580+ project . waitForWorkToStart ( ) . then ( ( ) => {
581+ runTestsSource . cancel ( ) ;
582+ } ) ;
583+
584+ if ( cmdLineOptions . tests || cmdLineOptions . failed ) {
585+ await runConsoleTests ( runJs , "mocha-fivemat-progress-reporter" , /*runInParallel*/ false , /*watchMode*/ true , runTestsSource . token ) ;
586+ }
587+ else {
588+ await runConsoleTests ( runJs , "min" , /*runInParallel*/ true , /*watchMode*/ true , runTestsSource . token ) ;
589+ }
590+ }
591+ finally {
592+ runTestsSemaphore . release ( ) ;
593+ }
594+ }
595+ }
596+ catch ( e ) {
597+ if ( e instanceof CancelError ) {
565598 log . warn ( "Operation was canceled" ) ;
566599 }
567600 else {
568- log . error ( error ) ;
601+ log . error ( e ) ;
569602 }
570- } ) ;
571- } , /*timeout*/ 100 , { max : 500 } ) ;
603+ }
604+ } ;
572605
573- gulp . watch ( watchPatterns , ( ) => project . wait ( runTestsSource && runTestsSource . token ) . then ( fn ) ) ;
606+ gulp . watch ( watchPatterns , ( e ) => fn ( ) ) ;
574607
575608 // NOTE: gulp.watch is far too slow when watching tests/cases/**/* as it first enumerates *every* file
576609 const testFilePattern = / ( \. t s | [ \\ / ] t s c o n f i g \. j s o n ) $ / ;
577610 fs . watch ( "tests/cases" , { recursive : true } , ( _ , file ) => {
578- if ( testFilePattern . test ( file ) ) project . wait ( runTestsSource && runTestsSource . token ) . then ( fn ) ;
611+ if ( testFilePattern . test ( file ) ) fn ( ) ;
579612 } ) ;
580-
581- function runTests ( ) {
582- if ( runTestsSource ) runTestsSource . cancel ( ) ;
583- runTestsSource = new CancelSource ( ) ;
584- return cmdLineOptions . tests || cmdLineOptions . failed
585- ? runConsoleTests ( runJs , "mocha-fivemat-progress-reporter" , /*runInParallel*/ false , /*watchMode*/ true , runTestsSource . token )
586- : runConsoleTests ( runJs , "min" , /*runInParallel*/ true , /*watchMode*/ true , runTestsSource . token ) ;
587- }
588613 } ) ;
589614
590615gulp . task ( "clean-built" , /*help*/ false , [ `clean:${ diagnosticInformationMapTs } ` ] , ( ) => del ( [ "built" ] ) ) ;
0 commit comments