ava 3.15.0 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. package/entrypoints/cli.mjs +4 -0
  2. package/entrypoints/eslint-plugin-helper.cjs +109 -0
  3. package/entrypoints/main.cjs +2 -0
  4. package/entrypoints/main.mjs +1 -0
  5. package/entrypoints/plugin.cjs +2 -0
  6. package/entrypoints/plugin.mjs +4 -0
  7. package/index.d.ts +6 -816
  8. package/lib/api.js +108 -49
  9. package/lib/assert.js +255 -270
  10. package/lib/chalk.js +9 -14
  11. package/lib/cli.js +118 -112
  12. package/lib/code-excerpt.js +12 -17
  13. package/lib/concordance-options.js +29 -65
  14. package/lib/context-ref.js +3 -6
  15. package/lib/create-chain.js +32 -20
  16. package/lib/environment-variables.js +1 -4
  17. package/lib/eslint-plugin-helper-worker.js +73 -0
  18. package/lib/extensions.js +2 -2
  19. package/lib/fork.js +81 -84
  20. package/lib/glob-helpers.cjs +140 -0
  21. package/lib/globs.js +136 -163
  22. package/lib/{ipc-flow-control.js → ipc-flow-control.cjs} +1 -0
  23. package/lib/is-ci.js +4 -2
  24. package/lib/like-selector.js +7 -13
  25. package/lib/line-numbers.js +11 -18
  26. package/lib/load-config.js +56 -180
  27. package/lib/module-types.js +3 -7
  28. package/lib/node-arguments.js +4 -5
  29. package/lib/{now-and-timers.js → now-and-timers.cjs} +0 -0
  30. package/lib/parse-test-args.js +22 -11
  31. package/lib/pkg.cjs +2 -0
  32. package/lib/plugin-support/shared-worker-loader.js +45 -48
  33. package/lib/plugin-support/shared-workers.js +24 -46
  34. package/lib/provider-manager.js +20 -14
  35. package/lib/reporters/beautify-stack.js +6 -12
  36. package/lib/reporters/colors.js +40 -15
  37. package/lib/reporters/default.js +114 -364
  38. package/lib/reporters/format-serialized-error.js +7 -18
  39. package/lib/reporters/improper-usage-messages.js +8 -9
  40. package/lib/reporters/prefix-title.js +17 -15
  41. package/lib/reporters/tap.js +18 -25
  42. package/lib/run-status.js +29 -23
  43. package/lib/runner.js +157 -172
  44. package/lib/scheduler.js +53 -0
  45. package/lib/serialize-error.js +61 -64
  46. package/lib/snapshot-manager.js +271 -289
  47. package/lib/test.js +135 -291
  48. package/lib/watcher.js +69 -44
  49. package/lib/worker/base.js +208 -0
  50. package/lib/worker/channel.cjs +290 -0
  51. package/lib/worker/dependency-tracker.js +24 -23
  52. package/lib/worker/{ensure-forked.js → guard-environment.cjs} +5 -4
  53. package/lib/worker/line-numbers.js +58 -20
  54. package/lib/worker/main.cjs +12 -0
  55. package/lib/worker/{options.js → options.cjs} +0 -0
  56. package/lib/worker/{plugin.js → plugin.cjs} +30 -21
  57. package/lib/worker/state.cjs +5 -0
  58. package/lib/worker/utils.cjs +6 -0
  59. package/package.json +71 -68
  60. package/plugin.d.ts +51 -53
  61. package/readme.md +5 -13
  62. package/types/assertions.d.ts +327 -0
  63. package/types/subscribable.ts +6 -0
  64. package/types/test-fn.d.ts +231 -0
  65. package/types/try-fn.d.ts +58 -0
  66. package/cli.js +0 -11
  67. package/eslint-plugin-helper.js +0 -201
  68. package/index.js +0 -8
  69. package/lib/worker/ipc.js +0 -201
  70. package/lib/worker/main.js +0 -21
  71. package/lib/worker/subprocess.js +0 -266
  72. package/plugin.js +0 -9
package/lib/assert.js CHANGED
@@ -1,23 +1,23 @@
1
- 'use strict';
2
- const concordance = require('concordance');
3
- const isError = require('is-error');
4
- const isPromise = require('is-promise');
5
- const concordanceOptions = require('./concordance-options').default;
6
- const {CIRCULAR_SELECTOR, isLikeSelector, selectComparable} = require('./like-selector');
7
- const snapshotManager = require('./snapshot-manager');
1
+ import concordance from 'concordance';
2
+ import isError from 'is-error';
3
+ import isPromise from 'is-promise';
4
+
5
+ import concordanceOptions from './concordance-options.js';
6
+ import {CIRCULAR_SELECTOR, isLikeSelector, selectComparable} from './like-selector.js';
7
+ import {SnapshotError, VersionMismatchError} from './snapshot-manager.js';
8
8
 
9
9
  function formatDescriptorDiff(actualDescriptor, expectedDescriptor, options) {
10
10
  options = {...options, ...concordanceOptions};
11
11
  return {
12
12
  label: 'Difference:',
13
- formatted: concordance.diffDescriptors(actualDescriptor, expectedDescriptor, options)
13
+ formatted: concordance.diffDescriptors(actualDescriptor, expectedDescriptor, options),
14
14
  };
15
15
  }
16
16
 
17
17
  function formatDescriptorWithLabel(label, descriptor) {
18
18
  return {
19
19
  label,
20
- formatted: concordance.formatDescriptor(descriptor, concordanceOptions)
20
+ formatted: concordance.formatDescriptor(descriptor, concordanceOptions),
21
21
  };
22
22
  }
