Skip to content

Fail snapshot assertions in CI if snapshot is missing #2101

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 28, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion lib/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,9 @@ class Api extends Emittery {

const execArgv = await this._computeForkExecArgv();
const options = {
...apiOptions, // If we're looking for matches, run every single test process in exclusive-only mode
...apiOptions,
recordNewSnapshots: !isCi,
// If we're looking for matches, run every single test process in exclusive-only mode
runOnlyExclusive: apiOptions.match.length > 0 || runtimeOptions.runOnlyExclusive === true
};
if (precompilation) {
Expand Down
3 changes: 2 additions & 1 deletion lib/assert.js
Original file line number Diff line number Diff line change
Expand Up @@ -616,9 +616,10 @@ class Assertions {
values: [formatDescriptorDiff(result.actual, result.expected, {invert: true})]
}));
} else {
// This can only occur in CI environments.
fail(new AssertionError({
assertion: 'snapshot',
message: message || 'No snapshot available, run with --update-snapshots'
message: message || 'No snapshot available — new snapshots are not created in CI environments'
}));
}
});
Expand Down
2 changes: 2 additions & 0 deletions lib/runner.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ class Runner extends Emittery {
this.file = options.file;
this.match = options.match || [];
this.projectDir = options.projectDir;
this.recordNewSnapshots = options.recordNewSnapshots === true;
this.runOnlyExclusive = options.runOnlyExclusive === true;
this.serial = options.serial === true;
this.snapshotDir = options.snapshotDir;
Expand Down Expand Up @@ -171,6 +172,7 @@ class Runner extends Emittery {
file: this.file,
fixedLocation: this.snapshotDir,
projectDir: this.projectDir,
recordNewSnapshots: this.recordNewSnapshots,
updating: this.updateSnapshots
});
this.emit('dependency', this.snapshots.snapPath);
Expand Down
8 changes: 7 additions & 1 deletion lib/snapshot-manager.js
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,7 @@ class Manager {
constructor(options) {
this.appendOnly = options.appendOnly;
this.dir = options.dir;
this.recordNewSnapshots = options.recordNewSnapshots;
this.relFile = options.relFile;
this.reportFile = options.reportFile;
this.snapFile = options.snapFile;
Expand All @@ -309,6 +310,10 @@ class Manager {
}

if (options.index === entries.length) {
if (!this.recordNewSnapshots) {
return {pass: false};
}

this.record(hash, options);
return {pass: true};
}
Expand Down Expand Up @@ -400,7 +405,7 @@ function resolveSourceFile(file) {
return file;
}

function load({file, fixedLocation, projectDir, updating}) {
function load({file, fixedLocation, projectDir, recordNewSnapshots, updating}) {
const sourceFile = resolveSourceFile(file);
const dir = determineSnapshotDir({file: sourceFile, fixedLocation, projectDir});
const relFile = path.relative(projectDir, sourceFile);
Expand All @@ -424,6 +429,7 @@ function load({file, fixedLocation, projectDir, updating}) {
return new Manager({
appendOnly,
dir,
recordNewSnapshots,
relFile,
reportFile,
snapFile,
Expand Down
1 change: 1 addition & 0 deletions lib/worker/subprocess.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ ipc.options.then(options => {
file: options.file,
match: options.match,
projectDir: options.projectDir,
recordNewSnapshots: options.recordNewSnapshots,
runOnlyExclusive: options.runOnlyExclusive,
serial: options.serial,
snapshotDir: options.snapshotDir,
Expand Down
43 changes: 38 additions & 5 deletions test/integration/snapshots.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@ const uniqueTempDir = require('unique-temp-dir');
const {test} = require('tap');
const {execCli} = require('../helper/cli');

const overrideCIChecks = {
CI: '',
TRAVIS: '',
CONTINUOUS_INTEGRATION: ''
};

for (const obj of [
{type: 'colocated', rel: '', dir: ''},
{type: '__tests__', rel: '__tests__-dir', dir: '__tests__/__snapshots__'},
Expand All @@ -24,7 +30,7 @@ for (const obj of [

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

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

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

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

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

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

// Test should pass, and a snapshot gets written
execCli(['--update-snapshots'], {dirname: fixtureDir}, error => {
execCli(['--update-snapshots', '--verbose'], {dirname: fixtureDir, env: overrideCIChecks}, error => {
t.ifError(error);
t.true(fs.existsSync(reportPath));
t.true(fs.existsSync(snapPath));
Expand All @@ -246,3 +252,30 @@ test('snapshots are indentical on different platforms', t => {
t.end();
});
});

test('in CI, new snapshots are not recorded', t => {
const fixtureDir = path.join(__dirname, '..', 'fixture', 'snapshots', 'test-content');
const reportPath = path.join(fixtureDir, 'tests', 'snapshots', 'test.js.md');
const snapPath = path.join(fixtureDir, 'tests', 'snapshots', 'test.js.snap');

const removeFile = filePath => {
try {
fs.unlinkSync(filePath);
} catch (error) {
if (error.code !== 'ENOENT') {
throw error;
}
}
};

// Clear current snapshots
[reportPath, snapPath].forEach(fp => removeFile(fp));

// Test should fail, no snapshot gets written
execCli([], {dirname: fixtureDir}, (_, stdout) => {
t.match(stdout, 'No snapshot available — new snapshots are not created in CI environments');
t.false(fs.existsSync(reportPath));
t.false(fs.existsSync(snapPath));
t.end();
});
});