Skip to content

Commit d01db61

Browse files
Detect t.try() usage in hooks; experimentally disable t.snapshot()
`t.try()` has never worked in hooks. Fail the hook properly instead of letting it crash. `t.snapshot()` sort of works, but not really. Add an experiment so support can be disabled. This will become the default behavior in the next major AVA release. Fixes #2523. Co-authored-by: Mark Wubben <mark@novemberborn.net>
1 parent eee2f7b commit d01db61

File tree

10 files changed

+89
-3
lines changed

10 files changed

+89
-3
lines changed

lib/assert.js

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,8 @@ class Assertions {
258258
skip = notImplemented,
259259
compareWithSnapshot = notImplemented,
260260
powerAssert,
261-
experiments = {}
261+
experiments = {},
262+
disableSnapshots = false
262263
} = {}) {
263264
const withSkip = assertionFn => {
264265
assertionFn.skip = skip;
@@ -699,6 +700,15 @@ class Assertions {
699700
});
700701

701702
this.snapshot = withSkip((expected, ...rest) => {
703+
if (disableSnapshots && experiments.disableSnapshotsInHooks) {
704+
fail(new AssertionError({
705+
assertion: 'snapshot',
706+
message: '`t.snapshot()` can only be used in tests',
707+
improperUsage: true
708+
}));
709+
return;
710+
}
711+
702712
let message;
703713
let snapshotOptions;
704714
if (rest.length > 1) {

lib/load-config.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ const pkgConf = require('pkg-conf');
77

88
const NO_SUCH_FILE = Symbol('no ava.config.js file');
99
const MISSING_DEFAULT_EXPORT = Symbol('missing default export');
10-
const EXPERIMENTS = new Set(['likeAssertion', 'reverseTeardowns']);
10+
const EXPERIMENTS = new Set(['disableSnapshotsInHooks', 'likeAssertion', 'reverseTeardowns']);
1111

1212
// *Very* rudimentary support for loading ava.config.js files containing an `export default` statement.
1313
const evaluateJsConfig = configFile => {

lib/test.js

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@ class ExecutionContext extends assert.Assertions {
4040
return test.compareWithSnapshot(options);
4141
},
4242
powerAssert: test.powerAssert,
43-
experiments: test.experiments
43+
experiments: test.experiments,
44+
disableSnapshots: test.isHook === true
4445
});
4546
testMap.set(this, test);
4647

@@ -74,6 +75,12 @@ class ExecutionContext extends assert.Assertions {
7475
};
7576

7677
this.try = async (...attemptArgs) => {
78+
if (test.isHook) {
79+
const error = new Error('`t.try()` can only be used in tests');
80+
test.saveFirstError(error);
81+
throw error;
82+
}
83+
7784
const {args, buildTitle, implementations, receivedImplementationArray} = parseTestArgs(attemptArgs);
7885

7986
if (implementations.length === 0) {

test/helpers/exec.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ exports.fixture = async (...args) => {
4444
const errors = new WeakMap();
4545
const stats = {
4646
failed: [],
47+
failedHooks: [],
4748
passed: [],
4849
skipped: [],
4950
uncaughtExceptions: [],
@@ -59,6 +60,14 @@ exports.fixture = async (...args) => {
5960
}
6061

6162
switch (statusEvent.type) {
63+
case 'hook-failed': {
64+
const {title, testFile} = statusEvent;
65+
const statObject = {title, file: normalizePath(cwd, testFile)};
66+
errors.set(statObject, statusEvent.err);
67+
stats.failedHooks.push(statObject);
68+
break;
69+
}
70+
6271
case 'selected-test': {
6372
if (statusEvent.skip) {
6473
const {title, testFile} = statusEvent;
@@ -108,6 +117,7 @@ exports.fixture = async (...args) => {
108117
throw Object.assign(error, {stats});
109118
} finally {
110119
stats.failed.sort(compareStatObjects);
120+
stats.failedHooks.sort(compareStatObjects);
111121
stats.passed.sort(compareStatObjects);
112122
stats.skipped.sort(compareStatObjects);
113123
stats.unsavedSnapshots.sort(compareStatObjects);
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
const test = require('ava');
2+
3+
test.before(t => {
4+
t.snapshot({});
5+
});
6+
7+
test('cannot use snapshot in hook', t => {
8+
t.pass();
9+
});
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
const test = require('ava');
2+
3+
test.before(async t => {
4+
await t.try(tt => tt.pass());
5+
});
6+
7+
test('cannot use `t.try()` in hook', t => {
8+
t.pass();
9+
});
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"ava": {
3+
"files": [
4+
"*.js"
5+
],
6+
"nonSemVerExperiments": {
7+
"disableSnapshotsInHooks": true
8+
}
9+
}
10+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# Snapshot report for `test/hook-restrictions/test.js`
2+
3+
The actual snapshot is saved in `test.js.snap`.
4+
5+
Generated by [AVA](https://avajs.dev).
6+
7+
## `t.try()` cannot be used in hooks
8+
9+
> error message
10+
11+
'`t.try()` can only be used in tests'
12+
13+
## snapshots cannot be used in hooks
14+
15+
> error message
16+
17+
'`t.snapshot()` can only be used in tests'
166 Bytes
Binary file not shown.

test/hook-restrictions/test.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
const test = require('@ava/test');
2+
const exec = require('../helpers/exec');
3+
4+
test('snapshots cannot be used in hooks', async t => {
5+
const result = await t.throwsAsync(exec.fixture('invalid-snapshots-in-hooks.js'));
6+
const error = result.stats.getError(result.stats.failedHooks[0]);
7+
t.snapshot(error.message, 'error message');
8+
});
9+
10+
test('`t.try()` cannot be used in hooks', async t => {
11+
const result = await t.throwsAsync(exec.fixture('invalid-t-try-in-hooks.js'));
12+
const error = result.stats.getError(result.stats.failedHooks[0]);
13+
t.snapshot(error.message, 'error message');
14+
});

0 commit comments

Comments
 (0)