23
23
 
@@ -25,17 +25,13 @@ function formatWithLabel(label, value) {
25
25
  return formatDescriptorWithLabel(label, concordance.describe(value, concordanceOptions));
26
26
  }
27
27
 
28
- function formatPowerAssertValue(value) {
29
- return concordance.format(value, concordanceOptions);
30
- }
31
-
32
28
  const hasOwnProperty = (object, prop) => Object.prototype.hasOwnProperty.call(object, prop);
33
29
  const noop = () => {};
34
30
  const notImplemented = () => {
35
31
  throw new Error('not implemented');
36
32
  };
37
33
 
38
- class AssertionError extends Error {
34
+ export class AssertionError extends Error {
39
35
  constructor(options) {
40
36
  super(options.message || '');
41
37
  this.name = 'AssertionError';
@@ -52,19 +48,11 @@ class AssertionError extends Error {
52
48
  // use the values for custom diff views
53
49
  this.raw = options.raw;
54
50
 
55
- // Reserved for power-assert statements
56
- this.statements = [];
57
-
58
- if (options.savedError) {
59
- this.savedError = options.savedError;
60
- } else {
61
- this.savedError = getErrorWithLongStackTrace();
62
- }
51
+ this.savedError = options.savedError ? options.savedError : getErrorWithLongStackTrace();
63
52
  }
64
53
  }
65
- exports.AssertionError = AssertionError;
66
54
 
67
- function checkAssertionMessage(assertion, message) {
55
+ export function checkAssertionMessage(assertion, message) {
68
56
  if (typeof message === 'undefined' || typeof message === 'string') {
69
57
  return true;
70
58
  }
@@ -73,50 +61,48 @@ function checkAssertionMessage(assertion, message) {
73
61
  assertion,
74
62
  improperUsage: true,
75
63
  message: 'The assertion message must be a string',
76
- values: [formatWithLabel('Called with:', message)]
64
+ values: [formatWithLabel('Called with:', message)],
77
65
  });
78
66
  }
79
67
 
80
- exports.checkAssertionMessage = checkAssertionMessage;
81
-
82
68
  function getErrorWithLongStackTrace() {
83
69
  const limitBefore = Error.stackTraceLimit;
84
- Error.stackTraceLimit = Infinity;
85
- const err = new Error();
70
+ Error.stackTraceLimit = Number.POSITIVE_INFINITY;
71
+ const error = new Error(); // eslint-disable-line unicorn/error-message
86
72
  Error.stackTraceLimit = limitBefore;
87
- return err;
73
+ return error;
88
74
  }
89
75
 
90
- function validateExpectations(assertion, expectations, numberArgs, experiments) { // eslint-disable-line complexity
76
+ function validateExpectations(assertion, expectations, numberArgs) { // eslint-disable-line complexity
91
77
  if (numberArgs === 1 || expectations === null || expectations === undefined) {
92
- if (experiments.disableNullExpectations && expectations === null) {
78
+ if (expectations === null) {
93
79
  throw new AssertionError({
94
80
  assertion,
95
81
  message: `The second argument to \`t.${assertion}()\` must be an expectation object or \`undefined\``,
96
- values: [formatWithLabel('Called with:', expectations)]
82
+ values: [formatWithLabel('Called with:', expectations)],
97
83
  });
98
84
  }
99
85
 
100
86
  expectations = {};
101
87
  } else if (
102
- typeof expectations === 'function' ||
103
- typeof expectations === 'string' ||
104
- expectations instanceof RegExp ||
105
- typeof expectations !== 'object' ||
106
- Array.isArray(expectations) ||
107
- Object.keys(expectations).length === 0
88
+ typeof expectations === 'function'
89
+ || typeof expectations === 'string'
90
+ || expectations instanceof RegExp
91
+ || typeof expectations !== 'object'
92
+ || Array.isArray(expectations)
93
+ || Object.keys(expectations).length === 0
108
94
  ) {
109
95
  throw new AssertionError({
110
96
  assertion,
111
97
  message: `The second argument to \`t.${assertion}()\` must be an expectation object, \`null\` or \`undefined\``,
112
- values: [formatWithLabel('Called with:', expectations)]
98
+ values: [formatWithLabel('Called with:', expectations)],
113
99
  });
114
100
  } else {
115
101
  if (hasOwnProperty(expectations, 'instanceOf') && typeof expectations.instanceOf !== 'function') {
116
102
  throw new AssertionError({
117
103
  assertion,
118
104
  message: `The \`instanceOf\` property of the second argument to \`t.${assertion}()\` must be a function`,
119
- values: [formatWithLabel('Called with:', expectations)]
105
+ values: [formatWithLabel('Called with:', expectations)],
120
106
  });
121
107
  }
122
108
 
@@ -124,7 +110,7 @@ function validateExpectations(assertion, expectations, numberArgs, experiments)
124
110
  throw new AssertionError({
125
111
  assertion,
126
112
  message: `The \`message\` property of the second argument to \`t.${assertion}()\` must be a string or regular expression`,
127
- values: [formatWithLabel('Called with:', expectations)]
113
+ values: [formatWithLabel('Called with:', expectations)],
128
114
  });
129
115
  }
130
116
 
@@ -132,7 +118,7 @@ function validateExpectations(assertion, expectations, numberArgs, experiments)
132
118
  throw new AssertionError({
133
119
  assertion,
134
120
  message: `The \`name\` property of the second argument to \`t.${assertion}()\` must be a string`,
135
- values: [formatWithLabel('Called with:', expectations)]
121
+ values: [formatWithLabel('Called with:', expectations)],
136
122
  });
137
123
  }
138
124
 
@@ -140,7 +126,7 @@ function validateExpectations(assertion, expectations, numberArgs, experiments)
140
126
  throw new AssertionError({
141
127
  assertion,
142
128
  message: `The \`code\` property of the second argument to \`t.${assertion}()\` must be a string or number`,
143
- values: [formatWithLabel('Called with:', expectations)]
129
+ values: [formatWithLabel('Called with:', expectations)],
144
130
  });
145
131
  }
146
132
 
@@ -156,7 +142,7 @@ function validateExpectations(assertion, expectations, numberArgs, experiments)
156
142
  throw new AssertionError({
157
143
  assertion,
158
144
  message: `The second argument to \`t.${assertion}()\` contains unexpected properties`,
159
- values: [formatWithLabel('Called with:', expectations)]
145
+ values: [formatWithLabel('Called with:', expectations)],
160
146
  });
161
147
  }
162
148
  }
@@ -173,7 +159,7 @@ function assertExpectations({assertion, actual, expectations, message, prefix, s
173
159
  assertion,
174
160
  message,
175
161
  savedError,
176
- values: [formatWithLabel(`${prefix} exception that is not an error:`, actual)]
162
+ values: [formatWithLabel(`${prefix} exception that is not an error:`, actual)],
177
163
  });
178
164
  }
