diff --git a/lib/runner.js b/lib/runner.js index 45126e374..bda2132fd 100644 --- a/lib/runner.js +++ b/lib/runner.js @@ -182,12 +182,13 @@ class Runner extends EventEmitter { compareTestSnapshot(options) { if (!this.snapshots) { - const name = path.basename(this.file); - // TODO: Only use __snapshots__ directory name if file is inside a - // __tests__ directory (relative to the project root). - const dir = path.join(path.dirname(this.file), '__snapshots__'); - const relFile = path.relative(this.projectDir, this.file); - this.snapshots = snapshotManager.load(dir, name, relFile, this.updateSnapshots); + this.snapshots = snapshotManager.load({ + name: path.basename(this.file), + projectDir: this.projectDir, + relFile: path.relative(this.projectDir, this.file), + testDir: path.dirname(this.file), + updating: this.updateSnapshots + }); this.emit('dependency', this.snapshots.snapPath); } diff --git a/lib/snapshot-manager.js b/lib/snapshot-manager.js index 5b710df69..e7a053919 100644 --- a/lib/snapshot-manager.js +++ b/lib/snapshot-manager.js @@ -354,15 +354,26 @@ class Manager { } } -function load(dir, name, relFile, updating) { - const reportFile = `${name}.md`; - const snapFile = `${name}.snap`; +function determineSnapshotDir(projectDir, testDir) { + const parts = new Set(path.relative(projectDir, testDir).split(path.sep)); + if (parts.has('__tests__')) { + return path.join(testDir, '__snapshots__'); + } else if (parts.has('test') || parts.has('tests')) { // Accept tests, even though it's not in the default test patterns + return path.join(testDir, 'snapshots'); + } + return testDir; +} + +function load(options) { + const dir = determineSnapshotDir(options.projectDir, options.testDir); + const reportFile = `${options.name}.md`; + const snapFile = `${options.name}.snap`; const snapPath = path.join(dir, snapFile); - let appendOnly = !updating; + let appendOnly = !options.updating; let snapshotsByHash; - if (!updating) { + if (!options.updating) { const buffer = tryRead(snapPath); if (buffer) { snapshotsByHash = decodeSnapshots(buffer, snapPath); @@ -374,7 +385,7 @@ function load(dir, name, relFile, updating) { return new Manager({ appendOnly, dir, - relFile, + relFile: options.relFile, reportFile, snapFile, snapPath, diff --git a/test/assert.js b/test/assert.js index 7a17e7a97..8902ca82b 100644 --- a/test/assert.js +++ b/test/assert.js @@ -736,9 +736,16 @@ test('.snapshot()', t => { // "$(npm bin)"/tap --no-cov -R spec test/assert.js // // Ignore errors and make sure not to run tests with the `-b` (bail) option. - const update = false; + const updating = false; - const manager = snapshotManager.load(path.join(__dirname, 'fixture'), 'assert.js', 'test/assert.js', update); + const projectDir = path.join(__dirname, 'fixture'); + const manager = snapshotManager.load({ + projectDir, + testDir: projectDir, + name: 'assert.js', + relFile: 'test/assert.js', + updating + }); const setup = title => { const fauxTest = new Test({ title, @@ -760,7 +767,7 @@ test('.snapshot()', t => { { const executionContext = setup('fails'); - if (update) { + if (updating) { assertions.snapshot.call(executionContext, {foo: 'bar'}); } else { failsWith(t, () => { @@ -784,7 +791,7 @@ test('.snapshot()', t => { { const executionContext = setup('fails'); - if (update) { + if (updating) { assertions.snapshot.call(executionContext, {foo: 'bar'}, 'my message'); } else { failsWith(t, () => { @@ -799,7 +806,7 @@ test('.snapshot()', t => { { const executionContext = setup('rendered comparison'); - if (update) { + if (updating) { assertions.snapshot.call(executionContext, renderer.create(React.createElement(HelloMessage, {name: 'Sindre'})).toJSON()); } else { passes(t, () => { @@ -810,7 +817,7 @@ test('.snapshot()', t => { { const executionContext = setup('rendered comparison'); - if (update) { + if (updating) { assertions.snapshot.call(executionContext, renderer.create(React.createElement(HelloMessage, {name: 'Sindre'})).toJSON()); } else { failsWith(t, () => { @@ -825,7 +832,7 @@ test('.snapshot()', t => { { const executionContext = setup('element comparison'); - if (update) { + if (updating) { assertions.snapshot.call(executionContext, React.createElement(HelloMessage, {name: 'Sindre'})); } else { failsWith(t, () => { diff --git a/test/cli.js b/test/cli.js index 8446a614d..161ac2f71 100644 --- a/test/cli.js +++ b/test/cli.js @@ -354,7 +354,7 @@ test('watcher reruns test files when snapshot dependencies change', t => { } else { passedFirst = true; setTimeout(() => { - touch.sync(path.join(__dirname, 'fixture/snapshots/__snapshots__/test.js.snap')); + touch.sync(path.join(__dirname, 'fixture/snapshots/test.js.snap')); }, 500); } } @@ -556,29 +556,39 @@ test('promise tests fail if event loop empties before they\'re resolved', t => { }); }); -test('snapshots work', t => { - try { - fs.unlinkSync(path.join(__dirname, 'fixture', 'snapshots', '__snapshots__', 'test.js.snap')); - } catch (err) { - if (err.code !== 'ENOENT') { - throw err; +for (const obj of [ + {type: 'colocated', rel: '', dir: ''}, + {type: '__tests__', rel: '__tests__-dir', dir: '__tests__/__snapshots__'}, + {type: 'test', rel: 'test-dir', dir: 'test/snapshots'}, + {type: 'tests', rel: 'tests-dir', dir: 'tests/snapshots'} +]) { + test(`snapshots work (${obj.type})`, t => { + const snapPath = path.join(__dirname, 'fixture', 'snapshots', obj.rel, obj.dir, 'test.js.snap'); + try { + fs.unlinkSync(snapPath); + } catch (err) { + if (err.code !== 'ENOENT') { + throw err; + } } - } - // Test should pass, and a snapshot gets written - execCli(['--update-snapshots', 'test.js'], {dirname: 'fixture/snapshots'}, err => { - t.ifError(err); - - // Test should pass, and the snapshot gets used - execCli(['test.js'], {dirname: 'fixture/snapshots'}, err => { + const dirname = path.join('fixture/snapshots', obj.rel); + // Test should pass, and a snapshot gets written + execCli(['--update-snapshots'], {dirname}, err => { t.ifError(err); - t.end(); + t.true(fs.existsSync(snapPath)); + + // Test should pass, and the snapshot gets used + execCli([], {dirname}, err => { + t.ifError(err); + t.end(); + }); }); }); -}); +} test('outdated snapshot version is reported to the console', t => { - const snapPath = path.join(__dirname, 'fixture', 'snapshots', '__snapshots__', 'test.js.snap'); + const snapPath = path.join(__dirname, 'fixture', 'snapshots', 'test.js.snap'); fs.writeFileSync(snapPath, Buffer.from([0x0A, 0x00, 0x00])); execCli(['test.js'], {dirname: 'fixture/snapshots'}, (err, stdout, stderr) => { @@ -592,7 +602,7 @@ test('outdated snapshot version is reported to the console', t => { }); test('newer snapshot version is reported to the console', t => { - const snapPath = path.join(__dirname, 'fixture', 'snapshots', '__snapshots__', 'test.js.snap'); + const snapPath = path.join(__dirname, 'fixture', 'snapshots', 'test.js.snap'); fs.writeFileSync(snapPath, Buffer.from([0x0A, 0xFF, 0xFF])); execCli(['test.js'], {dirname: 'fixture/snapshots'}, (err, stdout, stderr) => { @@ -606,7 +616,7 @@ test('newer snapshot version is reported to the console', t => { }); test('snapshot corruption is reported to the console', t => { - const snapPath = path.join(__dirname, 'fixture', 'snapshots', '__snapshots__', 'test.js.snap'); + const snapPath = path.join(__dirname, 'fixture', 'snapshots', 'test.js.snap'); fs.writeFileSync(snapPath, Buffer.from([0x0A, 0x01, 0x00])); execCli(['test.js'], {dirname: 'fixture/snapshots'}, (err, stdout, stderr) => { @@ -620,7 +630,7 @@ test('snapshot corruption is reported to the console', t => { }); test('legacy snapshot files are reported to the console', t => { - const snapPath = path.join(__dirname, 'fixture', 'snapshots', '__snapshots__', 'test.js.snap'); + const snapPath = path.join(__dirname, 'fixture', 'snapshots', 'test.js.snap'); fs.writeFileSync(snapPath, Buffer.from('// Jest Snapshot v1, https://goo.gl/fbAQLP\n')); execCli(['test.js'], {dirname: 'fixture/snapshots'}, (err, stdout, stderr) => { diff --git a/test/fixture/snapshots/.gitignore b/test/fixture/snapshots/.gitignore index b05c2dfa7..c8bddd146 100644 --- a/test/fixture/snapshots/.gitignore +++ b/test/fixture/snapshots/.gitignore @@ -1 +1,4 @@ +*.snap +*.md +snapshots __snapshots__ diff --git a/test/fixture/snapshots/__tests__-dir/__tests__/test.js b/test/fixture/snapshots/__tests__-dir/__tests__/test.js new file mode 100644 index 000000000..b1ba91e85 --- /dev/null +++ b/test/fixture/snapshots/__tests__-dir/__tests__/test.js @@ -0,0 +1,11 @@ +import test from '../../../../..'; + +test('test title', t => { + t.snapshot({foo: 'bar'}); + + t.snapshot({answer: 42}); +}); + +test('another test', t => { + t.snapshot(new Map()); +}); diff --git a/test/fixture/snapshots/__tests__-dir/package.json b/test/fixture/snapshots/__tests__-dir/package.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/test/fixture/snapshots/__tests__-dir/package.json @@ -0,0 +1 @@ +{} diff --git a/test/fixture/snapshots/test-dir/package.json b/test/fixture/snapshots/test-dir/package.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/test/fixture/snapshots/test-dir/package.json @@ -0,0 +1 @@ +{} diff --git a/test/fixture/snapshots/test-dir/test/test.js b/test/fixture/snapshots/test-dir/test/test.js new file mode 100644 index 000000000..b1ba91e85 --- /dev/null +++ b/test/fixture/snapshots/test-dir/test/test.js @@ -0,0 +1,11 @@ +import test from '../../../../..'; + +test('test title', t => { + t.snapshot({foo: 'bar'}); + + t.snapshot({answer: 42}); +}); + +test('another test', t => { + t.snapshot(new Map()); +}); diff --git a/test/fixture/snapshots/tests-dir/package.json b/test/fixture/snapshots/tests-dir/package.json new file mode 100644 index 000000000..07510b0f5 --- /dev/null +++ b/test/fixture/snapshots/tests-dir/package.json @@ -0,0 +1,5 @@ +{ + "ava": { + "files": "tests" + } +} diff --git a/test/fixture/snapshots/tests-dir/tests/test.js b/test/fixture/snapshots/tests-dir/tests/test.js new file mode 100644 index 000000000..b1ba91e85 --- /dev/null +++ b/test/fixture/snapshots/tests-dir/tests/test.js @@ -0,0 +1,11 @@ +import test from '../../../../..'; + +test('test title', t => { + t.snapshot({foo: 'bar'}); + + t.snapshot({answer: 42}); +}); + +test('another test', t => { + t.snapshot(new Map()); +});