@@ -72,6 +72,11 @@ function isTestFailure(testResult) {
7272 return testResult === TestResult . Failed || testResult === TestResult . TimedOut || testResult === TestResult . Crashed ;
7373}
7474
75+ function createHook ( callback , name ) {
76+ const location = getCallerLocation ( __filename ) ;
77+ return { name, body : callback , location } ;
78+ }
79+
7580class Test {
7681 constructor ( suite , name , callback , location ) {
7782 this . _suite = suite ;
@@ -83,6 +88,7 @@ class Test {
8388 this . _location = location ;
8489 this . _timeout = INFINITE_TIMEOUT ;
8590 this . _repeat = 1 ;
91+ this . _hooks = [ ] ;
8692
8793 // Test results. TODO: make these private.
8894 this . result = null ;
@@ -100,6 +106,7 @@ class Test {
100106 test . _timeout = this . _timeout ;
101107 test . _mode = this . _mode ;
102108 test . _expectation = this . _expectation ;
109+ test . _hooks = this . _hooks . slice ( ) ;
103110 return test ;
104111 }
105112
@@ -155,6 +162,18 @@ class Test {
155162 setRepeat ( repeat ) {
156163 this . _repeat = repeat ;
157164 }
165+
166+ before ( callback ) {
167+ this . _hooks . push ( createHook ( callback , 'before' ) ) ;
168+ }
169+
170+ after ( callback ) {
171+ this . _hooks . push ( createHook ( callback , 'after' ) ) ;
172+ }
173+
174+ hooks ( name ) {
175+ return this . _hooks . filter ( hook => ! name || hook . name === name ) ;
176+ }
158177}
159178
160179class Suite {
@@ -166,12 +185,7 @@ class Suite {
166185 this . _expectation = TestExpectation . Ok ;
167186 this . _location = location ;
168187 this . _repeat = 1 ;
169-
170- // TODO: make these private.
171- this . beforeAll = null ;
172- this . beforeEach = null ;
173- this . afterAll = null ;
174- this . afterEach = null ;
188+ this . _hooks = [ ] ;
175189
176190 this . Modes = { ...TestMode } ;
177191 this . Expectations = { ...TestExpectation } ;
@@ -225,6 +239,26 @@ class Suite {
225239 setRepeat ( repeat ) {
226240 this . _repeat = repeat ;
227241 }
242+
243+ beforeEach ( callback ) {
244+ this . _hooks . push ( createHook ( callback , 'beforeEach' ) ) ;
245+ }
246+
247+ afterEach ( callback ) {
248+ this . _hooks . push ( createHook ( callback , 'afterEach' ) ) ;
249+ }
250+
251+ beforeAll ( callback ) {
252+ this . _hooks . push ( createHook ( callback , 'beforeAll' ) ) ;
253+ }
254+
255+ afterAll ( callback ) {
256+ this . _hooks . push ( createHook ( callback , 'afterAll' ) ) ;
257+ }
258+
259+ hooks ( name ) {
260+ return this . _hooks . filter ( hook => ! name || hook . name === name ) ;
261+ }
228262}
229263
230264class Result {
@@ -330,16 +364,20 @@ class TestWorker {
330364 if ( this . _markTerminated ( test ) )
331365 return ;
332366 const suite = this . _suiteStack . pop ( ) ;
333- if ( ! await this . _runHook ( test , suite , 'afterAll' ) )
334- return ;
367+ for ( const hook of suite . hooks ( 'afterAll' ) ) {
368+ if ( ! await this . _runHook ( test , hook , suite . fullName ( ) ) )
369+ return ;
370+ }
335371 }
336372 while ( this . _suiteStack . length < suiteStack . length ) {
337373 if ( this . _markTerminated ( test ) )
338374 return ;
339375 const suite = suiteStack [ this . _suiteStack . length ] ;
340376 this . _suiteStack . push ( suite ) ;
341- if ( ! await this . _runHook ( test , suite , 'beforeAll' ) )
342- return ;
377+ for ( const hook of suite . hooks ( 'beforeAll' ) ) {
378+ if ( ! await this . _runHook ( test , hook , suite . fullName ( ) ) )
379+ return ;
380+ }
343381 }
344382
345383 if ( this . _markTerminated ( test ) )
@@ -349,8 +387,12 @@ class TestWorker {
349387 // no matter what happens.
350388
351389 await this . _testPass . _willStartTest ( this , test ) ;
352- for ( let i = 0 ; i < this . _suiteStack . length ; i ++ )
353- await this . _runHook ( test , this . _suiteStack [ i ] , 'beforeEach' ) ;
390+ for ( const suite of this . _suiteStack ) {
391+ for ( const hook of suite . hooks ( 'beforeEach' ) )
392+ await this . _runHook ( test , hook , suite . fullName ( ) , true ) ;
393+ }
394+ for ( const hook of test . hooks ( 'before' ) )
395+ await this . _runHook ( test , hook , test . fullName ( ) , true ) ;
354396
355397 if ( ! test . error && ! this . _markTerminated ( test ) ) {
356398 await this . _testPass . _willStartTestBody ( this , test ) ;
@@ -371,19 +413,19 @@ class TestWorker {
371413 await this . _testPass . _didFinishTestBody ( this , test ) ;
372414 }
373415
374- for ( let i = this . _suiteStack . length - 1 ; i >= 0 ; i -- )
375- await this . _runHook ( test , this . _suiteStack [ i ] , 'afterEach' ) ;
416+ for ( const hook of test . hooks ( 'after' ) )
417+ await this . _runHook ( test , hook , test . fullName ( ) , true ) ;
418+ for ( const suite of this . _suiteStack . slice ( ) . reverse ( ) ) {
419+ for ( const hook of suite . hooks ( 'afterEach' ) )
420+ await this . _runHook ( test , hook , suite . fullName ( ) , true ) ;
421+ }
376422 await this . _testPass . _didFinishTest ( this , test ) ;
377423 }
378424
379- async _runHook ( test , suite , hookName ) {
380- const hook = suite [ hookName ] ;
381- if ( ! hook )
382- return true ;
383-
384- await this . _testPass . _willStartHook ( this , suite , hook . location , hookName ) ;
425+ async _runHook ( test , hook , fullName , passTest = false ) {
426+ await this . _testPass . _willStartHook ( this , hook , fullName ) ;
385427 const timeout = this . _testPass . _runner . _timeout ;
386- const { promise, terminate } = runUserCallback ( hook . body , timeout , [ this . _state , test ] ) ;
428+ const { promise, terminate } = runUserCallback ( hook . body , timeout , passTest ? [ this . _state , test ] : [ this . _state ] ) ;
387429 this . _runningHookTerminate = terminate ;
388430 let error = await promise ;
389431 this . _runningHookTerminate = null ;
@@ -396,7 +438,7 @@ class TestWorker {
396438 }
397439 let message ;
398440 if ( error === TimeoutError ) {
399- message = `${ locationString } - Timeout Exceeded ${ timeout } ms while running "${ hookName } " in suite "${ suite . fullName ( ) } "` ;
441+ message = `${ locationString } - Timeout Exceeded ${ timeout } ms while running "${ hook . name } " in "${ fullName } "` ;
400442 error = null ;
401443 } else if ( error === TerminatedError ) {
402444 // Do not report termination details - it's just noise.
@@ -405,21 +447,22 @@ class TestWorker {
405447 } else {
406448 if ( error . stack )
407449 await this . _testPass . _runner . _sourceMapSupport . rewriteStackTraceWithSourceMaps ( error ) ;
408- message = `${ locationString } - FAILED while running "${ hookName } " in suite "${ suite . fullName ( ) } ": ` ;
450+ message = `${ locationString } - FAILED while running "${ hook . name } " in suite "${ fullName } ": ` ;
409451 }
410- await this . _testPass . _didFailHook ( this , suite , hook . location , hookName , message , error ) ;
452+ await this . _testPass . _didFailHook ( this , hook , fullName , message , error ) ;
411453 test . error = error ;
412454 return false ;
413455 }
414456
415- await this . _testPass . _didCompleteHook ( this , suite , hook . location , hookName ) ;
457+ await this . _testPass . _didCompleteHook ( this , hook , fullName ) ;
416458 return true ;
417459 }
418460
419461 async shutdown ( ) {
420462 while ( this . _suiteStack . length > 0 ) {
421463 const suite = this . _suiteStack . pop ( ) ;
422- await this . _runHook ( { } , suite , 'afterAll' ) ;
464+ for ( const hook of suite . hooks ( 'afterAll' ) )
465+ await this . _runHook ( { } , hook , suite . fullName ( ) ) ;
423466 }
424467 }
425468}
@@ -542,19 +585,19 @@ class TestPass {
542585 debug ( 'testrunner:test' ) ( `[${ worker . _workerId } ] ${ test . result . toUpperCase ( ) } "${ test . fullName ( ) } " (${ test . location ( ) . fileName + ':' + test . location ( ) . lineNumber } )` ) ;
543586 }
544587
545- async _willStartHook ( worker , suite , location , hookName ) {
546- debug ( 'testrunner:hook' ) ( `[${ worker . _workerId } ] "${ hookName } " started for "${ suite . fullName ( ) } " (${ location . fileName + ':' + location . lineNumber } )` ) ;
588+ async _willStartHook ( worker , hook , fullName ) {
589+ debug ( 'testrunner:hook' ) ( `[${ worker . _workerId } ] "${ hook . name } " started for "${ fullName } " (${ hook . location . fileName + ':' + hook . location . lineNumber } )` ) ;
547590 }
548591
549- async _didFailHook ( worker , suite , location , hookName , message , error ) {
550- debug ( 'testrunner:hook' ) ( `[${ worker . _workerId } ] "${ hookName } " FAILED for "${ suite . fullName ( ) } " (${ location . fileName + ':' + location . lineNumber } )` ) ;
592+ async _didFailHook ( worker , hook , fullName , message , error ) {
593+ debug ( 'testrunner:hook' ) ( `[${ worker . _workerId } ] "${ hook . name } " FAILED for "${ fullName } " (${ hook . location . fileName + ':' + hook . location . lineNumber } )` ) ;
551594 if ( message )
552595 this . _result . addError ( message , error , worker ) ;
553596 this . _result . setResult ( TestResult . Crashed , message ) ;
554597 }
555598
556- async _didCompleteHook ( worker , suite , location , hookName ) {
557- debug ( 'testrunner:hook' ) ( `[${ worker . _workerId } ] "${ hookName } " OK for "${ suite . fullName ( ) } " (${ location . fileName + ':' + location . lineNumber } )` ) ;
599+ async _didCompleteHook ( worker , hook , fullName ) {
600+ debug ( 'testrunner:hook' ) ( `[${ worker . _workerId } ] "${ hook . name } " OK for "${ fullName } " (${ hook . location . fileName + ':' + hook . location . lineNumber } )` ) ;
558601 }
559602}
560603
@@ -593,10 +636,10 @@ class TestRunner extends EventEmitter {
593636
594637 this . _debuggerLogBreakpointLines = new Multimap ( ) ;
595638
596- this . beforeAll = this . _addHook . bind ( this , ' beforeAll' ) ;
597- this . beforeEach = this . _addHook . bind ( this , ' beforeEach' ) ;
598- this . afterAll = this . _addHook . bind ( this , ' afterAll' ) ;
599- this . afterEach = this . _addHook . bind ( this , ' afterEach' ) ;
639+ this . beforeAll = ( callback ) => this . _currentSuite . beforeAll ( callback ) ;
640+ this . beforeEach = ( callback ) => this . _currentSuite . beforeEach ( callback ) ;
641+ this . afterAll = ( callback ) => this . _currentSuite . afterAll ( callback ) ;
642+ this . afterEach = ( callback ) => this . _currentSuite . afterEach ( callback ) ;
600643
601644 this . describe = this . _suiteBuilder ( [ ] ) ;
602645 this . it = this . _testBuilder ( [ ] ) ;
@@ -694,12 +737,6 @@ class TestRunner extends EventEmitter {
694737 this . describe . skip ( true ) ( '' , module . xdescribe , ...args ) ;
695738 }
696739
697- _addHook ( hookName , callback ) {
698- assert ( this . _currentSuite [ hookName ] === null , `Only one ${ hookName } hook available per suite` ) ;
699- const location = getCallerLocation ( __filename ) ;
700- this . _currentSuite [ hookName ] = { body : callback , location } ;
701- }
702-
703740 async run ( options = { } ) {
704741 const { totalTimeout = 0 } = options ;
705742 let session = this . _debuggerLogBreakpointLines . size ? await setLogBreakpoints ( this . _debuggerLogBreakpointLines ) : null ;
0 commit comments