179
165
 
@@ -187,8 +173,8 @@ function assertExpectations({assertion, actual, expectations, message, prefix, s
187
173
  actualStack,
188
174
  values: [
189
175
  formatWithLabel(`${prefix} unexpected exception:`, actual),
190
- formatWithLabel('Expected to be strictly equal to:', expectations.is)
191
- ]
176
+ formatWithLabel('Expected to be strictly equal to:', expectations.is),
177
+ ],
192
178
  });
193
179
  }
194
180
 
@@ -200,8 +186,8 @@ function assertExpectations({assertion, actual, expectations, message, prefix, s
200
186
  actualStack,
201
187
  values: [
202
188
  formatWithLabel(`${prefix} unexpected exception:`, actual),
203
- formatWithLabel('Expected instance of:', expectations.instanceOf)
204
- ]
189
+ formatWithLabel('Expected instance of:', expectations.instanceOf),
190
+ ],
205
191
  });
206
192
  }
207
193
 
@@ -213,8 +199,8 @@ function assertExpectations({assertion, actual, expectations, message, prefix, s
213
199
  actualStack,
214
200
  values: [
215
201
  formatWithLabel(`${prefix} unexpected exception:`, actual),
216
- formatWithLabel('Expected name to equal:', expectations.name)
217
- ]
202
+ formatWithLabel('Expected name to equal:', expectations.name),
203
+ ],
218
204
  });
219
205
  }
220
206
 
@@ -226,8 +212,8 @@ function assertExpectations({assertion, actual, expectations, message, prefix, s
226
212
  actualStack,
227
213
  values: [
228
214
  formatWithLabel(`${prefix} unexpected exception:`, actual),
229
- formatWithLabel('Expected message to equal:', expectations.message)
230
- ]
215
+ formatWithLabel('Expected message to equal:', expectations.message),
216
+ ],
231
217
  });
232
218
  }
233
219
 
@@ -239,8 +225,8 @@ function assertExpectations({assertion, actual, expectations, message, prefix, s
239
225
  actualStack,
240
226
  values: [
241
227
  formatWithLabel(`${prefix} unexpected exception:`, actual),
242
- formatWithLabel('Expected message to match:', expectations.message)
243
- ]
228
+ formatWithLabel('Expected message to match:', expectations.message),
229
+ ],
244
230
  });
245
231
  }
246
232
 
@@ -252,53 +238,31 @@ function assertExpectations({assertion, actual, expectations, message, prefix, s
252
238
  actualStack,
253
239
  values: [
254
240
  formatWithLabel(`${prefix} unexpected exception:`, actual),
255
- formatWithLabel('Expected code to equal:', expectations.code)
256
- ]
241
+ formatWithLabel('Expected code to equal:', expectations.code),
242
+ ],
257
243
  });
258
244
  }
259
245
  }
260
246
 
