Skip to content

Commit 0804107

Browse files
committed
Fail snapshot assertions in CI if snapshot is missing
Fixes #1585.
1 parent 2ce1999 commit 0804107

File tree

6 files changed

+53
-8
lines changed

6 files changed

+53
-8
lines changed

lib/api.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,9 @@ class Api extends Emittery {
207207

208208
const execArgv = await this._computeForkExecArgv();
209209
const options = {
210-
...apiOptions, // If we're looking for matches, run every single test process in exclusive-only mode
210+
...apiOptions,
211+
recordNewSnapshots: !isCi,
212+
// If we're looking for matches, run every single test process in exclusive-only mode
211213
runOnlyExclusive: apiOptions.match.length > 0 || runtimeOptions.runOnlyExclusive === true
212214
};
213215
if (precompilation) {

lib/assert.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -616,9 +616,10 @@ class Assertions {
616616
values: [formatDescriptorDiff(result.actual, result.expected, {invert: true})]
617617
}));
618618
} else {
619+
// This can only occur in CI environments.
619620
fail(new AssertionError({
620621
assertion: 'snapshot',
621-
message: message || 'No snapshot available, run with --update-snapshots'
622+
message: message || 'No snapshot available — new snapshots are not created in CI environments'
622623
}));
623624
}
624625
});

lib/runner.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ class Runner extends Emittery {
1616
this.file = options.file;
1717
this.match = options.match || [];
1818
this.projectDir = options.projectDir;
19+
this.recordNewSnapshots = options.recordNewSnapshots === true;
1920
this.runOnlyExclusive = options.runOnlyExclusive === true;
2021
this.serial = options.serial === true;
2122
this.snapshotDir = options.snapshotDir;
@@ -171,6 +172,7 @@ class Runner extends Emittery {
171172
file: this.file,
172173
fixedLocation: this.snapshotDir,
173174
projectDir: this.projectDir,
175+
recordNewSnapshots: this.recordNewSnapshots,
174176
updating: this.updateSnapshots
175177
});
176178
this.emit('dependency', this.snapshots.snapPath);

