diff --git a/packages/cli/snapshots/integration/snapshot-matcher/suite-first-run.integration.snapshots.js b/packages/cli/snapshots/integration/snapshot-matcher/suite-first-run.integration.snapshots.js new file mode 100644 index 000000000000..e8f724f91d11 --- /dev/null +++ b/packages/cli/snapshots/integration/snapshot-matcher/suite-first-run.integration.snapshots.js @@ -0,0 +1,17 @@ +// IMPORTANT +// This snapshot file is auto-generated, but designed for humans. +// It should be checked into source control and tracked carefully. +// Re-generate by setting UPDATE_SNAPSHOTS=1 and running tests. +// Make sure to inspect the changes in the snapshots below. +// Do not ignore changes! + +'use strict'; + +exports[`snapshot-matcher first case matches snapshot 1`] = ` +first case +`; + + +exports[`snapshot-matcher first case shared test matches snapshot 1`] = ` +common result +`; diff --git a/packages/cli/snapshots/integration/snapshot-matcher/suite-second-run.integration.snapshots.js b/packages/cli/snapshots/integration/snapshot-matcher/suite-second-run.integration.snapshots.js new file mode 100644 index 000000000000..c16c599ebdc5 --- /dev/null +++ b/packages/cli/snapshots/integration/snapshot-matcher/suite-second-run.integration.snapshots.js @@ -0,0 +1,17 @@ +// IMPORTANT +// This snapshot file is auto-generated, but designed for humans. +// It should be checked into source control and tracked carefully. +// Re-generate by setting UPDATE_SNAPSHOTS=1 and running tests. +// Make sure to inspect the changes in the snapshots below. +// Do not ignore changes! + +'use strict'; + +exports[`snapshot-matcher second case matches snapshot 1`] = ` +second case +`; + + +exports[`snapshot-matcher second case shared test matches snapshot 1`] = ` +common result +`; diff --git a/packages/cli/test/integration/snapshot-matcher/common.suite.js b/packages/cli/test/integration/snapshot-matcher/common.suite.js new file mode 100644 index 000000000000..5c346fff2929 --- /dev/null +++ b/packages/cli/test/integration/snapshot-matcher/common.suite.js @@ -0,0 +1,21 @@ +// Copyright IBM Corp. 2018,2020. All Rights Reserved. +// Node module: @loopback/cli +// This file is licensed under the MIT License. +// License text available at https://opensource.org/licenses/MIT + +'use strict'; + +// A shared test suite executed by "suite-first-run.integration.js" +// and "suite-second-run.integration.js" +const {expectToMatchSnapshot} = require('../../snapshots'); + +/** + * Execute this method from inside a `describe()` block in your test file. + */ +exports.commonTestSuite = function () { + describe('shared test', () => { + it('matches snapshot', function () { + expectToMatchSnapshot('common result'); + }); + }); +}; diff --git a/packages/cli/test/integration/snapshot-matcher/suite-first-run.integration.js b/packages/cli/test/integration/snapshot-matcher/suite-first-run.integration.js new file mode 100644 index 000000000000..42dcde6000b2 --- /dev/null +++ b/packages/cli/test/integration/snapshot-matcher/suite-first-run.integration.js @@ -0,0 +1,17 @@ +// Copyright IBM Corp. 2018,2020. All Rights Reserved. +// Node module: @loopback/cli +// This file is licensed under the MIT License. +// License text available at https://opensource.org/licenses/MIT + +'use strict'; + +const {expectToMatchSnapshot} = require('../../snapshots'); +const {commonTestSuite} = require('./common.suite'); + +describe('snapshot-matcher first case', () => { + commonTestSuite(); + + it('matches snapshot', () => { + expectToMatchSnapshot('first case'); + }); +}); diff --git a/packages/cli/test/integration/snapshot-matcher/suite-second-run.integration.js b/packages/cli/test/integration/snapshot-matcher/suite-second-run.integration.js new file mode 100644 index 000000000000..019c8c018c64 --- /dev/null +++ b/packages/cli/test/integration/snapshot-matcher/suite-second-run.integration.js @@ -0,0 +1,17 @@ +// Copyright IBM Corp. 2018,2020. All Rights Reserved. +// Node module: @loopback/cli +// This file is licensed under the MIT License. +// License text available at https://opensource.org/licenses/MIT + +'use strict'; + +const {expectToMatchSnapshot} = require('../../snapshots'); +const {commonTestSuite} = require('./common.suite'); + +describe('snapshot-matcher second case', () => { + commonTestSuite(); + + it('matches snapshot', () => { + expectToMatchSnapshot('second case'); + }); +}); diff --git a/packages/cli/test/snapshot-matcher.js b/packages/cli/test/snapshot-matcher.js index 17b841d3f6a5..6351e20339fe 100644 --- a/packages/cli/test/snapshot-matcher.js +++ b/packages/cli/test/snapshot-matcher.js @@ -16,8 +16,11 @@ move this file to a standalone package so that all Mocha users can use it. const chalk = require('chalk'); const assert = require('assert'); +const debug = require('debug')('test:snapshot-matcher'); const path = require('path'); +const root = process.cwd(); + module.exports = { initializeSnapshots, }; @@ -43,6 +46,22 @@ module.exports = { * ``` */ function initializeSnapshots(snapshotDir) { + if (debug.enabled) { + const stack = new Error().stack + .split(/\n/g) + // Remove the error message and the top stack frame pointing to ourselves + // and pick three frames (max), that should be enough to identify + // which test file called us. + .slice(2, 5) + .map(f => `\n${f}`) + .join(); + debug( + 'Initializing snapshot matcher, storing snapshots in %s%s', + snapshotDir, + stack, + ); + } + let currentTest; let snapshotErrors = false; @@ -101,8 +120,10 @@ function matchSnapshot(snapshotDir, currentTest, actualValue) { const key = buildSnapshotKey(currentTest); if (!(key in snapshotData)) { + const shortFile = path.relative(root, snapshotFile); throw new Error( - `No snapshot found for ${JSON.stringify(key)}.\n` + + `No snapshot found in ${JSON.stringify(shortFile)} ` + + `for ${JSON.stringify(key)}.\n` + 'Run the tests with `UPDATE_SNAPSHOTS=1` environment variable ' + 'to create and update snapshot files.', ); @@ -129,6 +150,13 @@ function recordSnapshot(snapshots, currentTest, actualValue) { const key = buildSnapshotKey(currentTest); const testFile = currentTest.file; + if (debug.enabled) { + debug( + 'Recording snapshot %j for test file %j', + key, + path.relative(root, testFile), + ); + } if (!snapshots[testFile]) snapshots[testFile] = Object.create(null); snapshots[testFile][key] = actualValue; } @@ -211,6 +239,7 @@ function writeSnapshotData(snapshotFile, snapshots) { const content = header + entries.join('\n'); mkdirp.sync(path.dirname(snapshotFile)); + debug('Updating snapshot file %j', path.relative(root, snapshotFile)); return writeFileAtomic(snapshotFile, content, {encoding: 'utf-8'}); }