261
- class Assertions {
247
+ export class Assertions {
262
248
  constructor({
263
249
  pass = notImplemented,
264
250
  pending = notImplemented,
265
251
  fail = notImplemented,
266
252
  skip = notImplemented,
267
253
  compareWithSnapshot = notImplemented,
268
- powerAssert,
269
254
  experiments = {},
270
- disableSnapshots = false
255
+ disableSnapshots = false,
271
256
  } = {}) {
272
257
  const withSkip = assertionFn => {
273
258
  assertionFn.skip = skip;
274
259
  return assertionFn;
275
260
  };
276
261
 
277
- // When adding new enhanced functions with new patterns, don't forget to
278
- // enable the pattern in the power-assert compilation step in @ava/babel.
279
- const withPowerAssert = (pattern, assertionFn) => powerAssert.empower(assertionFn, {
280
- onError: event => {
281
- if (event.powerAssertContext) {
282
- event.error.statements = powerAssert.format(event.powerAssertContext, formatPowerAssertValue);
283
- }
284
-
285
- fail(event.error);
286
- },
287
- onSuccess: () => {
288
- pass();
289
- },
290
- bindReceiver: false,
291
- patterns: [pattern]
292
- });
293
-
294
- const checkMessage = (assertion, message, powerAssert = false) => {
262
+ const checkMessage = (assertion, message) => {
295
263
  const result = checkAssertionMessage(assertion, message);
296
264
  if (result === true) {
297
- return this.true;
298
- }
299
-
300
- if (powerAssert) {
301
- throw result;
265
+ return true;
302
266
  }
303
267
 
304
268
  fail(result);
@@ -307,52 +271,58 @@ class Assertions {
307
271
 
308
272
  this.pass = withSkip(() => {
309
273
  pass();
274
+ return true;
310
275
  });
311
276
 
312
277
  this.fail = withSkip(message => {
313
278
  if (!checkMessage('fail', message)) {
314
- return;
279
+ return false;
315
280
  }
316
281
 
317
282
  fail(new AssertionError({
318
283
  assertion: 'fail',
319
- message: message || 'Test failed via `t.fail()`'
284
+ message: message || 'Test failed via `t.fail()`',
320
285
  }));
286
+
287
+ return false;
321
288
  });
322
289
 
323
290
  this.is = withSkip((actual, expected, message) => {
324
291
  if (!checkMessage('is', message)) {
325
- return;
292
+ return false;
326
293
  }
327
294
 
328
295
  if (Object.is(actual, expected)) {
329
296
  pass();
330
- } else {
331
- const result = concordance.compare(actual, expected, concordanceOptions);
332
- const actualDescriptor = result.actual || concordance.describe(actual, concordanceOptions);
333
- const expectedDescriptor = result.expected || concordance.describe(expected, concordanceOptions);
297
+ return true;
298
+ }
334
299
 
335
- if (result.pass) {
336
- fail(new AssertionError({
337
- assertion: 'is',
338
- message,
339
- raw: {actual, expected},
340
- values: [formatDescriptorWithLabel('Values are deeply equal to each other, but they are not the same:', actualDescriptor)]
341
- }));
342
- } else {
343
- fail(new AssertionError({
344
- assertion: 'is',
345
- message,
346
- raw: {actual, expected},
347
- values: [formatDescriptorDiff(actualDescriptor, expectedDescriptor)]
348
- }));
349
- }
300
+ const result = concordance.compare(actual, expected, concordanceOptions);
301
+ const actualDescriptor = result.actual || concordance.describe(actual, concordanceOptions);
302
+ const expectedDescriptor = result.expected || concordance.describe(expected, concordanceOptions);
303
+
304
+ if (result.pass) {
305
+ fail(new AssertionError({
306
+ assertion: 'is',
307
+ message,
308
+ raw: {actual, expected},
309
+ values: [formatDescriptorWithLabel('Values are deeply equal to each other, but they are not the same:', actualDescriptor)],
310
+ }));
311
+ } else {
312
+ fail(new AssertionError({
313
+ assertion: 'is',
314
+ message,
315
+ raw: {actual, expected},
316
+ values: [formatDescriptorDiff(actualDescriptor, expectedDescriptor)],
317
+ }));
350
318
  }
319
+
320
+ return false;
351
321
  });
352
322
 
353
323
  this.not = withSkip((actual, expected, message) => {
354
324
  if (!checkMessage('not', message)) {
355
- return;
325
+ return false;
356
326
  }
357
327
 
358
328
  if (Object.is(actual, expected)) {
@@ -360,36 +330,40 @@ class Assertions {
360
330
  assertion: 'not',
361
331
  message,
362
332
  raw: {actual, expected},
363
- values: [formatWithLabel('Value is the same as:', actual)]
333
+ values: [formatWithLabel('Value is the same as:', actual)],
364
334
  }));
365
- } else {
366
- pass();
335
+ return false;
367
336
  }
337
+
338
+ pass();
339
+ return true;
368
340
  });
369
341
 
370
342
  this.deepEqual = withSkip((actual, expected, message) => {
371
343
  if (!checkMessage('deepEqual', message)) {
372
- return;
344
+ return false;
373
345
  }
374
346
 
375
347
  const result = concordance.compare(actual, expected, concordanceOptions);
376
348
  if (result.pass) {
377
349
  pass();
378
- } else {
379
- const actualDescriptor = result.actual || concordance.describe(actual, concordanceOptions);
380
- const expectedDescriptor = result.expected || concordance.describe(expected, concordanceOptions);
381
- fail(new AssertionError({
382
- assertion: 'deepEqual',
383
- message,
384
- raw: {actual, expected},
385
- values: [formatDescriptorDiff(actualDescriptor, expectedDescriptor)]
386
- }));
350
+ return true;
387
351
  }
352
+
353
+ const actualDescriptor = result.actual || concordance.describe(actual, concordanceOptions);
354
+ const expectedDescriptor = result.expected || concordance.describe(expected, concordanceOptions);
355
+ fail(new AssertionError({
356
+ assertion: 'deepEqual',
357
+ message,
358
+ raw: {actual, expected},
359
+ values: [formatDescriptorDiff(actualDescriptor, expectedDescriptor)],
360
+ }));
361
+ return false;
388
362
  });
389
363
 
390
364
  this.notDeepEqual = withSkip((actual, expected, message) => {
391
365
  if (!checkMessage('notDeepEqual', message)) {
392
- return;
366
+ return false;
393
367
  }
394
368
 
395
369
  const result = concordance.compare(actual, expected, concordanceOptions);
@@ -399,16 +373,18 @@ class Assertions {
399
373
  assertion: 'notDeepEqual',
400
374
  message,
401
375
  raw: {actual, expected},
402
- values: [formatDescriptorWithLabel('Value is deeply equal:', actualDescriptor)]
376
+ values: [formatDescriptorWithLabel('Value is deeply equal:', actualDescriptor)],
403
377
  }));
404
- } else {
405
- pass();
378
+ return false;
406
379
  }
380
+
381
+ pass();
382
+ return true;
407
383
  });
408
384
 
409
385
  this.like = withSkip((actual, selector, message) => {
410
386
  if (!checkMessage('like', message)) {
411
- return;
387
+ return false;
412
388
  }
413
389
 
414
390
  if (!isLikeSelector(selector)) {
@@ -416,9 +392,9 @@ class Assertions {
416
392
  assertion: 'like',
417
393
  improperUsage: true,
418
394
  message: '`t.like()` selector must be a non-empty object',
419
- values: [formatWithLabel('Called with:', selector)]
395
+ values: [formatWithLabel('Called with:', selector)],
420
396
  }));
421
- return;
397
+ return false;
422
398
  }
423
399
 
424
400
  let comparable;
@@ -430,9 +406,9 @@ class Assertions {
430
406
  assertion: 'like',
431
407
  improperUsage: true,
432
408
  message: '`t.like()` selector must not contain circular references',
433
- values: [formatWithLabel('Called with:', selector)]
409
+ values: [formatWithLabel('Called with:', selector)],
434
410
  }));
