@@ -66,6 +66,10 @@ class TestContext {
6666 this . #test = test ;
6767 }
6868
69+ get name ( ) {
70+ return this . #test. name ;
71+ }
72+
6973 diagnostic ( message ) {
7074 this . #test. diagnostic ( message ) ;
7175 }
@@ -88,6 +92,14 @@ class TestContext {
8892
8993 return subtest . start ( ) ;
9094 }
95+
96+ beforeEach ( fn , options ) {
97+ this . #test. createBeforeEachHook ( fn , options ) ;
98+ }
99+
100+ afterEach ( fn , options ) {
101+ this . #test. createAfterEachHook ( fn , options ) ;
102+ }
91103}
92104
93105class Test extends AsyncResource {
@@ -165,6 +177,8 @@ class Test extends AsyncResource {
165177 this . pendingSubtests = [ ] ;
166178 this . readySubtests = new SafeMap ( ) ;
167179 this . subtests = [ ] ;
180+ this . beforeEachHooks = [ ] ;
181+ this . afterEachHooks = [ ] ;
168182 this . waitingOn = 0 ;
169183 this . finished = false ;
170184 }
@@ -267,6 +281,18 @@ class Test extends AsyncResource {
267281 return test ;
268282 }
269283
284+ createBeforeEachHook ( fn , options ) {
285+ const hook = new TestHook ( fn , options ) ;
286+ ArrayPrototypePush ( this . beforeEachHooks , hook ) ;
287+ return hook ;
288+ }
289+
290+ createAfterEachHook ( fn , options ) {
291+ const hook = new TestHook ( fn , options ) ;
292+ ArrayPrototypePush ( this . afterEachHooks , hook ) ;
293+ return hook ;
294+ }
295+
270296 cancel ( ) {
271297 if ( this . endTime !== null ) {
272298 return ;
@@ -278,6 +304,7 @@ class Test extends AsyncResource {
278304 kCancelledByParent
279305 )
280306 ) ;
307+ this . startTime = this . startTime || this . endTime ; // if a test was canceled before it was started, e.g inside a hook
281308 this . cancelled = true ;
282309 }
283310
@@ -334,12 +361,24 @@ class Test extends AsyncResource {
334361 return { ctx, args : [ ctx ] } ;
335362 }
336363
337- async run ( ) {
338- this . parent . activeSubtests ++ ;
364+ async #runHooks( hooks ) {
365+ await ArrayPrototypeReduce ( hooks , async ( prev , hook ) => {
366+ await prev ;
367+ await hook . run ( this . getRunArgs ( ) ) ;
368+ } , PromiseResolve ( ) ) ;
369+ }
370+
371+ async run ( ...runArgs ) {
372+ if ( this . parent !== null ) {
373+ this . parent . activeSubtests ++ ;
374+ }
375+ if ( this . parent ?. beforeEachHooks . length > 0 ) {
376+ await this . #runHooks( this . parent . beforeEachHooks ) ;
377+ }
339378 this . startTime = hrtime ( ) ;
340379
341380 try {
342- const { args, ctx } = this . getRunArgs ( ) ;
381+ const { args, ctx } = ReflectApply ( this . getRunArgs , this , runArgs ) ;
343382 ArrayPrototypeUnshift ( args , this . fn , ctx ) ; // Note that if it's not OK to mutate args, we need to first clone it.
344383
345384 if ( this . fn . length === args . length - 1 ) {
@@ -372,9 +411,13 @@ class Test extends AsyncResource {
372411 }
373412 }
374413
414+ if ( this . parent ?. afterEachHooks . length > 0 ) {
415+ await this . #runHooks( this . parent . afterEachHooks ) ;
416+ }
417+
375418 // Clean up the test. Then, try to report the results and execute any
376419 // tests that were pending due to available concurrency.
377- this . postRun ( ) ;
420+ await this . postRun ( ) ;
378421 }
379422
380423 postRun ( ) {
@@ -413,7 +456,7 @@ class Test extends AsyncResource {
413456 this . parent . activeSubtests -- ;
414457 this . parent . addReadySubtest ( this ) ;
415458 this . parent . processReadySubtestRange ( false ) ;
416- this . parent . processPendingSubtests ( ) ;
459+ return this . parent . processPendingSubtests ( ) ;
417460 }
418461 }
419462
@@ -473,10 +516,23 @@ class Test extends AsyncResource {
473516 }
474517}
475518
519+ class TestHook extends Test {
520+ constructor ( fn , options ) {
521+ if ( options === null || typeof options !== 'object' ) {
522+ options = kEmptyObject ;
523+ }
524+ super ( { fn, ...options } ) ;
525+ }
526+ getRunArgs ( testContext ) {
527+ return testContext ;
528+ }
529+ }
530+
476531class ItTest extends Test {
477532 constructor ( opt ) { super ( opt ) ; } // eslint-disable-line no-useless-constructor
478533 getRunArgs ( ) {
479- return { ctx : { } , args : [ ] } ;
534+ const ctx = new TestContext ( this ) ;
535+ return { ctx, args : [ ] } ;
480536 }
481537}
482538class Suite extends Test {
0 commit comments