@@ -58,6 +58,8 @@ function test(test) {
5858 test . fn = function ( done ) {
5959 const doneFn = makeDoneCallableOnce ( done )
6060 let testPassed = false
61+ let testFailed = false
62+
6163 // Ensure recorder is running so any steps added inside test function are executed
6264 recorder . startUnlessRunning ( )
6365 // Fire before event first, then started event so listeners are notified prior to queued steps
@@ -66,10 +68,12 @@ function test(test) {
6668 recorder . errHandler ( err => {
6769 recorder . session . start ( 'teardown' )
6870 recorder . cleanAsyncErr ( )
71+ testFailed = true
6972 if ( test . throws ) {
70- // check that test should actually fail
73+ // check that test should actually fail with expected error
7174 try {
7275 assertThrown ( err , test . throws )
76+ // If assertThrown doesn't throw, it means the error matches the expected error
7377 if ( ! testPassed ) {
7478 testPassed = true
7579 event . emit ( event . test . passed , test )
@@ -87,6 +91,7 @@ function test(test) {
8791 err = newErr
8892 }
8993 }
94+ // If test.throws is not set, or if the error doesn't match expected, fail the test
9095 test . err = err
9196 event . emit ( event . test . failed , test , err )
9297 event . emit ( event . test . finished , test )
@@ -107,20 +112,60 @@ function test(test) {
107112 if ( isAsyncFunction ( testFn ) ) await res
108113 } )
109114 recorder . add ( 'restore test session' , ( ) => recorder . session . restore ( 'test' ) )
110- recorder . add ( 'fire test.passed' , ( ) => {
111- if ( ! testPassed ) {
112- testPassed = true
113- event . emit ( event . test . passed , test )
114- }
115- event . emit ( event . test . finished , test )
116- // Add test.after to the queue after event listeners have added their operations
117- process . nextTick ( ( ) => {
118- recorder . add ( 'fire test.after' , ( ) => {
119- event . emit ( event . test . after , test )
115+
116+ // Check if test has retries configured
117+ const hasRetries = test . retries && test . retries ( ) > 0
118+
119+ if ( hasRetries ) {
120+ // For retry tests, use the original approach
121+ recorder . add ( 'fire test.passed' , ( ) => {
122+ if ( ! testPassed ) {
123+ testPassed = true
124+ event . emit ( event . test . passed , test )
125+ }
126+ event . emit ( event . test . finished , test )
127+ // Add test.after to the queue after event listeners have added their operations
128+ process . nextTick ( ( ) => {
129+ recorder . add ( 'fire test.after' , ( ) => {
130+ event . emit ( event . test . after , test )
131+ } )
120132 } )
121133 } )
122- } )
123- recorder . add ( 'finish test' , doneFn )
134+ recorder . add ( 'finish test' , ( ) => {
135+ doneFn ( )
136+ } )
137+ } else {
138+ // For non-retry tests, use the delayed approach to fix error propagation
139+ // Use longer delay for BDD tests since they have async step execution
140+ const delay = test . title && test . title . includes ( 'bdd' ) ? 100 : 10
141+ setTimeout ( ( ) => {
142+ recorder . add ( 'fire test.passed' , ( ) => {
143+ // Only emit test.passed if test hasn't failed and hasn't already passed
144+ if ( ! testPassed && ! testFailed && ! test . err ) {
145+ testPassed = true
146+ event . emit ( event . test . passed , test )
147+ }
148+ // Only emit test.finished if test hasn't failed
149+ if ( ! testFailed && ! test . err ) {
150+ event . emit ( event . test . finished , test )
151+ }
152+ // Add test.after to the queue after event listeners have added their operations
153+ process . nextTick ( ( ) => {
154+ recorder . add ( 'fire test.after' , ( ) => {
155+ event . emit ( event . test . after , test )
156+ } )
157+ } )
158+ } )
159+
160+ recorder . add ( 'finish test' , ( ) => {
161+ if ( test . err ) {
162+ doneFn ( test . err )
163+ } else {
164+ doneFn ( )
165+ }
166+ } )
167+ } , delay ) // Variable delay based on test type
168+ }
124169 recorder . catch ( )
125170 }
126171 return test
0 commit comments