435
- return;
411
+ return false;
436
412
  }
437
413
 
438
414
  throw error;
@@ -441,15 +417,18 @@ class Assertions {
441
417
  const result = concordance.compare(comparable, selector, concordanceOptions);
442
418
  if (result.pass) {
443
419
  pass();
444
- } else {
445
- const actualDescriptor = result.actual || concordance.describe(comparable, concordanceOptions);
446
- const expectedDescriptor = result.expected || concordance.describe(selector, concordanceOptions);
447
- fail(new AssertionError({
448
- assertion: 'like',
449
- message,
450
- values: [formatDescriptorDiff(actualDescriptor, expectedDescriptor)]
451
- }));
420
+ return true;
452
421
  }
422
+
423
+ const actualDescriptor = result.actual || concordance.describe(comparable, concordanceOptions);
424
+ const expectedDescriptor = result.expected || concordance.describe(selector, concordanceOptions);
425
+ fail(new AssertionError({
426
+ assertion: 'like',
427
+ message,
428
+ values: [formatDescriptorDiff(actualDescriptor, expectedDescriptor)],
429
+ }));
430
+
431
+ return false;
453
432
  });
454
433
 
455
434
  this.throws = withSkip((...args) => {
@@ -467,7 +446,7 @@ class Assertions {
467
446
  assertion: 'throws',
468
447
  improperUsage: true,
469
448
  message: '`t.throws()` must be called with a function',
470
- values: [formatWithLabel('Called with:', fn)]
449
+ values: [formatWithLabel('Called with:', fn)],
471
450
  }));
472
451
  return;
473
452
  }
@@ -489,7 +468,7 @@ class Assertions {
489
468
  fail(new AssertionError({
490
469
  assertion: 'throws',
491
470
  message,
492
- values: [formatWithLabel('Function returned a promise. Use `t.throwsAsync()` instead:', retval)]
471
+ values: [formatWithLabel('Function returned a promise. Use `t.throwsAsync()` instead:', retval)],
493
472
  }));
494
473
  return;
495
474
  }
@@ -501,7 +480,7 @@ class Assertions {
501
480
  fail(new AssertionError({
502
481
  assertion: 'throws',
503
482
  message,
504
- values: [formatWithLabel('Function returned:', retval)]
483
+ values: [formatWithLabel('Function returned:', retval)],
505
484
  }));
506
485
  return;
507
486
  }
@@ -512,7 +491,7 @@ class Assertions {
512
491
  actual,
513
492
  expectations,
514
493
  message,
515
- prefix: 'Function threw'
494
+ prefix: 'Function threw',
516
495
  });
517
496
  pass();
518
497
  return actual;
@@ -521,11 +500,11 @@ class Assertions {
521
500
  }
522
501
  });
523
502
 
