@@ -145,6 +145,9 @@ async function runPoolTests() {
145145 initializeListeners ( )
146146 disablePause ( )
147147
148+ // Emit event.all.before once at the start of pool mode
149+ event . dispatcher . emit ( event . all . before , codecept )
150+
148151 // Accumulate results across all tests in pool mode
149152 let consolidatedStats = { passes : 0 , failures : 0 , tests : 0 , pending : 0 , failedHooks : 0 }
150153 let allTests = [ ]
@@ -161,18 +164,27 @@ async function runPoolTests() {
161164 parentPort ?. off ( 'message' , messageHandler )
162165
163166 if ( eventData . type === 'TEST_ASSIGNED' ) {
164- const testUid = eventData . test
167+ // In pool mode with ESM, we receive test FILE paths instead of UIDs
168+ // because UIDs are not stable across different mocha instances
169+ const testIdentifier = eventData . test
165170
166171 try {
167- // In pool mode, we need to create a fresh Mocha instance for each test
168- // because Mocha instances become disposed after running tests
169- container . createMocha ( ) // Create fresh Mocha instance
170- filterTestById ( testUid )
172+ // Create a fresh Mocha instance for each test file
173+ container . createMocha ( )
171174 const mocha = container . mocha ( )
175+
176+ // Load only the assigned test file
177+ mocha . files = [ testIdentifier ]
178+ mocha . loadFiles ( )
172179
173180 if ( mocha . suite . total ( ) > 0 ) {
174- // Run the test and complete
175- await codecept . run ( )
181+ // Run only the tests in the current mocha suite
182+ // Don't use codecept.run() as it overwrites mocha.files with ALL test files
183+ await new Promise ( ( resolve , reject ) => {
184+ mocha . run ( ( ) => {
185+ resolve ( )
186+ } )
187+ } )
176188
177189 // Get the results from this specific test run
178190 const result = container . result ( )
@@ -211,9 +223,9 @@ async function runPoolTests() {
211223 // No tests available, exit worker
212224 resolve ( 'NO_MORE_TESTS' )
213225 } else {
214- // Handle other message types (support messages, etc.) and re-add handler
226+ // Handle other message types (support messages, etc.)
215227 container . append ( { support : eventData . data } )
216- parentPort ?. on ( 'message' , messageHandler )
228+ // Don't re-add handler - each test request creates its own one-time handler
217229 }
218230 }
219231
@@ -230,6 +242,9 @@ async function runPoolTests() {
230242 }
231243 }
232244
245+ // Emit event.all.after once at the end of pool mode
246+ event . dispatcher . emit ( event . all . after , codecept )
247+
233248 try {
234249 await codecept . teardown ( )
235250 } catch ( err ) {
@@ -257,68 +272,38 @@ async function runPoolTests() {
257272}
258273
259274function filterTestById ( testUid ) {
260- // Reload test files fresh for each test in pool mode
261- const files = codecept . testFiles
262-
275+ // In pool mode with ESM, test files are already loaded once at initialization
276+ // We just need to filter the existing mocha suite to only include the target test
277+
263278 // Get the existing mocha instance
264279 const mocha = container . mocha ( )
265280
281+ // Save reference to all suites before clearing
282+ const allSuites = [ ...mocha . suite . suites ]
283+
266284 // Clear suites and tests but preserve other mocha settings
267285 mocha . suite . suites = [ ]
268286 mocha . suite . tests = [ ]
269287
270- // Note: ESM doesn't have require.cache, modules are cached by the loader
271- // In ESM, we rely on mocha.loadFiles() to handle test file loading
272-
273- // Set files and load them
274- mocha . files = files
275- mocha . loadFiles ( )
276-
277- // Now filter to only the target test - use a more robust approach
288+ // Find and add only the suite containing our target test
278289 let foundTest = false
279- for ( const suite of mocha . suite . suites ) {
290+ for ( const suite of allSuites ) {
280291 const originalTests = [ ...suite . tests ]
281- suite . tests = [ ]
282-
283- for ( const test of originalTests ) {
284- if ( test . uid === testUid ) {
285- suite . tests . push ( test )
286- foundTest = true
287- break // Only add one matching test
288- }
289- }
290-
291- // If no tests found in this suite, remove it
292- if ( suite . tests . length === 0 ) {
293- suite . parent . suites = suite . parent . suites . filter ( s => s !== suite )
292+
293+ // Check if this suite has our target test
294+ const targetTest = originalTests . find ( test => test . uid === testUid )
295+
296+ if ( targetTest ) {
297+ // Create a filtered suite with only the target test
298+ suite . tests = [ targetTest ]
299+ mocha . suite . suites . push ( suite )
300+ foundTest = true
301+ break // Only include one test
294302 }
295303 }
296304
297- // Filter out empty suites from the root
298- mocha . suite . suites = mocha . suite . suites . filter ( suite => suite . tests . length > 0 )
299-
300305 if ( ! foundTest ) {
301- // If testUid doesn't match, maybe it's a simple test name - try fallback
302- mocha . suite . suites = [ ]
303- mocha . suite . tests = [ ]
304- mocha . loadFiles ( )
305-
306- // Try matching by title
307- for ( const suite of mocha . suite . suites ) {
308- const originalTests = [ ...suite . tests ]
309- suite . tests = [ ]
310-
311- for ( const test of originalTests ) {
312- if ( test . title === testUid || test . fullTitle ( ) === testUid || test . uid === testUid ) {
313- suite . tests . push ( test )
314- foundTest = true
315- break
316- }
317- }
318- }
319-
320- // Clean up empty suites again
321- mocha . suite . suites = mocha . suite . suites . filter ( suite => suite . tests . length > 0 )
306+ console . error ( `WARNING: Test with UID ${ testUid } not found in mocha suites` )
322307 }
323308}
324309
@@ -349,10 +334,11 @@ function initializeListeners() {
349334 const serializableErr = serializeError ( err )
350335 safelySendToParent ( { event : event . test . finished , workerIndex, data : { ...simplifiedData , err : serializableErr } } )
351336 } )
352- event . dispatcher . on ( event . test . failed , ( test , err ) => {
337+ event . dispatcher . on ( event . test . failed , ( test , err , hookName ) => {
353338 const simplifiedData = test . simplify ( )
354339 const serializableErr = serializeError ( err )
355- safelySendToParent ( { event : event . test . failed , workerIndex, data : { ...simplifiedData , err : serializableErr } } )
340+ // Include hookName to identify hook failures
341+ safelySendToParent ( { event : event . test . failed , workerIndex, data : { ...simplifiedData , err : serializableErr , hookName } } )
356342 } )
357343 event . dispatcher . on ( event . test . passed , ( test , err ) => safelySendToParent ( { event : event . test . passed , workerIndex, data : { ...test . simplify ( ) , err } } ) )
358344 event . dispatcher . on ( event . test . started , test => safelySendToParent ( { event : event . test . started , workerIndex, data : test . simplify ( ) } ) )
0 commit comments