@@ -47,20 +47,58 @@ function refreshForTestRunnerWatch() {
4747 }
4848}
4949
50+ async function performFileOperation ( operation , useRunApi , timeout = 1000 ) {
51+ if ( useRunApi ) {
52+ const interval = setInterval ( ( ) => {
53+ operation ( ) ;
54+ clearInterval ( interval ) ;
55+ } , common . platformTimeout ( timeout ) ) ;
56+ } else {
57+ operation ( ) ;
58+ await setTimeout ( common . platformTimeout ( timeout ) ) ;
59+ }
60+ }
61+
62+ function assertTestOutput ( run , shouldCheckRecursion = false ) {
63+ if ( shouldCheckRecursion ) {
64+ assert . doesNotMatch ( run , / r u n \( \) i s b e i n g c a l l e d r e c u r s i v e l y / ) ;
65+ }
66+ assert . match ( run , / t e s t s 1 / ) ;
67+ assert . match ( run , / p a s s 1 / ) ;
68+ assert . match ( run , / f a i l 0 / ) ;
69+ assert . match ( run , / c a n c e l l e d 0 / ) ;
70+ }
71+
5072async function testRunnerWatch ( {
5173 fileToUpdate,
5274 file,
5375 action = 'update' ,
5476 fileToCreate,
5577 isolation,
78+ useRunApi = false ,
79+ cwd = tmpdir . path ,
80+ runnerCwd,
5681} ) {
5782 const ran1 = Promise . withResolvers ( ) ;
5883 const ran2 = Promise . withResolvers ( ) ;
59- const child = spawn ( process . execPath ,
60- [ '--watch' , '--test' , '--test-reporter=spec' ,
61- isolation ? `--test-isolation=${ isolation } ` : '' ,
62- file ? fixturePaths [ file ] : undefined ] . filter ( Boolean ) ,
63- { encoding : 'utf8' , stdio : 'pipe' , cwd : tmpdir . path } ) ;
84+
85+ let args ;
86+ if ( useRunApi ) {
87+ // Use the fixture that calls run() API
88+ const runner = fixtures . path ( 'test-runner-watch.mjs' ) ;
89+ args = [ runner ] ;
90+ if ( file ) args . push ( '--file' , file ) ;
91+ if ( runnerCwd ) args . push ( '--cwd' , runnerCwd ) ;
92+ if ( isolation ) args . push ( '--isolation' , isolation ) ;
93+ } else {
94+ // Use CLI --watch --test flags
95+ args = [ '--watch' , '--test' , '--test-reporter=spec' ,
96+ isolation ? `--test-isolation=${ isolation } ` : '' ,
97+ file ? fixturePaths [ file ] : undefined ] . filter ( Boolean ) ;
98+ }
99+
100+ const child = spawn ( process . execPath , args ,
101+ { encoding : 'utf8' , stdio : 'pipe' , cwd } ) ;
64102 let stdout = '' ;
65103 let currentRun = '' ;
66104 const runs = [ ] ;
@@ -79,20 +117,28 @@ async function testRunnerWatch({
79117 currentRun = '' ;
80118 const content = fixtureContent [ fileToUpdate ] ;
81119 const path = fixturePaths [ fileToUpdate ] ;
82- writeFileSync ( path , content ) ;
83- await setTimeout ( common . platformTimeout ( 1000 ) ) ;
84- await ran2 . promise ;
120+
121+ if ( useRunApi ) {
122+ const interval = setInterval (
123+ ( ) => writeFileSync ( path , content ) ,
124+ common . platformTimeout ( 1000 ) ,
125+ ) ;
126+ await ran2 . promise ;
127+ clearInterval ( interval ) ;
128+ } else {
129+ writeFileSync ( path , content ) ;
130+ await setTimeout ( common . platformTimeout ( 1000 ) ) ;
131+ await ran2 . promise ;
132+ }
133+
85134 runs . push ( currentRun ) ;
86135 child . kill ( ) ;
87136 await once ( child , 'exit' ) ;
88137
89138 assert . strictEqual ( runs . length , 2 ) ;
90139
91140 for ( const run of runs ) {
92- assert . match ( run , / t e s t s 1 / ) ;
93- assert . match ( run , / p a s s 1 / ) ;
94- assert . match ( run , / f a i l 0 / ) ;
95- assert . match ( run , / c a n c e l l e d 0 / ) ;
141+ assertTestOutput ( run , useRunApi ) ;
96142 }
97143 } ;
98144
@@ -102,31 +148,53 @@ async function testRunnerWatch({
102148 currentRun = '' ;
103149 const fileToRenamePath = tmpdir . resolve ( fileToUpdate ) ;
104150 const newFileNamePath = tmpdir . resolve ( `test-renamed-${ fileToUpdate } ` ) ;
105- renameSync ( fileToRenamePath , newFileNamePath ) ;
106- await setTimeout ( common . platformTimeout ( 1000 ) ) ;
151+
152+ await performFileOperation (
153+ ( ) => renameSync ( fileToRenamePath , newFileNamePath ) ,
154+ useRunApi ,
155+ ) ;
107156 await ran2 . promise ;
157+
108158 runs . push ( currentRun ) ;
109159 child . kill ( ) ;
110160 await once ( child , 'exit' ) ;
111161
112162 assert . strictEqual ( runs . length , 2 ) ;
113163
114- for ( const run of runs ) {
115- assert . match ( run , / t e s t s 1 / ) ;
116- assert . match ( run , / p a s s 1 / ) ;
117- assert . match ( run , / f a i l 0 / ) ;
118- assert . match ( run , / c a n c e l l e d 0 / ) ;
164+ const [ firstRun , secondRun ] = runs ;
165+ assertTestOutput ( firstRun , useRunApi ) ;
166+
167+ if ( action === 'rename2' ) {
168+ assert . match ( secondRun , / M O D U L E _ N O T _ F O U N D / ) ;
169+ return ;
119170 }
171+
172+ assertTestOutput ( secondRun , useRunApi ) ;
120173 } ;
121174
122175 const testDelete = async ( ) => {
123176 await ran1 . promise ;
124177 runs . push ( currentRun ) ;
125178 currentRun = '' ;
126179 const fileToDeletePath = tmpdir . resolve ( fileToUpdate ) ;
127- unlinkSync ( fileToDeletePath ) ;
128- await setTimeout ( common . platformTimeout ( 2000 ) ) ;
129- ran2 . resolve ( ) ;
180+
181+ if ( useRunApi ) {
182+ const { existsSync } = require ( 'node:fs' ) ;
183+ const interval = setInterval ( ( ) => {
184+ if ( existsSync ( fileToDeletePath ) ) {
185+ unlinkSync ( fileToDeletePath ) ;
186+ } else {
187+ ran2 . resolve ( ) ;
188+ clearInterval ( interval ) ;
189+ }
190+ } , common . platformTimeout ( 1000 ) ) ;
191+ await ran2 . promise ;
192+ } else {
193+ unlinkSync ( fileToDeletePath ) ;
194+ await setTimeout ( common . platformTimeout ( 2000 ) ) ;
195+ ran2 . resolve ( ) ;
196+ }
197+
130198 runs . push ( currentRun ) ;
131199 child . kill ( ) ;
132200 await once ( child , 'exit' ) ;
@@ -143,25 +211,29 @@ async function testRunnerWatch({
143211 runs . push ( currentRun ) ;
144212 currentRun = '' ;
145213 const newFilePath = tmpdir . resolve ( fileToCreate ) ;
146- writeFileSync ( newFilePath , 'module.exports = {};' ) ;
147- await setTimeout ( common . platformTimeout ( 1000 ) ) ;
214+
215+ await performFileOperation (
216+ ( ) => writeFileSync ( newFilePath , 'module.exports = {};' ) ,
217+ useRunApi ,
218+ ) ;
148219 await ran2 . promise ;
220+
149221 runs . push ( currentRun ) ;
150222 child . kill ( ) ;
151223 await once ( child , 'exit' ) ;
152224
153225 for ( const run of runs ) {
154- assert . match ( run , / t e s t s 1 / ) ;
155- assert . match ( run , / p a s s 1 / ) ;
156- assert . match ( run , / f a i l 0 / ) ;
157- assert . match ( run , / c a n c e l l e d 0 / ) ;
226+ assertTestOutput ( run , false ) ;
158227 }
159228 } ;
160229
161230 action === 'update' && await testUpdate ( ) ;
162231 action === 'rename' && await testRename ( ) ;
232+ action === 'rename2' && await testRename ( ) ;
163233 action === 'delete' && await testDelete ( ) ;
164234 action === 'create' && await testCreate ( ) ;
235+
236+ return runs ;
165237}
166238
167239
@@ -170,4 +242,6 @@ module.exports = {
170242 skipIfNoWatchModeSignals,
171243 testRunnerWatch,
172244 refreshForTestRunnerWatch,
245+ fixtureContent,
246+ fixturePaths,
173247} ;
0 commit comments