524
- this.throwsAsync = withSkip((...args) => {
503
+ this.throwsAsync = withSkip(async (...args) => {
525
504
  let [thrower, expectations, message] = args;
526
505
 
527
506
  if (!checkMessage('throwsAsync', message)) {
528
- return Promise.resolve();
507
+ return;
529
508
  }
530
509
 
531
510
  if (typeof thrower !== 'function' && !isPromise(thrower)) {
@@ -533,28 +512,28 @@ class Assertions {
533
512
  assertion: 'throwsAsync',
534
513
  improperUsage: true,
535
514
  message: '`t.throwsAsync()` must be called with a function or promise',
536
- values: [formatWithLabel('Called with:', thrower)]
515
+ values: [formatWithLabel('Called with:', thrower)],
537
516
  }));
538
- return Promise.resolve();
517
+ return;
539
518
  }
540
519
 
541
520
  try {
542
521
  expectations = validateExpectations('throwsAsync', expectations, args.length, experiments);
543
522
  } catch (error) {
544
523
  fail(error);
545
- return Promise.resolve();
524
+ return;
546
525
  }
547
526
 
548
- const handlePromise = (promise, wasReturned) => {
527
+ const handlePromise = async (promise, wasReturned) => {
549
528
  // Create an error object to record the stack before it gets lost in the promise chain.
550
529
  const savedError = getErrorWithLongStackTrace();
551
530
  // Handle "promise like" objects by casting to a real Promise.
552
- const intermediate = Promise.resolve(promise).then(value => { // eslint-disable-line promise/prefer-await-to-then
531
+ const intermediate = Promise.resolve(promise).then(value => {
553
532
  throw new AssertionError({
554
533
  assertion: 'throwsAsync',
555
534
  message,
556
535
  savedError,
557
- values: [formatWithLabel(`${wasReturned ? 'Returned promise' : 'Promise'} resolved with:`, value)]
536
+ values: [formatWithLabel(`${wasReturned ? 'Returned promise' : 'Promise'} resolved with:`, value)],
558
537
  });
559
538
  }, error => {
560
539
  assertExpectations({
@@ -563,14 +542,17 @@ class Assertions {
563
542
  expectations,
564
543
  message,
565
544
  prefix: `${wasReturned ? 'Returned promise' : 'Promise'} rejected with`,
566
- savedError
545
+ savedError,
567
546
  });
568
547
  return error;
569
548
  });
570
549
 
571
550
  pending(intermediate);
572
- // Don't reject the returned promise, even if the assertion fails.
573
- return intermediate.catch(noop);
551
+ try {
552
+ return await intermediate;
553
+ } catch {
554
+ // Don't reject the returned promise, even if the assertion fails.
555
+ }
574
556
  };
575
557
 
576
558
  if (isPromise(thrower)) {
@@ -590,9 +572,9 @@ class Assertions {
590
572
  assertion: 'throwsAsync',
591
573
  message,
592
574
  actualStack: actual.stack,
593
- values: [formatWithLabel('Function threw synchronously. Use `t.throws()` instead:', actual)]
575
+ values: [formatWithLabel('Function threw synchronously. Use `t.throws()` instead:', actual)],
594
576
  }));
595
- return Promise.resolve();
577
+ return;
596
578
  }
597
579
 
598
580
  if (isPromise(retval)) {
@@ -602,9 +584,8 @@ class Assertions {
602
584
  fail(new AssertionError({
603
585
  assertion: 'throwsAsync',
604
586
  message,
605
- values: [formatWithLabel('Function returned:', retval)]
587
+ values: [formatWithLabel('Function returned:', retval)],
606
588
  }));
607
- return Promise.resolve();
608
589
  });
609
590
 
610
591
  this.notThrows = withSkip((fn, message) => {
@@ -617,7 +598,7 @@ class Assertions {
617
598
  assertion: 'notThrows',
618
599
  improperUsage: true,
619
600
  message: '`t.notThrows()` must be called with a function',
620
- values: [formatWithLabel('Called with:', fn)]
601
+ values: [formatWithLabel('Called with:', fn)],
621
602
  }));
622
603
  return;
623
604
  }
@@ -629,7 +610,7 @@ class Assertions {
629
610
  assertion: 'notThrows',
630
611
  message,
631
612
  actualStack: error.stack,
632
- values: [formatWithLabel('Function threw:', error)]
613
+ values: [formatWithLabel('Function threw:', error)],
633
614
  }));
634
615
  return;
635
616
  }
@@ -647,26 +628,30 @@ class Assertions {
647
628
  assertion: 'notThrowsAsync',
648
629
  improperUsage: true,
649
630
  message: '`t.notThrowsAsync()` must be called with a function or promise',
650
- values: [formatWithLabel('Called with:', nonThrower)]
631
+ values: [formatWithLabel('Called with:', nonThrower)],
651
632
  }));
652
633
  return Promise.resolve();
653
634
  }
654
635
 
655
- const handlePromise = (promise, wasReturned) => {
636
+ const handlePromise = async (promise, wasReturned) => {
656
637
  // Create an error object to record the stack before it gets lost in the promise chain.
657
638
  const savedError = getErrorWithLongStackTrace();
658
639
  // Handle "promise like" objects by casting to a real Promise.
659
- const intermediate = Promise.resolve(promise).then(noop, error => { // eslint-disable-line promise/prefer-await-to-then
640
+ const intermediate = Promise.resolve(promise).then(noop, error => {
660
641
  throw new AssertionError({
661
642
  assertion: 'notThrowsAsync',
662
643
  message,
663
644
  savedError,
664
- values: [formatWithLabel(`${wasReturned ? 'Returned promise' : 'Promise'} rejected with:`, error)]
645
+ values: [formatWithLabel(`${wasReturned ? 'Returned promise' : 'Promise'} rejected with:`, error)],
665
646
  });
666
647
  });
667
648
  pending(intermediate);
668
- // Don't reject the returned promise, even if the assertion fails.
669
- return intermediate.catch(noop);
649
+
650
+ try {
651
+ return await intermediate;
652
+ } catch {
653
+ // Don't reject the returned promise, even if the assertion fails.
654
+ }
670
655
  };
671
656
 
672
657
  if (isPromise(nonThrower)) {
@@ -681,7 +666,7 @@ class Assertions {
681
666
  assertion: 'notThrowsAsync',
682
667
  message,
683
668
  actualStack: error.stack,
684
- values: [formatWithLabel('Function threw:', error)]
669
+ values: [formatWithLabel('Function threw:', error)],
685
670
  }));
686
671
  return Promise.resolve();
687
672
  }
@@ -690,7 +675,7 @@ class Assertions {
690
675
  fail(new AssertionError({
691
676
  assertion: 'notThrowsAsync',
692
677
  message,
693
- values: [formatWithLabel('Function did not return a promise. Use `t.notThrows()` instead:', retval)]
678
+ values: [formatWithLabel('Function did not return a promise. Use `t.notThrows()` instead:', retval)],
694
679
  }));
695
680
  return Promise.resolve();
696
681
  }
@@ -698,47 +683,50 @@ class Assertions {
698
683
  return handlePromise(retval, true);
699
684
  });
700
685
 
