@@ -8,7 +8,6 @@ const plur = require('plur');
8
8
const assert = require ( './assert' ) ;
9
9
const formatAssertError = require ( './format-assert-error' ) ;
10
10
const globals = require ( './globals' ) ;
11
- const throwsHelper = require ( './throws-helper' ) ;
12
11
13
12
class SkipApi {
14
13
constructor ( test ) {
@@ -60,6 +59,13 @@ class ExecutionContext {
60
59
61
60
contextRef . context = context ;
62
61
}
62
+
63
+ _throwsArgStart ( assertion , file , line ) {
64
+ this . _test . trackThrows ( { assertion, file, line} ) ;
65
+ }
66
+ _throwsArgEnd ( ) {
67
+ this . _test . trackThrows ( null ) ;
68
+ }
63
69
}
64
70
Object . defineProperty ( ExecutionContext . prototype , 'context' , { enumerable : true } ) ;
65
71
@@ -101,9 +107,11 @@ class Test {
101
107
this . calledEnd = false ;
102
108
this . duration = null ;
103
109
this . endCallbackFinisher = null ;
110
+ this . finishDueToAttributedError = null ;
104
111
this . finishDueToInactivity = null ;
105
112
this . finishing = false ;
106
113
this . pendingAssertions = [ ] ;
114
+ this . pendingThrowsAssertion = null ;
107
115
this . planCount = null ;
108
116
this . startedAt = 0 ;
109
117
}
@@ -204,6 +212,60 @@ class Test {
204
212
}
205
213
}
206
214
215
+ trackThrows ( pending ) {
216
+ this . pendingThrowsAssertion = pending ;
217
+ }
218
+
219
+ detectImproperThrows ( err ) {
220
+ if ( ! this . pendingThrowsAssertion ) {
221
+ return false ;
222
+ }
223
+
224
+ const pending = this . pendingThrowsAssertion ;
225
+ this . pendingThrowsAssertion = null ;
226
+
227
+ const values = [ ] ;
228
+ if ( err ) {
229
+ values . push ( formatAssertError . formatWithLabel ( `The following error was thrown, possibly before \`t.${ pending . assertion } ()\` could be called:` , err ) ) ;
230
+ }
231
+
232
+ this . saveFirstError ( new assert . AssertionError ( {
233
+ assertion : pending . assertion ,
234
+ fixedSource : { file : pending . file , line : pending . line } ,
235
+ improperUsage : true ,
236
+ message : `Improper usage of \`t.${ pending . assertion } ()\` detected` ,
237
+ stack : err instanceof Error && err . stack ,
238
+ values
239
+ } ) ) ;
240
+ return true ;
241
+ }
242
+
243
+ waitForPendingThrowsAssertion ( ) {
244
+ return new Promise ( resolve => {
245
+ this . finishDueToAttributedError = ( ) => {
246
+ resolve ( this . finishPromised ( ) ) ;
247
+ } ;
248
+
249
+ this . finishDueToInactivity = ( ) => {
250
+ this . detectImproperThrows ( ) ;
251
+ resolve ( this . finishPromised ( ) ) ;
252
+ } ;
253
+
254
+ // Wait up to a second to see if an error can be attributed to the
255
+ // pending assertion.
256
+ globals . setTimeout ( ( ) => this . finishDueToInactivity ( ) , 1000 ) . unref ( ) ;
257
+ } ) ;
258
+ }
259
+
260
+ attributeLeakedError ( err ) {
261
+ if ( ! this . detectImproperThrows ( err ) ) {
262
+ return false ;
263
+ }
264
+
265
+ this . finishDueToAttributedError ( ) ;
266
+ return true ;
267
+ }
268
+
207
269
callFn ( ) {
208
270
try {
209
271
return {
@@ -223,13 +285,13 @@ class Test {
223
285
224
286
const result = this . callFn ( ) ;
225
287
if ( ! result . ok ) {
226
- throwsHelper ( result . error ) ;
227
-
228
- this . saveFirstError ( new assert . AssertionError ( {
229
- message : 'Error thrown in test' ,
230
- stack : result . error instanceof Error && result . error . stack ,
231
- values : [ formatAssertError . formatWithLabel ( 'Error:' , result . error ) ]
232
- } ) ) ;
288
+ if ( ! this . detectImproperThrows ( result . error ) ) {
289
+ this . saveFirstError ( new assert . AssertionError ( {
290
+ message : 'Error thrown in test' ,
291
+ stack : result . error instanceof Error && result . error . stack ,
292
+ values : [ formatAssertError . formatWithLabel ( ' Error:' , result . error ) ]
293
+ } ) ) ;
294
+ }
233
295
return this . finish ( ) ;
234
296
}
235
297
@@ -260,6 +322,10 @@ class Test {
260
322
resolve ( this . finishPromised ( ) ) ;
261
323
} ;
262
324
325
+ this . finishDueToAttributedError = ( ) => {
326
+ resolve ( this . finishPromised ( ) ) ;
327
+ } ;
328
+
263
329
this . finishDueToInactivity = ( ) => {
264
330
this . saveFirstError ( new Error ( '`t.end()` was never called' ) ) ;
265
331
resolve ( this . finishPromised ( ) ) ;
@@ -269,6 +335,10 @@ class Test {
269
335
270
336
if ( promise ) {
271
337
return new Promise ( resolve => {
338
+ this . finishDueToAttributedError = ( ) => {
339
+ resolve ( this . finishPromised ( ) ) ;
340
+ } ;
341
+
272
342
this . finishDueToInactivity = ( ) => {
273
343
const err = returnedObservable ?
274
344
new Error ( 'Observable returned by test never completed' ) :
@@ -279,13 +349,13 @@ class Test {
279
349
280
350
promise
281
351
. catch ( err => {
282
- throwsHelper ( err ) ;
283
-
284
- this . saveFirstError ( new assert . AssertionError ( {
285
- message : 'Rejected promise returned by test' ,
286
- stack : err instanceof Error && err . stack ,
287
- values : [ formatAssertError . formatWithLabel ( 'Rejection reason:' , err ) ]
288
- } ) ) ;
352
+ if ( ! this . detectImproperThrows ( err ) ) {
353
+ this . saveFirstError ( new assert . AssertionError ( {
354
+ message : 'Rejected promise returned by test' ,
355
+ stack : err instanceof Error && err . stack ,
356
+ values : [ formatAssertError . formatWithLabel ( 'Rejection reason:' , err ) ]
357
+ } ) ) ;
358
+ }
289
359
} )
290
360
. then ( ( ) => resolve ( this . finishPromised ( ) ) ) ;
291
361
} ) ;
@@ -296,6 +366,11 @@ class Test {
296
366
297
367
finish ( ) {
298
368
this . finishing = true ;
369
+
370
+ if ( ! this . assertError && this . pendingThrowsAssertion ) {
371
+ return this . waitForPendingThrowsAssertion ( ) ;
372
+ }
373
+
299
374
this . verifyPlan ( ) ;
300
375
this . verifyAssertions ( ) ;
301
376
0 commit comments