Skip to content

Commit 4f093ab

Browse files
ninevranovemberborn
andauthoredDec 31, 2020
Remove snapshot files when a test file stops using snapshots
Fixes #1424. Co-authored-by: Mark Wubben <mark@novemberborn.net>
1 parent 98595da commit 4f093ab

File tree

36 files changed

+710
-5
lines changed

36 files changed

+710
-5
lines changed
 

‎lib/runner.js

+21-4
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ class Runner extends Emittery {
2929

3030
this.activeRunnables = new Set();
3131
this.boundCompareTestSnapshot = this.compareTestSnapshot.bind(this);
32+
this.skippedSnapshots = false;
33+
this.boundSkipSnapshot = this.skipSnapshot.bind(this);
3234
this.interrupted = false;
3335
this.snapshots = null;
3436
this.nextTaskIndex = 0;
@@ -199,8 +201,19 @@ class Runner extends Emittery {
199201
return this.snapshots.compare(options);
200202
}
201203

204+
skipSnapshot() {
205+
this.skippedSnapshots = true;
206+
}
207+
202208
saveSnapshotState() {
203-
if (this.updateSnapshots && (this.runOnlyExclusive || this.skippingTests)) {
209+
if (
210+
this.updateSnapshots &&
211+
(
212+
this.runOnlyExclusive ||
213+
this.skippingTests ||
214+
this.skippedSnapshots
215+
)
216+
) {
204217
return {cannotSave: true};
205218
}
206219

@@ -209,9 +222,11 @@ class Runner extends Emittery {
209222
}
210223

211224
if (this.updateSnapshots) {
212-
// TODO: There may be unused snapshot files if no test caused the
213-
// snapshots to be loaded. Prune them. But not if tests (including hooks!)
214-
// were skipped. Perhaps emit a warning if this occurs?
225+
return {touchedFiles: snapshotManager.cleanSnapshots({
226+
file: this.file,
227+
fixedLocation: this.snapshotDir,
228+
projectDir: this.projectDir
229+
})};
215230
}
216231

217232
return {};
@@ -297,6 +312,7 @@ class Runner extends Emittery {
297312
task.implementation :
298313
t => task.implementation.apply(null, [t].concat(task.args)),
299314
compareTestSnapshot: this.boundCompareTestSnapshot,
315+
skipSnapshot: this.boundSkipSnapshot,
300316
updateSnapshots: this.updateSnapshots,
301317
metadata: {...task.metadata, associatedTaskIndex},
302318
powerAssert: this.powerAssert,
@@ -349,6 +365,7 @@ class Runner extends Emittery {
349365
task.implementation :
350366
t => task.implementation.apply(null, [t].concat(task.args)),
351367
compareTestSnapshot: this.boundCompareTestSnapshot,
368+
skipSnapshot: this.boundSkipSnapshot,
352369
updateSnapshots: this.updateSnapshots,
353370
metadata: task.metadata,
354371
powerAssert: this.powerAssert,

‎lib/snapshot-manager.js

+38-1
Original file line numberDiff line numberDiff line change
@@ -449,12 +449,49 @@ const determineSnapshotDir = mem(({file, fixedLocation, projectDir}) => {
449449

450450
exports.determineSnapshotDir = determineSnapshotDir;
451451

452-
function load({file, fixedLocation, projectDir, recordNewSnapshots, updating}) {
452+
function determineSnapshotPaths({file, fixedLocation, projectDir}) {
453453
const dir = determineSnapshotDir({file, fixedLocation, projectDir});
454454
const relFile = path.relative(projectDir, resolveSourceFile(file));
455455
const name = path.basename(relFile);
456456
const reportFile = `${name}.md`;
457457
const snapFile = `${name}.snap`;
458+
459+
return {
460+
dir,
461+
relFile,
462+
snapFile,
463+
reportFile
464+
};
465+
}
466+
467+
function cleanFile(file) {
468+
try {
469+
fs.unlinkSync(file);
470+
return [file];
471+
} catch (error) {
472+
if (error.code === 'ENOENT') {
473+
return [];
474+
}
475+
476+
throw error;
477+
}
478+
}
479+
480+
// Remove snapshot and report if they exist. Returns an array containing the
481+
// paths of the touched files.
482+
function cleanSnapshots({file, fixedLocation, projectDir}) {
483+
const {dir, snapFile, reportFile} = determineSnapshotPaths({file, fixedLocation, projectDir});
484+
485+
return [
486+
...cleanFile(path.join(dir, snapFile)),
487+
...cleanFile(path.join(dir, reportFile))
488+
];
489+
}
490+
491+
exports.cleanSnapshots = cleanSnapshots;
492+
493+
function load({file, fixedLocation, projectDir, recordNewSnapshots, updating}) {
494+
const {dir, relFile, snapFile, reportFile} = determineSnapshotPaths({file, fixedLocation, projectDir});
458495
const snapPath = path.join(dir, snapFile);
459496

460497
let appendOnly = !updating;

‎lib/test.js

+4
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,10 @@ class Test {
249249
};
250250

251251
this.skipSnapshot = () => {
252+
if (typeof options.skipSnapshot === 'function') {
253+
options.skipSnapshot();
254+
}
255+
252256
if (options.updateSnapshots) {
253257
this.addFailedAssertion(new Error('Snapshot assertions cannot be skipped when updating snapshots'));
254258
} else {

‎package.json

+1
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@
123123
"delay": "^4.4.0",
124124
"esm": "^3.2.25",
125125
"execa": "^5.0.0",
126+
"fs-extra": "^9.0.1",
126127
"get-stream": "^6.0.0",
127128
"it-first": "^1.0.4",
128129
"proxyquire": "^2.1.3",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
const test = require('../../../..');
2+
3+
if (process.env.TEMPLATE) {
4+
test('test title', t => {
5+
t.snapshot({foo: 'bar'});
6+
t.snapshot({answer: 42});
7+
t.pass();
8+
});
9+
10+
test('another test', t => {
11+
t.snapshot(new Map());
12+
});
13+
} else {
14+
test('test title', t => {
15+
t.pass();
16+
});
17+
18+
test('another test', t => {
19+
t.pass();
20+
});
21+
}

‎test-tap/integration/watcher.js

+46
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,52 @@ test('watcher does not rerun test files when they write snapshot files', t => {
8282
});
8383
});
8484

85+
test('watcher does not rerun test files when they unlink snapshot files', t => {
86+
// Run fixture as template to generate snapshots
87+
execCli(
88+
['--update-snapshots'],
89+
{
90+
dirname: 'fixture/snapshots/watcher-rerun-unlink',
91+
env: {AVA_FORCE_CI: 'not-ci', TEMPLATE: 'true'}
92+
},
93+
err => {
94+
t.ifError(err);
95+
96+
// Run fixture in watch mode; snapshots should be removed, and watcher should not rerun
97+
let killed = false;
98+
99+
const child = execCli(
100+
['--verbose', '--watch', '--update-snapshots', 'test.js'],
101+
{
102+
dirname: 'fixture/snapshots/watcher-rerun-unlink',
103+
env: {AVA_FORCE_CI: 'not-ci'}
104+
},
105+
err => {
106+
t.ok(killed);
107+
t.ifError(err);
108+
t.end();
109+
}
110+
);
111+
112+
let buffer = '';
113+
let passedFirst = false;
114+
child.stdout.on('data', string => {
115+
buffer += string;
116+
if (buffer.includes('2 tests passed') && !passedFirst) {
117+
buffer = '';
118+
passedFirst = true;
119+
setTimeout(() => {
120+
child.kill();
121+
killed = true;
122+
}, 500);
123+
} else if (passedFirst && !killed) {
124+
t.is(buffer.replace(/\s/g, '').replace(END_MESSAGE.replace(/\s/g, ''), ''), '');
125+
}
126+
});
127+
}
128+
);
129+
});
130+
85131
test('watcher does not rerun test files when ignored files change', t => {
86132
let killed = false;
87133

‎test-tap/test.js

+30
Original file line numberDiff line numberDiff line change
@@ -696,6 +696,36 @@ test('snapshot assertion can be skipped', t => {
696696
});
697697
});
698698

699+
// Snapshots reused from test/assert.js
700+
test('snapshot assertions call options.skipSnapshot when skipped', async t => {
701+
const projectDir = path.join(__dirname, 'fixture');
702+
const manager = snapshotManager.load({
703+
file: path.join(projectDir, 'assert.js'),
704+
projectDir,
705+
fixedLocation: null,
706+
updating: false
707+
});
708+
709+
const skipSnapshot = sinon.spy();
710+
711+
const test = new Test({
712+
compareTestSnapshot: options => manager.compare(options),
713+
skipSnapshot,
714+
updateSnapshots: false,
715+
metadata: {},
716+
title: 'passes',
717+
fn(t) {
718+
t.snapshot.skip({not: {a: 'match'}});
719+
t.snapshot.skip({not: {b: 'match'}});
720+
t.snapshot(React.createElement(HelloMessage, {name: 'Sindre'}));
721+
}
722+
});
723+
724+
await test.run();
725+
726+
t.true(skipSnapshot.calledTwice);
727+
});
728+
699729
test('snapshot assertion cannot be skipped when updating snapshots', t => {
700730
return new Test({
701731
updateSnapshots: true,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"ava": {
3+
"snapshotDir": "fixedSnapshotDir"
4+
}
5+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
const test = require(process.env.AVA_PATH); // This fixture is copied to a temporary directory, so require AVA through its configured path.
2+
3+
if (process.env.TEMPLATE) {
4+
test('some snapshots', t => {
5+
t.snapshot('foo');
6+
t.snapshot('bar');
7+
t.pass();
8+
});
9+
10+
test('another snapshot', t => {
11+
t.snapshot('baz');
12+
t.pass();
13+
});
14+
} else {
15+
test('some snapshots', t => {
16+
t.pass();
17+
});
18+
19+
test('another snapshot', t => {
20+
t.pass();
21+
});
22+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
const test = require('ava');
2+
3+
test('without snapshots', t => {
4+
t.pass();
5+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
const test = require(process.env.AVA_PATH); // This fixture is copied to a temporary directory, so require AVA through its configured path.
2+
3+
if (process.env.TEMPLATE) {
4+
test('some snapshots', t => {
5+
t.snapshot('foo');
6+
t.snapshot('bar');
7+
t.pass();
8+
});
9+
10+
test('another snapshot', t => {
11+
t.snapshot('baz');
12+
t.pass();
13+
});
14+
} else {
15+
test.only('some snapshots', t => {
16+
t.pass();
17+
});
18+
19+
test('another snapshot', t => {
20+
t.pass();
21+
});
22+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
const test = require(process.env.AVA_PATH); // This fixture is copied to a temporary directory, so require AVA through its configured path.
2+
3+
if (process.env.TEMPLATE) {
4+
test('some snapshots', t => {
5+
t.snapshot('foo');
6+
t.snapshot('bar');
7+
t.pass();
8+
});
9+
10+
test('another snapshot', t => {
11+
t.snapshot('baz');
12+
t.pass();
13+
});
14+
} else {
15+
test('some snapshots', t => {
16+
t.pass();
17+
});
18+
19+
test('another snapshot', t => {
20+
t.pass();
21+
});
22+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
const test = require(process.env.AVA_PATH); // This fixture is copied to a temporary directory, so require AVA through its configured path.
2+
3+
if (process.env.TEMPLATE) {
4+
test('skipped snapshots in try', async t => {
5+
const attempt = await t.try(tt => {
6+
tt.snapshot('in try');
7+
});
8+
9+
attempt.commit();
10+
11+
t.pass();
12+
});
13+
} else {
14+
test('skipped snapshots in try', async t => {
15+
const attempt = await t.try(tt => {
16+
tt.snapshot.skip('in try');
17+
});
18+
19+
attempt.discard();
20+
21+
t.pass();
22+
});
23+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
const test = require(process.env.AVA_PATH); // This fixture is copied to a temporary directory, so require AVA through its configured path.
2+
3+
if (process.env.TEMPLATE) {
4+
test('some snapshots', t => {
5+
t.snapshot('foo');
6+
t.snapshot('bar');
7+
t.pass();
8+
});
9+
10+
test('another snapshot', t => {
11+
t.snapshot('baz');
12+
t.pass();
13+
});
14+
} else {
15+
test('some snapshots', t => {
16+
t.snapshot.skip('foo');
17+
t.pass();
18+
});
19+
20+
test('another snapshot', t => {
21+
t.pass();
22+
});
23+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
const test = require(process.env.AVA_PATH); // This fixture is copied to a temporary directory, so require AVA through its configured path.
2+
3+
if (process.env.TEMPLATE) {
4+
test('some snapshots', t => {
5+
t.snapshot('foo');
6+
t.snapshot('bar');
7+
t.pass();
8+
});
9+
10+
test('another snapshot', t => {
11+
t.snapshot('baz');
12+
t.pass();
13+
});
14+
} else {
15+
test.skip('some snapshots', t => {
16+
t.pass();
17+
});
18+
19+
test('another snapshot', t => {
20+
t.pass();
21+
});
22+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
const test = require(process.env.AVA_PATH); // This fixture is copied to a temporary directory, so require AVA through its configured path.
2+
3+
if (process.env.TEMPLATE) {
4+
test('some snapshots', t => {
5+
t.snapshot('foo');
6+
t.snapshot('bar');
7+
t.pass();
8+
});
9+
10+
test('another snapshot', t => {
11+
t.snapshot('baz');
12+
t.pass();
13+
});
14+
} else {
15+
test('some snapshots', t => {
16+
t.pass();
17+
});
18+
19+
test('another snapshot', t => {
20+
t.pass();
21+
});
22+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{}
+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
const test = require(process.env.AVA_PATH); // This fixture is copied to a temporary directory, so require AVA through its configured path.
2+
3+
if (process.env.TEMPLATE) {
4+
test('snapshots in try', async t => {
5+
const attempt = await t.try(tt => {
6+
tt.snapshot('in try');
7+
});
8+
9+
attempt.commit();
10+
11+
t.pass();
12+
});
13+
} else {
14+
test('snapshots in try', async t => {
15+
const attempt = await t.try(tt => {
16+
tt.snapshot('in try');
17+
});
18+
19+
attempt.discard();
20+
21+
t.pass();
22+
});
23+
}
+86
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
const fs = require('fs').promises;
2+
const exec = require('../../helpers/exec');
3+
const path = require('path');
4+
const tempy = require('tempy');
5+
const fse = require('fs-extra');
6+
7+
function withTemporaryFixture(macro) {
8+
const avaPath = path.resolve(path.join(__dirname, '..', '..', '..'));
9+
10+
return async (t, {cwd, env, ...options}) => {
11+
await tempy.directory.task(async temporary => {
12+
await fse.copy(cwd, temporary);
13+
await macro(t, {
14+
cwd: temporary,
15+
env: {
16+
AVA_PATH: avaPath,
17+
...env
18+
},
19+
...options
20+
});
21+
});
22+
};
23+
}
24+
25+
module.exports.withTemporaryFixture = withTemporaryFixture;
26+
27+
async function testSnapshotPruning(t, {
28+
cwd,
29+
env,
30+
cli,
31+
remove,
32+
snapshotPath = 'test.js.snap',
33+
reportPath = 'test.js.md',
34+
checkRun = async (t, run) => {
35+
await t.notThrowsAsync(run, 'Expected fixture not to throw');
36+
}
37+
}) {
38+
snapshotPath = path.join(cwd, snapshotPath);
39+
reportPath = path.join(cwd, reportPath);
40+
41+
t.teardown(async () => {
42+
try {
43+
await fs.unlink(snapshotPath);
44+
await fs.unlink(reportPath);
45+
} catch {}
46+
});
47+
48+
// Execute fixture as template to generate snapshots
49+
const templateResult = exec.fixture(['--update-snapshots'], {
50+
cwd,
51+
env: {
52+
...env,
53+
AVA_FORCE_CI: 'not-ci',
54+
TEMPLATE: 'true'
55+
}
56+
});
57+
58+
await t.notThrowsAsync(templateResult, 'Template crashed - there\'s a bug in the test');
59+
60+
// Check that the snapshots were created
61+
await t.notThrowsAsync(fs.access(snapshotPath), 'Template didn\'t create a snapshot - there\'s a bug in the test');
62+
await t.notThrowsAsync(fs.access(reportPath), 'Template didn\'t create a report - there\'s a bug in the test');
63+
64+
// Execute fixture as run
65+
const run = exec.fixture(cli, {
66+
cwd,
67+
env: {
68+
AVA_FORCE_CI: 'not-ci',
69+
...env
70+
}
71+
});
72+
73+
await checkRun(t, run);
74+
75+
if (remove) {
76+
// Assert files don't exist
77+
await t.throwsAsync(fs.access(snapshotPath), {code: 'ENOENT'}, 'Expected snapshot to be removed');
78+
await t.throwsAsync(fs.access(reportPath), {code: 'ENOENT'}, 'Expected report to be remove');
79+
} else {
80+
// Assert files exist
81+
await t.notThrowsAsync(fs.access(snapshotPath), 'Expected snapshot not to be removed');
82+
await t.notThrowsAsync(fs.access(reportPath), 'Expected report not to be removed');
83+
}
84+
}
85+
86+
module.exports.testSnapshotPruning = testSnapshotPruning;
+76
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
# Snapshot report for `test/snapshot-removal/test.js`
2+
3+
The actual snapshot is saved in `test.js.snap`.
4+
5+
Generated by [AVA](https://avajs.dev).
6+
7+
## snapshots remain if skipped in a discarded try()
8+
9+
> files where snapshots could not be updated
10+
11+
[
12+
{
13+
file: 'test.js',
14+
},
15+
]
16+
17+
## snapshots remain if snapshot assertions are skipped
18+
19+
> files where snapshots could not be updated
20+
21+
[
22+
{
23+
file: 'test.js',
24+
},
25+
]
26+
27+
## snapshots remain if tests are skipped
28+
29+
> files where snapshots could not be updated
30+
31+
[
32+
{
33+
file: 'test.js',
34+
},
35+
]
36+
37+
## snapshots remain if tests run with --match
38+
39+
> stderr
40+
41+
'Snapshots cannot be updated when matching specific tests.'
42+
43+
## snapshots remain if tests selected by line numbers
44+
45+
> stderr
46+
47+
'Snapshots cannot be updated when selecting specific tests by their line number.'
48+
49+
## snapshots remain if they are still used
50+
51+
> passed tests
52+
53+
[
54+
{
55+
file: 'test.js',
56+
title: 'another snapshot',
57+
},
58+
{
59+
file: 'test.js',
60+
title: 'some snapshots',
61+
},
62+
]
63+
64+
> files where snapshots could not be updated
65+
66+
[]
67+
68+
## snapshots remain if using test.only
69+
70+
> files where snapshots could not be updated
71+
72+
[
73+
{
74+
file: 'test.js',
75+
},
76+
]
513 Bytes
Binary file not shown.

‎test/snapshot-removal/test.js

+133
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
const test = require('@ava/test');
2+
const exec = require('../helpers/exec');
3+
const {testSnapshotPruning, withTemporaryFixture} = require('./helpers/macros');
4+
const path = require('path');
5+
6+
const macro = withTemporaryFixture(testSnapshotPruning);
7+
8+
test('snapshots are removed when tests stop using them', macro, {
9+
cwd: exec.cwd('removal'),
10+
cli: ['--update-snapshots'],
11+
remove: true
12+
});
13+
14+
test('snapshots are removed from a snapshot directory', macro, {
15+
cwd: exec.cwd('snapshot-dir'),
16+
cli: ['--update-snapshots'],
17+
remove: true,
18+
snapshotPath: path.join('test', 'snapshots', 'test.js.snap'),
19+
reportPath: path.join('test', 'snapshots', 'test.js.md')
20+
});
21+
22+
test('snapshots are removed from a custom snapshotDir', macro, {
23+
cwd: exec.cwd('fixed-snapshot-dir'),
24+
cli: ['--update-snapshots'],
25+
remove: true,
26+
snapshotPath: path.join('fixedSnapshotDir', 'test.js.snap'),
27+
reportPath: path.join('fixedSnapshotDir', 'test.js.md')
28+
});
29+
30+
test('removing non-existent snapshots doesn\'t throw', async t => {
31+
// Execute fixture; this should try to unlink the nonexistent snapshots, and
32+
// should not throw
33+
const run = exec.fixture(['--update-snapshots'], {
34+
cwd: exec.cwd('no-snapshots'),
35+
env: {
36+
AVA_FORCE_CI: 'not-ci'
37+
}
38+
});
39+
40+
await t.notThrowsAsync(run);
41+
});
42+
43+
test('snapshots remain if not updating', macro, {
44+
cwd: exec.cwd('removal'),
45+
cli: [],
46+
remove: false
47+
});
48+
49+
test('snapshots remain if they are still used', macro, {
50+
cwd: exec.cwd('removal'),
51+
cli: ['--update-snapshots'],
52+
remove: false,
53+
env: {
54+
TEMPLATE: 'true'
55+
},
56+
async checkRun(t, run) {
57+
await t.notThrowsAsync(run, 'Expected fixture not to throw');
58+
const result = await run;
59+
t.snapshot(result.stats.passed, 'passed tests');
60+
t.snapshot(result.stats.unsavedSnapshots, 'files where snapshots could not be updated');
61+
}
62+
});
63+
64+
test('snapshots remain if tests run with --match', macro, {
65+
cwd: exec.cwd('removal'),
66+
cli: ['--update-snapshots', '--match=\'*snapshot*\''],
67+
remove: false,
68+
checkRun: async (t, run) => {
69+
const result = await t.throwsAsync(run, undefined, 'Expected fixture to throw');
70+
t.snapshot(exec.cleanOutput(result.stderr), 'stderr');
71+
}
72+
});
73+
74+
test('snapshots remain if tests selected by line numbers', macro, {
75+
cwd: exec.cwd('removal'),
76+
cli: ['test.js:3-12', '--update-snapshots'],
77+
remove: false,
78+
checkRun: async (t, run) => {
79+
const result = await t.throwsAsync(run, undefined, 'Expected fixture to throw');
80+
t.snapshot(exec.cleanOutput(result.stderr), 'stderr');
81+
}
82+
});
83+
84+
test('snapshots remain if using test.only', macro, {
85+
cwd: exec.cwd('only-test'),
86+
cli: ['--update-snapshots'],
87+
remove: false,
88+
checkRun: async (t, run) => {
89+
await t.notThrowsAsync(run, 'Expected fixture not to throw');
90+
const result = await run;
91+
t.snapshot(result.stats.unsavedSnapshots, 'files where snapshots could not be updated');
92+
}
93+
});
94+
95+
test('snapshots remain if tests are skipped', macro, {
96+
cwd: exec.cwd('skipped-tests'),
97+
cli: ['--update-snapshots'],
98+
remove: false,
99+
checkRun: async (t, run) => {
100+
await t.notThrowsAsync(run, 'Expected fixture not to throw');
101+
const result = await run;
102+
t.snapshot(result.stats.unsavedSnapshots, 'files where snapshots could not be updated');
103+
}
104+
});
105+
106+
test('snapshots remain if snapshot assertions are skipped', macro, {
107+
cwd: exec.cwd('skipped-snapshots'),
108+
cli: ['--update-snapshots'],
109+
remove: false,
110+
checkRun: async (t, run) => {
111+
const result = await t.throwsAsync(run, {
112+
message: /Snapshot assertions cannot be skipped when updating snapshots/
113+
}, 'Expected fixture to throw');
114+
t.snapshot(result.stats.unsavedSnapshots, 'files where snapshots could not be updated');
115+
}
116+
});
117+
118+
test('snapshots remain if used in a discarded try()', macro, {
119+
cwd: exec.cwd('try'),
120+
cli: ['--update-snapshots'],
121+
remove: false
122+
});
123+
124+
test('snapshots remain if skipped in a discarded try()', macro, {
125+
cwd: exec.cwd('skipped-snapshots-in-try'),
126+
cli: ['--update-snapshots'],
127+
remove: false,
128+
checkRun: async (t, run) => {
129+
await t.notThrowsAsync(run, 'Expected fixture not to throw');
130+
const result = await run;
131+
t.snapshot(result.stats.unsavedSnapshots, 'files where snapshots could not be updated');
132+
}
133+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
const test = require('ava');
2+
3+
test('always failing snapshot', t => {
4+
t.snapshot(Date.now());
5+
});
6+
7+
test('skipped assertion', t => {
8+
t.snapshot.skip(Date.now()); // eslint-disable-line ava/no-skip-assert
9+
t.pass();
10+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# Snapshot report for `contains-skip-assertion.js`
2+
3+
The actual snapshot is saved in `contains-skip-assertion.js.snap`.
4+
5+
Generated by [AVA](https://avajs.dev).
6+
7+
## always failing snapshot
8+
9+
> Snapshot 1
10+
11+
1607992742963
Binary file not shown.

‎test/snapshot-updates/snapshots/test.js.md

+28
Original file line numberDiff line numberDiff line change
@@ -66,3 +66,31 @@ Generated by [AVA](https://avajs.dev).
6666
> Snapshot 1
6767
6868
'Snapshots cannot be updated when selecting specific tests by their line number.'
69+
70+
## cannot update snapshots when skipping snapshot assertions
71+
72+
> failed tests
73+
74+
[
75+
{
76+
file: 'contains-skip-assertion.js',
77+
title: 'skipped assertion',
78+
},
79+
]
80+
81+
> passed tests
82+
83+
[
84+
{
85+
file: 'contains-skip-assertion.js',
86+
title: 'always failing snapshot',
87+
},
88+
]
89+
90+
> files where snapshots could not be updated
91+
92+
[
93+
{
94+
file: 'contains-skip-assertion.js',
95+
},
96+
]
71 Bytes
Binary file not shown.

‎test/snapshot-updates/test.js

+7
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,10 @@ test('cannot update snapshots when selecting tests by line number', async t => {
2424
const result = await t.throwsAsync(exec.fixture(['contains-skip.js:4', '-u']));
2525
t.snapshot(exec.cleanOutput(result.stderr));
2626
});
27+
28+
test('cannot update snapshots when skipping snapshot assertions', async t => {
29+
const result = await t.throwsAsync(exec.fixture(['contains-skip-assertion.js', '-u'], {env: {AVA_FORCE_CI: 'not-ci'}}));
30+
t.snapshot(result.stats.failed, 'failed tests');
31+
t.snapshot(result.stats.passed, 'passed tests');
32+
t.snapshot(result.stats.unsavedSnapshots, 'files where snapshots could not be updated');
33+
});

0 commit comments

Comments
 (0)
Please sign in to comment.