701
- this.snapshot = withSkip((expected, ...rest) => {
702
- if (disableSnapshots && experiments.disableSnapshotsInHooks) {
686
+ this.snapshot = withSkip((expected, message) => {
687
+ if (disableSnapshots) {
703
688
  fail(new AssertionError({
704
689
  assertion: 'snapshot',
705
690
  message: '`t.snapshot()` can only be used in tests',
706
- improperUsage: true
691
+ improperUsage: true,
707
692
  }));
708
- return;
693
+ return false;
709
694
  }
710
695
 
711
- let message;
712
- let snapshotOptions;
713
- if (rest.length > 1) {
714
- [snapshotOptions, message] = rest;
715
- } else {
716
- const [optionsOrMessage] = rest;
717
- if (typeof optionsOrMessage === 'object') {
718
- snapshotOptions = optionsOrMessage;
719
- } else {
720
- message = optionsOrMessage;
721
- }
696
+ if (message && message.id !== undefined) {
697
+ fail(new AssertionError({
698
+ assertion: 'snapshot',
699
+ message: 'AVA 4 no longer supports snapshot IDs',
700
+ improperUsage: true,
701
+ values: [formatWithLabel('Called with id:', message.id)],
702
+ }));
703
+ return false;
722
704
  }
723
705
 
724
706
  if (!checkMessage('snapshot', message)) {
725
- return;
707
+ return false;
708
+ }
709
+
710
+ if (message === '') {
711
+ fail(new AssertionError({
712
+ assertion: 'snapshot',
713
+ improperUsage: true,
714
+ message: 'The snapshot assertion message must be a non-empty string',
715
+ values: [formatWithLabel('Called with:', message)],
716
+ }));
717
+ return false;
726
718
  }
727
719
 
728
720
  let result;
729
721
  try {
730
- result = compareWithSnapshot({
731
- expected,
732
- id: snapshotOptions ? snapshotOptions.id : undefined,
733
- message
734
- });
722
+ result = compareWithSnapshot({expected, message});
735
723
  } catch (error) {
736
- if (!(error instanceof snapshotManager.SnapshotError)) {
724
+ if (!(error instanceof SnapshotError)) {
737
725
  throw error;
738
726
  }
739
727
 
740
728
  const improperUsage = {name: error.name, snapPath: error.snapPath};
741
- if (error instanceof snapshotManager.VersionMismatchError) {
729
+ if (error instanceof VersionMismatchError) {
742
730
  improperUsage.snapVersion = error.snapVersion;
743
731
  improperUsage.expectedVersion = error.expectedVersion;
744
732
  }
@@ -746,48 +734,55 @@ class Assertions {
746
734
  fail(new AssertionError({
747
735
  assertion: 'snapshot',
748
736
  message: message || 'Could not compare snapshot',
749
- improperUsage
737
+ improperUsage,
750
738
  }));
751
- return;
739
+ return false;
752
740
  }
753
741
 
754
742
  if (result.pass) {
755
743
  pass();
756
- } else if (result.actual) {
744
+ return true;
745
+ }
746
+
747
+ if (result.actual) {
757
748
  fail(new AssertionError({
758
749
  assertion: 'snapshot',
759
750
  message: message || 'Did not match snapshot',
760
- values: [formatDescriptorDiff(result.actual, result.expected, {invert: true})]
751
+ values: [formatDescriptorDiff(result.actual, result.expected, {invert: true})],
761
752
  }));
762
753
  } else {
763
754
  // This can only occur in CI environments.
764
755
  fail(new AssertionError({
765
756
  assertion: 'snapshot',
766
- message: message || 'No snapshot available — new snapshots are not created in CI environments'
757
+ message: message || 'No snapshot available — new snapshots are not created in CI environments',
767
758
  }));
768
759
  }
760
+
761
+ return false;
769
762
  });
770
763
 
771
764
  this.truthy = withSkip((actual, message) => {
772
765
  if (!checkMessage('truthy', message)) {
773
- return;
766
+ return false;
774
767
  }
775
768
 
776
769
  if (actual) {
777
770
  pass();
778
- } else {
779
- fail(new AssertionError({
780
- assertion: 'truthy',
781
- message,
782
- operator: '!!',
783
- values: [formatWithLabel('Value is not truthy:', actual)]
784
- }));
771
+ return true;
785
772
  }
773
+
774
+ fail(new AssertionError({
775
+ assertion: 'truthy',
776
+ message,
777
+ operator: '!!',
778
+ values: [formatWithLabel('Value is not truthy:', actual)],
779
+ }));
780
+ return false;
786
781
  });
787
782
 
788
783
  this.falsy = withSkip((actual, message) => {
789
784
  if (!checkMessage('falsy', message)) {
790
- return;
785
+ return false;
791
786
  }
792
787
 
793
788
  if (actual) {
@@ -795,48 +790,54 @@ class Assertions {
795
790
  assertion: 'falsy',
796
791
  message,
797
792
  operator: '!',
798
- values: [formatWithLabel('Value is not falsy:', actual)]
793
+ values: [formatWithLabel('Value is not falsy:', actual)],
799
794
  }));
800
- } else {
801
- pass();
795
+ return false;
802
796
  }
797
+
798
+ pass();
799
+ return true;
803
800
  });
804
801
 
805
802
  this.true = withSkip((actual, message) => {
806
803
  if (!checkMessage('true', message)) {
807
- return;
804
+ return false;
808
805
  }
809
806
 
810
807
  if (actual === true) {
811
808
  pass();
812
- } else {
813
- fail(new AssertionError({
814
- assertion: 'true',
815
- message,
816
- values: [formatWithLabel('Value is not `true`:', actual)]
817
- }));
809
+ return true;
818
810
  }
811
+
812
+ fail(new AssertionError({
813
+ assertion: 'true',
814
+ message,
815
+ values: [formatWithLabel('Value is not `true`:', actual)],
816
+ }));
817
+ return false;
819
818
  });
820
819
 
821
820
  this.false = withSkip((actual, message) => {
822
821
  if (!checkMessage('false', message)) {
823
- return;
822
+ return false;
824
823
  }
825
824
 
826
825
  if (actual === false) {
827
826
  pass();
828
- } else {
829
- fail(new AssertionError({
830
- assertion: 'false',
831
- message,
832
- values: [formatWithLabel('Value is not `false`:', actual)]
833
- }));
827
+ return true;
834
828
  }
829
+
830
+ fail(new AssertionError({
831
+ assertion: 'false',
832
+ message,
833
+ values: [formatWithLabel('Value is not `false`:', actual)],
834
+ }));
835
+ return false;
835
836
  });
836
837
 
837
838
  this.regex = withSkip((string, regex, message) => {
838
839
  if (!checkMessage('regex', message)) {
839
- return;
840
+ return false;
840
841
  }
841
842
 
842
843
  if (typeof string !== 'string') {
@@ -844,9 +845,9 @@ class Assertions {
844
845
  assertion: 'regex',
845
846
  improperUsage: true,
846
847
  message: '`t.regex()` must be called with a string',
847
- values: [formatWithLabel('Called with:', string)]
848
+ values: [formatWithLabel('Called with:', string)],
848
849
  }));
849
- return;
850
+ return false;
850
851
  }
851
852
 
852
853
  if (!(regex instanceof RegExp)) {
@@ -854,9 +855,9 @@ class Assertions {
854
855
  assertion: 'regex',
855
856
  improperUsage: true,
856
857
  message: '`t.regex()` must be called with a regular expression',
857
- values: [formatWithLabel('Called with:', regex)]
858
+ values: [formatWithLabel('Called with:', regex)],
858
859
  }));
859
- return;
860
+ return false;
860
861
  }
861
862
 
862
863
  if (!regex.test(string)) {
@@ -865,18 +866,19 @@ class Assertions {
865
866
  message,
866
867
  values: [
867
868
  formatWithLabel('Value must match expression:', string),
868
- formatWithLabel('Regular expression:', regex)
869
- ]
869
+ formatWithLabel('Regular expression:', regex),
870
+ ],
870
871
  }));
871
- return;
872
+ return false;
872
873
  }