lib/snapshot-manager.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,7 @@ class Manager {
291291
constructor(options) {
292292
this.appendOnly = options.appendOnly;
293293
this.dir = options.dir;
294+
this.recordNewSnapshots = options.recordNewSnapshots;
294295
this.relFile = options.relFile;
295296
this.reportFile = options.reportFile;
296297
this.snapFile = options.snapFile;
@@ -309,6 +310,10 @@ class Manager {
309310
}
310311

311312
if (options.index === entries.length) {
313+
if (!this.recordNewSnapshots) {
314+
return {pass: false};
315+
}
316+
312317
this.record(hash, options);
313318
return {pass: true};
314319
}
@@ -400,7 +405,7 @@ function resolveSourceFile(file) {
400405
return file;
401406
}
402407

403-
function load({file, fixedLocation, projectDir, updating}) {
408+
function load({file, fixedLocation, projectDir, recordNewSnapshots, updating}) {
404409
const sourceFile = resolveSourceFile(file);
405410
const dir = determineSnapshotDir({file: sourceFile, fixedLocation, projectDir});
406411
const relFile = path.relative(projectDir, sourceFile);
@@ -424,6 +429,7 @@ function load({file, fixedLocation, projectDir, updating}) {
424429
return new Manager({
425430
appendOnly,
426431
dir,
432+
recordNewSnapshots,
427433
relFile,
428434
reportFile,
429435
snapFile,

lib/worker/subprocess.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ ipc.options.then(options => {
3636
file: options.file,
3737
match: options.match,
3838
projectDir: options.projectDir,
39+
recordNewSnapshots: options.recordNewSnapshots,
3940
runOnlyExclusive: options.runOnlyExclusive,
4041
serial: options.serial,
4142
snapshotDir: options.snapshotDir,

test/integration/snapshots.js

Lines changed: 38 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,12 @@ const uniqueTempDir = require('unique-temp-dir');
66
const {test} = require('tap');
77
const {execCli} = require('../helper/cli');
88

9+
const overrideCIChecks = {
10+
CI: '',
11+
TRAVIS: '',
12+
CONTINUOUS_INTEGRATION: ''
13+
};
14+
915
for (const obj of [
1016
{type: 'colocated', rel: '', dir: ''},
1117
{type: '__tests__', rel: '__tests__-dir', dir: '__tests__/__snapshots__'},
@@ -24,7 +30,7 @@ for (const obj of [
2430

2531
const dirname = path.join('fixture/snapshots', obj.rel);
2632
// Test should pass, and a snapshot gets written
27-
execCli(['--update-snapshots'], {dirname}, error => {
33+
execCli(['--update-snapshots', '--verbose'], {dirname, env: overrideCIChecks}, error => {
2834
t.ifError(error);
2935
t.true(fs.existsSync(snapPath));
3036

@@ -50,7 +56,7 @@ test('one', t => {
5056
})`;
5157
fs.writeFileSync(path.join(cwd, 'test.js'), initial);
5258

53-
const run = () => execa(process.execPath, [cliPath, '--verbose', '--no-color'], {cwd, env: {CI: '1'}, reject: false});
59+
const run = () => execa(process.execPath, [cliPath, '--verbose', '--no-color'], {cwd, env: overrideCIChecks, reject: false});
5460
return run().then(result => {
5561
t.match(result.stdout, /1 test passed/);
5662

@@ -161,7 +167,7 @@ test('snapshots infer their location and name from sourcemaps', t => {
161167
t.true(fs.existsSync(relFilePath));
162168
};
163169

164-
execCli([], {dirname: relativeFixtureDir}, (error, stdout) => {
170+
execCli(['--verbose'], {dirname: relativeFixtureDir, env: overrideCIChecks}, (error, stdout) => {
165171
t.ifError(error);
166172
snapFixtureFilePaths.forEach(x => verifySnapFixtureFiles(x));
167173
t.match(stdout, /6 tests passed/);
@@ -202,7 +208,7 @@ test('snapshots resolved location from "snapshotDir" in AVA config', t => {
202208
t.true(fs.existsSync(relFilePath));
203209
};
204210

205-
execCli([], {dirname: relativeFixtureDir}, (error, stdout) => {
211+
execCli(['--verbose'], {dirname: relativeFixtureDir, env: overrideCIChecks}, (error, stdout) => {
206212
t.ifError(error);
207213
snapFixtureFilePaths.forEach(x => verifySnapFixtureFiles(x));
208214
t.match(stdout, /6 tests passed/);
@@ -231,7 +237,7 @@ test('snapshots are indentical on different platforms', t => {
231237
[reportPath, snapPath].forEach(fp => removeFile(fp));
232238

233239
// Test should pass, and a snapshot gets written
234-
execCli(['--update-snapshots'], {dirname: fixtureDir}, error => {
240+
execCli(['--update-snapshots', '--verbose'], {dirname: fixtureDir, env: overrideCIChecks}, error => {
235241
t.ifError(error);
236242
t.true(fs.existsSync(reportPath));
237243
t.true(fs.existsSync(snapPath));
@@ -246,3 +252,30 @@ test('snapshots are indentical on different platforms', t => {
246252
t.end();
247253
});
248254
});
255+
256+
test('in CI, new snapshots are not recorded', t => {
257+
const fixtureDir = path.join(__dirname, '..', 'fixture', 'snapshots', 'test-content');
258+
const reportPath = path.join(fixtureDir, 'tests', 'snapshots', 'test.js.md');
259+
const snapPath = path.join(fixtureDir, 'tests', 'snapshots', 'test.js.snap');
260+
261+
const removeFile = filePath => {
262+
try {
263+
fs.unlinkSync(filePath);
264+
} catch (error) {
265+
if (error.code !== 'ENOENT') {
266+
throw error;
267+
}
268+
}
269+
};
270+
271+
// Clear current snapshots
272+
[reportPath, snapPath].forEach(fp => removeFile(fp));
273+
274+
// Test should fail, no snapshot gets written
275+
execCli([], {dirname: fixtureDir}, (_, stdout) => {
276+
t.match(stdout, 'No snapshot available — new snapshots are not created in CI environments');
277+
t.false(fs.existsSync(reportPath));
278+
t.false(fs.existsSync(snapPath));
279+
t.end();
280+
});
281+
});

0 commit comments

Comments
 (0)