@@ -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
@@ -534,57 +533,80 @@ gulp.task(
534533 [ "watch-diagnostics" , "watch-lib" ] . concat ( useCompilerDeps ) ,
535534 ( ) => project . watch ( tsserverProject , { typescript : useCompiler } ) ) ;
536535
537- gulp . task (
538- "watch-local" ,
539- /*help*/ false ,
540- [ "watch-lib" , "watch-tsc" , "watch-services" , "watch-server" ] ) ;
541-
542536gulp . task (
543537 "watch-runner" ,
544538 /*help*/ false ,
545539 useCompilerDeps ,
546540 ( ) => project . watch ( testRunnerProject , { typescript : useCompiler } ) ) ;
547541
548- const watchPatterns = [
549- runJs ,
550- typescriptDts ,
551- tsserverlibraryDts
552- ] ;
542+ gulp . task (
543+ "watch-local" ,
544+ "Watches for changes to projects in src/ (but does not execute tests)." ,
545+ [ "watch-lib" , "watch-tsc" , "watch-services" , "watch-server" , "watch-runner" , "watch-lssl" ] ) ;
553546
554547gulp . task (
555548 "watch" ,
556- "Watches for changes to the build inputs for built/local/run.js, then executes runtests-parallel ." ,
549+ "Watches for changes to the build inputs for built/local/run.js, then runs tests ." ,
557550 [ "build-rules" , "watch-runner" , "watch-services" , "watch-lssl" ] ,
558551 ( ) => {
559- /** @type {CancelSource | undefined } */
560- let runTestsSource ;
552+ const sem = new Semaphore ( 1 ) ;
561553
562- const fn = debounce ( ( ) => {
563- runTests ( ) . catch ( error => {
564- if ( error instanceof CancelError ) {
565- log . warn ( "Operation was canceled" ) ;
566- }
567- else {
568- log . error ( error ) ;
569- }
570- } ) ;
571- } , /*timeout*/ 100 , { max : 500 } ) ;
572-
573- gulp . watch ( watchPatterns , ( ) => project . wait ( ) . then ( fn ) ) ;
554+ gulp . watch ( [ runJs , typescriptDts , tsserverlibraryDts ] , ( ) => {
555+ runTests ( ) ;
556+ } ) ;
574557
575558 // NOTE: gulp.watch is far too slow when watching tests/cases/**/* as it first enumerates *every* file
576559 const testFilePattern = / ( \. t s | [ \\ / ] t s c o n f i g \. j s o n ) $ / ;
577560 fs . watch ( "tests/cases" , { recursive : true } , ( _ , file ) => {
578- if ( testFilePattern . test ( file ) ) project . wait ( ) . then ( fn ) ;
561+ if ( testFilePattern . test ( file ) ) runTests ( ) ;
579562 } ) ;
580563
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- }
564+ async function runTests ( ) {
565+ try {
566+ // Ensure only one instance of the test runner is running at any given time.
567+ if ( sem . count > 0 ) {
568+ await sem . wait ( ) ;
569+ try {
570+ // Wait for any concurrent recompilations to complete...
571+ try {
572+ await delay ( 100 ) ;
573+ while ( project . hasRemainingWork ( ) ) {
574+ await project . waitForWorkToComplete ( ) ;
575+ await delay ( 500 ) ;
576+ }
577+ }
578+ catch ( e ) {
579+ if ( e instanceof CancelError ) return ;
580+ throw e ;
581+ }
582+
583+ // cancel any pending or active test run if a new recompilation is triggered
584+ const source = new CancellationTokenSource ( ) ;
585+ project . waitForWorkToStart ( ) . then ( ( ) => {
586+ source . cancel ( ) ;
587+ } ) ;
588+
589+ if ( cmdLineOptions . tests || cmdLineOptions . failed ) {
590+ await runConsoleTests ( runJs , "mocha-fivemat-progress-reporter" , /*runInParallel*/ false , /*watchMode*/ true , source . token ) ;
591+ }
592+ else {
593+ await runConsoleTests ( runJs , "min" , /*runInParallel*/ true , /*watchMode*/ true , source . token ) ;
594+ }
595+ }
596+ finally {
597+ sem . release ( ) ;
598+ }
599+ }
600+ }
601+ catch ( e ) {
602+ if ( e instanceof CancelError ) {
603+ log . warn ( "Operation was canceled" ) ;
604+ }
605+ else {
606+ log . error ( e ) ;
607+ }
608+ }
609+ } ;
588610 } ) ;
589611
590612gulp . task ( "clean-built" , /*help*/ false , [ `clean:${ diagnosticInformationMapTs } ` ] , ( ) => del ( [ "built" ] ) ) ;
0 commit comments