873
874
 
874
875
  pass();
876
+ return true;
875
877
  });
876
878
 
877
879
  this.notRegex = withSkip((string, regex, message) => {
878
880
  if (!checkMessage('notRegex', message)) {
879
- return;
881
+ return false;
880
882
  }
881
883
 
882
884
  if (typeof string !== 'string') {
@@ -884,9 +886,9 @@ class Assertions {
884
886
  assertion: 'notRegex',
885
887
  improperUsage: true,
886
888
  message: '`t.notRegex()` must be called with a string',
887
- values: [formatWithLabel('Called with:', string)]
889
+ values: [formatWithLabel('Called with:', string)],
888
890
  }));
889
- return;
891
+ return false;
890
892
  }
891
893
 
892
894
  if (!(regex instanceof RegExp)) {
@@ -894,9 +896,9 @@ class Assertions {
894
896
  assertion: 'notRegex',
895
897
  improperUsage: true,
896
898
  message: '`t.notRegex()` must be called with a regular expression',
897
- values: [formatWithLabel('Called with:', regex)]
899
+ values: [formatWithLabel('Called with:', regex)],
898
900
  }));
899
- return;
901
+ return false;
900
902
  }
901
903
 
902
904
  if (regex.test(string)) {
@@ -905,50 +907,33 @@ class Assertions {
905
907
  message,
906
908
  values: [
907
909
  formatWithLabel('Value must not match expression:', string),
908
- formatWithLabel('Regular expression:', regex)
909
- ]
910
+ formatWithLabel('Regular expression:', regex),
911
+ ],
910
912
  }));
911
- return;
913
+ return false;
912
914
  }
913
915
 
914
916
  pass();
917
+ return true;
915
918
  });
916
919
 
917
- if (powerAssert === undefined) {
918
- this.assert = withSkip((actual, message) => {
919
- if (!checkMessage('assert', message)) {
920
- return;
921
- }
920
+ this.assert = withSkip((actual, message) => {
921
+ if (!checkMessage('assert', message)) {
922
+ return false;
923
+ }
922
924
 
923
- if (!actual) {
924
- fail(new AssertionError({
925
- assertion: 'assert',
926
- message,
927
- operator: '!!',
928
- values: [formatWithLabel('Value is not truthy:', actual)]
929
- }));
930
- return;
931
- }
925
+ if (!actual) {
926
+ fail(new AssertionError({
927
+ assertion: 'assert',
928
+ message,
929
+ operator: '!!',
930
+ values: [formatWithLabel('Value is not truthy:', actual)],
931
+ }));
932
+ return false;
933
+ }
932
934
 
933
- pass();
934
- });
935
- } else {
936
- this.assert = withSkip(withPowerAssert(
937
- 'assert(value, [message])',
938
- (actual, message) => {
939
- checkMessage('assert', message, true);
940
-
941
- if (!actual) {
942
- throw new AssertionError({
943
- assertion: 'assert',
944
- message,
945
- operator: '!!',
946
- values: [formatWithLabel('Value is not truthy:', actual)]
947
- });
948
- }
949
- })
950
- );
951
- }
935
+ pass();
936
+ return true;
937
+ });
952
938
  }
953
939
  }
954
- exports.Assertions = Assertions;