From 02e65fb3de91c0144c0f0d15e709e4a776ba4cff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Pierzcha=C5=82a?= Date: Wed, 15 Feb 2017 21:08:25 +0100 Subject: [PATCH 1/9] Add snapshot version support --- .../__snapshots__/Intro-test.js.snap | 2 + .../__snapshots__/Clock.react-test.js.snap | 2 + .../__snapshots__/Link.react-test.js.snap | 2 + .../__snapshots__/console-test.js.snap | 2 + .../coverage_report-test.js.snap | 2 + .../__snapshots__/failures-test.js.snap | 2 + .../__snapshots__/globals-test.js.snap | 2 + .../snapshot-serializers-test.js.snap | 2 + .../__snapshots__/snapshot-test.js.snap | 2 + .../__snapshots__/stack_trace-test.js.snap | 2 + .../testNamePattern-test.js.snap | 2 + .../__snapshots__/transform-test.js.snap | 2 + .../typescript-coverage-test.js.snap | 2 + integration_tests/__tests__/transform-test.js | 2 +- .../multiple-transformers-test.js.snap | 2 + .../generateEmptyCoverage-test.js.snap | 2 + .../watch-filename-pattern-mode-test.js.snap | 2 + .../__snapshots__/watch-test.js.snap | 2 + .../__snapshots__/highlight-test.js.snap | 2 + .../__snapshots__/utils-test.js.snap | 6 +- .../__snapshots__/normalize-test.js.snap | 2 + .../__tests__/__snapshots__/diff-test.js.snap | 2 + .../__snapshots__/index-test.js.snap | 4 +- .../__snapshots__/matchers-test.js.snap | 2 + .../__snapshots__/index-test.js.snap | 2 + .../__snapshots__/extend-test.js.snap | 2 + .../__snapshots__/matchers-test.js.snap | 2 + .../__snapshots__/spyMatchers-test.js.snap | 2 + .../toThrowMatchers-test.js.snap | 2 + .../__snapshots__/messages-test.js.snap | 2 + .../__snapshots__/transform-test.js.snap | 2 + packages/jest-snapshot/src/State.js | 4 +- .../jest-snapshot/src/__tests__/utils-test.js | 64 +++++++++++++++++-- packages/jest-snapshot/src/utils.js | 40 ++++++++++-- .../__snapshots__/FakeTimers-test.js.snap | 2 + .../validateCLIOptions-test.js.snap | 2 + .../__snapshots__/validate-test.js.snap | 2 + .../__snapshots__/pretty-format-test.js.snap | 2 + 38 files changed, 166 insertions(+), 18 deletions(-) diff --git a/examples/react-native/__tests__/__snapshots__/Intro-test.js.snap b/examples/react-native/__tests__/__snapshots__/Intro-test.js.snap index 6edc1ae2c2fe..b660ae33f66e 100644 --- a/examples/react-native/__tests__/__snapshots__/Intro-test.js.snap +++ b/examples/react-native/__tests__/__snapshots__/Intro-test.js.snap @@ -1,3 +1,5 @@ +// Jest Snapshot v1 + exports[`renders correctly 1`] = ` 1482363367.071 diff --git a/examples/snapshot/__tests__/__snapshots__/Link.react-test.js.snap b/examples/snapshot/__tests__/__snapshots__/Link.react-test.js.snap index 97f6046e24f5..21d9519c91f8 100644 --- a/examples/snapshot/__tests__/__snapshots__/Link.react-test.js.snap +++ b/examples/snapshot/__tests__/__snapshots__/Link.react-test.js.snap @@ -1,3 +1,5 @@ +// Jest Snapshot v1 + exports[`changes the class when hovered 1`] = ` { }); it('transforms dependencies using specific transformers', () => { - const {json, stderr} = runJest.json(dir, ['--no-cache']); + const {json, stderr} = runJest.json(dir, ['--no-cache', '-u']); expect(stderr).toMatch(/PASS/); expect(json.numTotalTests).toBe(1); diff --git a/integration_tests/transform/multiple-transformers/__tests__/__snapshots__/multiple-transformers-test.js.snap b/integration_tests/transform/multiple-transformers/__tests__/__snapshots__/multiple-transformers-test.js.snap index a49d275a3dd6..e9b3608274e1 100644 --- a/integration_tests/transform/multiple-transformers/__tests__/__snapshots__/multiple-transformers-test.js.snap +++ b/integration_tests/transform/multiple-transformers/__tests__/__snapshots__/multiple-transformers-test.js.snap @@ -1,3 +1,5 @@ +// Jest Snapshot v1 + exports[`generates a snapshot with correctly transformed dependencies 1`] = `
\\":function(module,exports,require,__dirname,__filename,global,jest){/* istanbul ignore next */var cov_25u22311x4 = function () {var path = \\"/fruits/banana.js\\",hash = \\"04636d4ae73b4b3e24bf6fba39e08c946fd0afb5\\",global = new Function('return this')(),gcv = \\"__coverage__\\",coverageData = { path: \\"/fruits/banana.js\\", statementMap: { \\"0\\": { start: { line: 1, column: 0 }, end: { line: 1, column: 26 } } }, fnMap: {}, branchMap: {}, s: { \\"0\\": 0 }, f: {}, b: {}, _coverageSchema: \\"332fd63041d2c1bcb487cc26dd0d5f7d97098a6c\\" },coverage = global[gcv] || (global[gcv] = {});if (coverage[path] && coverage[path].hash === hash) {return coverage[path];}coverageData.hash = hash;return coverage[path] = coverageData;}();++cov_25u22311x4.s[0];module.exports = \\"banana\\"; }});" diff --git a/packages/jest-snapshot/src/State.js b/packages/jest-snapshot/src/State.js index 5424a410092e..ef57a268cfa8 100644 --- a/packages/jest-snapshot/src/State.js +++ b/packages/jest-snapshot/src/State.js @@ -48,7 +48,7 @@ class SnapshotState { ) { this._dirty = false; this._snapshotPath = snapshotPath || getSnapshotPath(testPath); - this._snapshotData = getSnapshotData(this._snapshotPath); + this._snapshotData = getSnapshotData(this._snapshotPath, update); this._uncheckedKeys = new Set(Object.keys(this._snapshotData)); this._counters = new Map(); this._index = 0; @@ -83,7 +83,7 @@ class SnapshotState { const isEmpty = Object.keys(this._snapshotData).length === 0; - if ((this._dirty || this._uncheckedKeys.size) && !isEmpty) { + if ((this._dirty || this._uncheckedKeys.size || update) && !isEmpty) { saveSnapshotFile(this._snapshotData, this._snapshotPath); status.saved = true; } else if (isEmpty && fileExists(this._snapshotPath)) { diff --git a/packages/jest-snapshot/src/__tests__/utils-test.js b/packages/jest-snapshot/src/__tests__/utils-test.js index 5870d5a846dc..a4c125410188 100644 --- a/packages/jest-snapshot/src/__tests__/utils-test.js +++ b/packages/jest-snapshot/src/__tests__/utils-test.js @@ -9,17 +9,28 @@ 'use strict'; const { + getSnapshotData, getSnapshotPath, keyToTestName, saveSnapshotFile, testNameToKey, + SNAPSHOT_VERSION, } = require('../utils'); const fs = require('fs'); const path = require('path'); const writeFileSync = fs.writeFileSync; -beforeEach(() => fs.writeFileSync = jest.fn()); -afterEach(() => fs.writeFileSync = writeFileSync); +const readFileSync = fs.readFileSync; +beforeEach(() => { + fs.writeFileSync = jest.fn(); + fs.readFileSync = jest.fn(); +}); +afterEach(() => { + fs.writeFileSync = writeFileSync; + fs.readFileSync = readFileSync; +}); + +jest.mock('jest-file-exists', () => () => true); test('keyToTestName()', () => { expect(keyToTestName('abc cde 12')).toBe('abc cde'); @@ -49,7 +60,10 @@ test('saveSnapshotFile() works with \r\n', () => { saveSnapshotFile(data, filename); expect(fs.writeFileSync) - .toBeCalledWith(filename, 'exports[`myKey`] = `
\n
`;\n'); + .toBeCalledWith( + filename, + '// Jest Snapshot v1\n\nexports[`myKey`] = `
\n
`;\n' + ); }); test('saveSnapshotFile() works with \r', () => { @@ -60,7 +74,46 @@ test('saveSnapshotFile() works with \r', () => { saveSnapshotFile(data, filename); expect(fs.writeFileSync) - .toBeCalledWith(filename, 'exports[`myKey`] = `
\n
`;\n'); + .toBeCalledWith( + filename, + '// Jest Snapshot v1\n\nexports[`myKey`] = `
\n
`;\n' + ); +}); + +test('getSnapshotData() throws when no snapshot version', () => { + const filename = path.join(__dirname, 'old-snapshot.snap'); + fs.readFileSync = jest.fn(() => 'exports[`myKey`] = `
\n
`;\n'); + const update = false; + + expect(() => getSnapshotData(filename, update)).toThrowError( + `Stored snapshot version is outdated.\n` + + `Expected: v${SNAPSHOT_VERSION}, but received: v0\n` + + `Update the snapshot to remove this error.` + ); +}); + +test('getSnapshotData() throws for older snapshot version', () => { + const filename = path.join(__dirname, 'old-snapshot.snap'); + fs.readFileSync = jest.fn(() => + '// Jest Snapshot v0.99\n\nexports[`myKey`] = `
\n
`;\n' + ); + const update = false; + + expect(() => getSnapshotData(filename, update)).toThrowError( + `Stored snapshot version is outdated.\n` + + `Expected: v${SNAPSHOT_VERSION}, but received: v0.99\n` + + `Update the snapshot to remove this error.` + ); +}); + +test('getSnapshotData() does not throw for when updating', () => { + const filename = path.join(__dirname, 'old-snapshot.snap'); + fs.readFileSync = jest.fn(() => + 'exports[`myKey`] = `
\n
`;\n' + ); + const update = true; + + expect(() => getSnapshotData(filename, update)).not.toThrow(); }); test('escaping', () => { @@ -68,7 +121,8 @@ test('escaping', () => { const data = '"\'\\'; saveSnapshotFile({key: data}, filename); const writtenData = fs.writeFileSync.mock.calls[0][1]; - expect(writtenData).toBe("exports[`key`] = `\"'\\\\`;\n"); + expect(writtenData) + .toBe("// Jest Snapshot v1\n\nexports[`key`] = `\"'\\\\`;\n"); // eslint-disable-next-line no-unused-vars const exports = {}; diff --git a/packages/jest-snapshot/src/utils.js b/packages/jest-snapshot/src/utils.js index e6f22a45cca9..239414923999 100644 --- a/packages/jest-snapshot/src/utils.js +++ b/packages/jest-snapshot/src/utils.js @@ -21,6 +21,24 @@ const naturalCompare = require('natural-compare'); const getSerializers = require('./plugins').getSerializers; const SNAPSHOT_EXTENSION = 'snap'; +const SNAPSHOT_VERSION = '1'; +const SNAPSHOT_VERSION_REGEXP = /^\/\/ Jest Snapshot v(.+)/g; + +const writeSnapshotVersion = () => + `// Jest Snapshot v${SNAPSHOT_VERSION}`; + +const validateSnapshotVersion = (snapshotContents: string) => { + const versionTest = SNAPSHOT_VERSION_REGEXP.exec(snapshotContents); + const version = versionTest && versionTest[1] || '0'; + + if (version < SNAPSHOT_VERSION) { + throw new Error( + `Stored snapshot version is outdated.\n` + + `Expected: v${SNAPSHOT_VERSION}, but received: v${version}\n` + + `Update the snapshot to remove this error.` + ); + } +}; const testNameToKey = (testName: string, count: number) => testName + ' ' + count; @@ -38,18 +56,22 @@ const getSnapshotPath = (testPath: Path) => path.join( path.basename(testPath) + '.' + SNAPSHOT_EXTENSION, ); -const getSnapshotData = (snapshotPath: Path) => { +const getSnapshotData = (snapshotPath: Path, update: boolean) => { const data = Object.create(null); + let snapshotContents; if (fileExists(snapshotPath)) { try { - delete require.cache[require.resolve(snapshotPath)]; - /* eslint-disable no-useless-call */ - Object.assign(data, require.call(null, snapshotPath)); - /* eslint-enable no-useless-call */ + snapshotContents = fs.readFileSync(snapshotPath, 'utf8'); + // eslint-disable-next-line no-new-func + const populate = new Function('exports', snapshotContents); + populate(data); } catch (e) {} } + if (!update && snapshotContents) { + validateSnapshotVersion(snapshotContents); + } return data; }; @@ -89,15 +111,19 @@ const saveSnapshotFile = ( const snapshots = Object.keys(snapshotData).sort(naturalCompare) .map(key => 'exports[' + printBacktickString(key) + '] = ' + - printBacktickString(normalizeNewlines(snapshotData[key])) + ';', + printBacktickString(normalizeNewlines(snapshotData[key])) + ';', ); ensureDirectoryExists(snapshotPath); - fs.writeFileSync(snapshotPath, snapshots.join('\n\n') + '\n'); + fs.writeFileSync( + snapshotPath, + writeSnapshotVersion() + '\n\n' + snapshots.join('\n\n') + '\n' + ); }; module.exports = { SNAPSHOT_EXTENSION, + SNAPSHOT_VERSION, ensureDirectoryExists, getSnapshotData, getSnapshotPath, diff --git a/packages/jest-util/src/__tests__/__snapshots__/FakeTimers-test.js.snap b/packages/jest-util/src/__tests__/__snapshots__/FakeTimers-test.js.snap index b810300ba283..b984e83fde38 100644 --- a/packages/jest-util/src/__tests__/__snapshots__/FakeTimers-test.js.snap +++ b/packages/jest-util/src/__tests__/__snapshots__/FakeTimers-test.js.snap @@ -1,3 +1,5 @@ +// Jest Snapshot v1 + exports[`FakeTimers runAllTimers warns when trying to advance timers while real timers are used 1`] = ` "A function to advance timers was called but the timers API is not mocked with fake timers. Call \`jest.useFakeTimers()\` in this test or enable fake timers globally by setting \`\\"timers\\": \\"fake\\"\` in the configuration file. This warning is likely a result of a default configuration change in Jest 15. diff --git a/packages/jest-util/src/__tests__/__snapshots__/validateCLIOptions-test.js.snap b/packages/jest-util/src/__tests__/__snapshots__/validateCLIOptions-test.js.snap index d10942de03d5..11909faa9e45 100644 --- a/packages/jest-util/src/__tests__/__snapshots__/validateCLIOptions-test.js.snap +++ b/packages/jest-util/src/__tests__/__snapshots__/validateCLIOptions-test.js.snap @@ -1,3 +1,5 @@ +// Jest Snapshot v1 + exports[`fails for multiple unknown options 1`] = ` "● Unrecognized CLI Parameters: diff --git a/packages/jest-validate/src/__tests__/__snapshots__/validate-test.js.snap b/packages/jest-validate/src/__tests__/__snapshots__/validate-test.js.snap index 20004537cce0..3d2398842e4a 100644 --- a/packages/jest-validate/src/__tests__/__snapshots__/validate-test.js.snap +++ b/packages/jest-validate/src/__tests__/__snapshots__/validate-test.js.snap @@ -1,3 +1,5 @@ +// Jest Snapshot v1 + exports[`displays warning for deprecated config options 1`] = ` "● Deprecation Warning: diff --git a/packages/pretty-format/src/__tests__/__snapshots__/pretty-format-test.js.snap b/packages/pretty-format/src/__tests__/__snapshots__/pretty-format-test.js.snap index 668772c55b33..1be2dd0063a1 100644 --- a/packages/pretty-format/src/__tests__/__snapshots__/pretty-format-test.js.snap +++ b/packages/pretty-format/src/__tests__/__snapshots__/pretty-format-test.js.snap @@ -1,3 +1,5 @@ +// Jest Snapshot v1 + exports[`prettyFormat() ReactTestComponent and ReactElement plugins ReactElement plugin highlights syntax 1`] = ` " Date: Wed, 15 Feb 2017 21:45:39 +0100 Subject: [PATCH 2/9] Add missing snapshots --- .../__snapshots__/watch-test-name-pattern-mode-test.js.snap | 2 ++ .../__snapshots__/formatTestNameByPattern-test.js.snap | 2 ++ 2 files changed, 4 insertions(+) diff --git a/packages/jest-cli/src/__tests__/__snapshots__/watch-test-name-pattern-mode-test.js.snap b/packages/jest-cli/src/__tests__/__snapshots__/watch-test-name-pattern-mode-test.js.snap index 9021f10519b3..042ae1eb41a6 100644 --- a/packages/jest-cli/src/__tests__/__snapshots__/watch-test-name-pattern-mode-test.js.snap +++ b/packages/jest-cli/src/__tests__/__snapshots__/watch-test-name-pattern-mode-test.js.snap @@ -1,3 +1,5 @@ +// Jest Snapshot v1 + exports[`Watch mode flows Pressing "T" enters pattern mode 1`] = ` " diff --git a/packages/jest-cli/src/lib/__tests__/__snapshots__/formatTestNameByPattern-test.js.snap b/packages/jest-cli/src/lib/__tests__/__snapshots__/formatTestNameByPattern-test.js.snap index e669641cb54f..115a52591847 100644 --- a/packages/jest-cli/src/lib/__tests__/__snapshots__/formatTestNameByPattern-test.js.snap +++ b/packages/jest-cli/src/lib/__tests__/__snapshots__/formatTestNameByPattern-test.js.snap @@ -1,3 +1,5 @@ +// Jest Snapshot v1 + exports[`for multiline test name returns test name with highlighted pattern and replaced line breaks 1`] = `"should⏎ name the ⏎function you at..."`; exports[`for multiline test name returns test name with highlighted pattern and replaced line breaks 2`] = `"should⏎ name the ⏎function you at..."`; From b6339c0181b6ba44ca4af6305a8c0f29df862dfa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Pierzcha=C5=82a?= Date: Wed, 15 Feb 2017 22:36:33 +0100 Subject: [PATCH 3/9] Add link to snapshot guide, small regexp fixes --- .../__tests__/__snapshots__/console-test.js.snap | 2 +- .../__snapshots__/coverage_report-test.js.snap | 2 +- .../__tests__/__snapshots__/failures-test.js.snap | 2 +- .../__tests__/__snapshots__/globals-test.js.snap | 2 +- .../snapshot-serializers-test.js.snap | 2 +- .../__tests__/__snapshots__/snapshot-test.js.snap | 2 +- .../__snapshots__/stack_trace-test.js.snap | 2 +- .../__snapshots__/testNamePattern-test.js.snap | 2 +- .../__snapshots__/transform-test.js.snap | 2 +- .../typescript-coverage-test.js.snap | 2 +- .../multiple-transformers-test.js.snap | 2 +- .../generateEmptyCoverage-test.js.snap | 2 +- .../watch-filename-pattern-mode-test.js.snap | 2 +- .../watch-test-name-pattern-mode-test.js.snap | 2 +- .../__tests__/__snapshots__/watch-test.js.snap | 2 +- .../formatTestNameByPattern-test.js.snap | 2 +- .../__snapshots__/highlight-test.js.snap | 2 +- .../__tests__/__snapshots__/utils-test.js.snap | 2 +- .../__snapshots__/normalize-test.js.snap | 2 +- .../src/__tests__/__snapshots__/diff-test.js.snap | 2 +- .../__tests__/__snapshots__/index-test.js.snap | 2 +- .../__tests__/__snapshots__/matchers-test.js.snap | 2 +- .../__tests__/__snapshots__/index-test.js.snap | 2 +- .../__tests__/__snapshots__/extend-test.js.snap | 2 +- .../__tests__/__snapshots__/matchers-test.js.snap | 2 +- .../__snapshots__/spyMatchers-test.js.snap | 2 +- .../__snapshots__/toThrowMatchers-test.js.snap | 2 +- .../__tests__/__snapshots__/messages-test.js.snap | 2 +- .../__snapshots__/transform-test.js.snap | 2 +- .../jest-snapshot/src/__tests__/utils-test.js | 15 +++++++++++---- packages/jest-snapshot/src/utils.js | 6 ++++-- .../__snapshots__/FakeTimers-test.js.snap | 2 +- .../__snapshots__/validateCLIOptions-test.js.snap | 2 +- .../__tests__/__snapshots__/validate-test.js.snap | 2 +- .../__snapshots__/pretty-format-test.js.snap | 2 +- 35 files changed, 48 insertions(+), 39 deletions(-) diff --git a/integration_tests/__tests__/__snapshots__/console-test.js.snap b/integration_tests/__tests__/__snapshots__/console-test.js.snap index 7b8856ba7c20..c6617ce1678f 100644 --- a/integration_tests/__tests__/__snapshots__/console-test.js.snap +++ b/integration_tests/__tests__/__snapshots__/console-test.js.snap @@ -1,4 +1,4 @@ -// Jest Snapshot v1 +// Jest Snapshot v1, https://goo.gl/fbAQLP exports[`console printing 1`] = ` " PASS __tests__/console-test.js diff --git a/integration_tests/__tests__/__snapshots__/coverage_report-test.js.snap b/integration_tests/__tests__/__snapshots__/coverage_report-test.js.snap index 1339c71be711..d5934e33081e 100644 --- a/integration_tests/__tests__/__snapshots__/coverage_report-test.js.snap +++ b/integration_tests/__tests__/__snapshots__/coverage_report-test.js.snap @@ -1,4 +1,4 @@ -// Jest Snapshot v1 +// Jest Snapshot v1, https://goo.gl/fbAQLP exports[`collects coverage only from specified files 1`] = ` "----------|----------|----------|----------|----------|----------------| diff --git a/integration_tests/__tests__/__snapshots__/failures-test.js.snap b/integration_tests/__tests__/__snapshots__/failures-test.js.snap index dd7a407564c9..8b408e5b1601 100644 --- a/integration_tests/__tests__/__snapshots__/failures-test.js.snap +++ b/integration_tests/__tests__/__snapshots__/failures-test.js.snap @@ -1,4 +1,4 @@ -// Jest Snapshot v1 +// Jest Snapshot v1, https://goo.gl/fbAQLP exports[`throwing not Error objects 1`] = ` Object { diff --git a/integration_tests/__tests__/__snapshots__/globals-test.js.snap b/integration_tests/__tests__/__snapshots__/globals-test.js.snap index 75543eedd933..8b86d8fed4ad 100644 --- a/integration_tests/__tests__/__snapshots__/globals-test.js.snap +++ b/integration_tests/__tests__/__snapshots__/globals-test.js.snap @@ -1,4 +1,4 @@ -// Jest Snapshot v1 +// Jest Snapshot v1, https://goo.gl/fbAQLP exports[`basic test constructs 1`] = ` " PASS __tests__/basic-test-constructs-test.js diff --git a/integration_tests/__tests__/__snapshots__/snapshot-serializers-test.js.snap b/integration_tests/__tests__/__snapshots__/snapshot-serializers-test.js.snap index 63491f2650f8..2a87b6477f19 100644 --- a/integration_tests/__tests__/__snapshots__/snapshot-serializers-test.js.snap +++ b/integration_tests/__tests__/__snapshots__/snapshot-serializers-test.js.snap @@ -1,4 +1,4 @@ -// Jest Snapshot v1 +// Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Snapshot serializers renders snapshot 1`] = ` Object { diff --git a/integration_tests/__tests__/__snapshots__/snapshot-test.js.snap b/integration_tests/__tests__/__snapshots__/snapshot-test.js.snap index 8c4f7103df03..cb2563da7e6c 100644 --- a/integration_tests/__tests__/__snapshots__/snapshot-test.js.snap +++ b/integration_tests/__tests__/__snapshots__/snapshot-test.js.snap @@ -1,4 +1,4 @@ -// Jest Snapshot v1 +// Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Snapshot Validation deletes a snapshot when a test does removes all the snapshots 1`] = ` "Test Suites: 3 passed, 3 total diff --git a/integration_tests/__tests__/__snapshots__/stack_trace-test.js.snap b/integration_tests/__tests__/__snapshots__/stack_trace-test.js.snap index 057959cabbaa..7c69c1c5616a 100644 --- a/integration_tests/__tests__/__snapshots__/stack_trace-test.js.snap +++ b/integration_tests/__tests__/__snapshots__/stack_trace-test.js.snap @@ -1,4 +1,4 @@ -// Jest Snapshot v1 +// Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Stack Trace does not print a stack trace for errors when --noStackTrace is given 1`] = ` "Test Suites: 1 failed, 1 total diff --git a/integration_tests/__tests__/__snapshots__/testNamePattern-test.js.snap b/integration_tests/__tests__/__snapshots__/testNamePattern-test.js.snap index 19ea224e6e45..317165f41bea 100644 --- a/integration_tests/__tests__/__snapshots__/testNamePattern-test.js.snap +++ b/integration_tests/__tests__/__snapshots__/testNamePattern-test.js.snap @@ -1,4 +1,4 @@ -// Jest Snapshot v1 +// Jest Snapshot v1, https://goo.gl/fbAQLP exports[`testNamePattern 1`] = ` "Test Suites: 1 passed, 1 total diff --git a/integration_tests/__tests__/__snapshots__/transform-test.js.snap b/integration_tests/__tests__/__snapshots__/transform-test.js.snap index 57f9da730f6e..fa94c6f34d0e 100644 --- a/integration_tests/__tests__/__snapshots__/transform-test.js.snap +++ b/integration_tests/__tests__/__snapshots__/transform-test.js.snap @@ -1,4 +1,4 @@ -// Jest Snapshot v1 +// Jest Snapshot v1, https://goo.gl/fbAQLP exports[`babel-jest instruments only specific files and collects coverage 1`] = ` "------------|----------|----------|----------|----------|----------------| diff --git a/integration_tests/__tests__/__snapshots__/typescript-coverage-test.js.snap b/integration_tests/__tests__/__snapshots__/typescript-coverage-test.js.snap index 4c2a45a30286..a81fd746e81e 100644 --- a/integration_tests/__tests__/__snapshots__/typescript-coverage-test.js.snap +++ b/integration_tests/__tests__/__snapshots__/typescript-coverage-test.js.snap @@ -1,4 +1,4 @@ -// Jest Snapshot v1 +// Jest Snapshot v1, https://goo.gl/fbAQLP exports[`instruments and collects coverage for typescript files 1`] = ` "------------|----------|----------|----------|----------|----------------| diff --git a/integration_tests/transform/multiple-transformers/__tests__/__snapshots__/multiple-transformers-test.js.snap b/integration_tests/transform/multiple-transformers/__tests__/__snapshots__/multiple-transformers-test.js.snap index e9b3608274e1..610c80366e9a 100644 --- a/integration_tests/transform/multiple-transformers/__tests__/__snapshots__/multiple-transformers-test.js.snap +++ b/integration_tests/transform/multiple-transformers/__tests__/__snapshots__/multiple-transformers-test.js.snap @@ -1,4 +1,4 @@ -// Jest Snapshot v1 +// Jest Snapshot v1, https://goo.gl/fbAQLP exports[`generates a snapshot with correctly transformed dependencies 1`] = `
\\":function(module,exports,require,__dirname,__filename,global,jest){/* istanbul ignore next */var cov_25u22311x4 = function () {var path = \\"/fruits/banana.js\\",hash = \\"04636d4ae73b4b3e24bf6fba39e08c946fd0afb5\\",global = new Function('return this')(),gcv = \\"__coverage__\\",coverageData = { path: \\"/fruits/banana.js\\", statementMap: { \\"0\\": { start: { line: 1, column: 0 }, end: { line: 1, column: 26 } } }, fnMap: {}, branchMap: {}, s: { \\"0\\": 0 }, f: {}, b: {}, _coverageSchema: \\"332fd63041d2c1bcb487cc26dd0d5f7d97098a6c\\" },coverage = global[gcv] || (global[gcv] = {});if (coverage[path] && coverage[path].hash === hash) {return coverage[path];}coverageData.hash = hash;return coverage[path] = coverageData;}();++cov_25u22311x4.s[0];module.exports = \\"banana\\"; diff --git a/packages/jest-snapshot/src/__tests__/utils-test.js b/packages/jest-snapshot/src/__tests__/utils-test.js index a4c125410188..0061762d046f 100644 --- a/packages/jest-snapshot/src/__tests__/utils-test.js +++ b/packages/jest-snapshot/src/__tests__/utils-test.js @@ -14,6 +14,7 @@ const { keyToTestName, saveSnapshotFile, testNameToKey, + SNAPSHOT_GUIDE_LINK, SNAPSHOT_VERSION, } = require('../utils'); const fs = require('fs'); @@ -62,7 +63,8 @@ test('saveSnapshotFile() works with \r\n', () => { expect(fs.writeFileSync) .toBeCalledWith( filename, - '// Jest Snapshot v1\n\nexports[`myKey`] = `
\n
`;\n' + `// Jest Snapshot v1, ${SNAPSHOT_GUIDE_LINK}\n\n` + + 'exports[`myKey`] = `
\n
`;\n' ); }); @@ -76,7 +78,8 @@ test('saveSnapshotFile() works with \r', () => { expect(fs.writeFileSync) .toBeCalledWith( filename, - '// Jest Snapshot v1\n\nexports[`myKey`] = `
\n
`;\n' + `// Jest Snapshot v1, ${SNAPSHOT_GUIDE_LINK}\n\n` + + 'exports[`myKey`] = `
\n
`;\n' ); }); @@ -95,7 +98,8 @@ test('getSnapshotData() throws when no snapshot version', () => { test('getSnapshotData() throws for older snapshot version', () => { const filename = path.join(__dirname, 'old-snapshot.snap'); fs.readFileSync = jest.fn(() => - '// Jest Snapshot v0.99\n\nexports[`myKey`] = `
\n
`;\n' + `// Jest Snapshot v0.99, ${SNAPSHOT_GUIDE_LINK}\n\n` + + 'exports[`myKey`] = `
\n
`;\n' ); const update = false; @@ -122,7 +126,10 @@ test('escaping', () => { saveSnapshotFile({key: data}, filename); const writtenData = fs.writeFileSync.mock.calls[0][1]; expect(writtenData) - .toBe("// Jest Snapshot v1\n\nexports[`key`] = `\"'\\\\`;\n"); + .toBe( + `// Jest Snapshot v1, ${SNAPSHOT_GUIDE_LINK}\n\n` + + "exports[`key`] = `\"'\\\\`;\n" + ); // eslint-disable-next-line no-unused-vars const exports = {}; diff --git a/packages/jest-snapshot/src/utils.js b/packages/jest-snapshot/src/utils.js index 239414923999..f080ba1d9360 100644 --- a/packages/jest-snapshot/src/utils.js +++ b/packages/jest-snapshot/src/utils.js @@ -22,10 +22,11 @@ const getSerializers = require('./plugins').getSerializers; const SNAPSHOT_EXTENSION = 'snap'; const SNAPSHOT_VERSION = '1'; -const SNAPSHOT_VERSION_REGEXP = /^\/\/ Jest Snapshot v(.+)/g; +const SNAPSHOT_VERSION_REGEXP = /^\/\/ Jest Snapshot v(.+),/; +const SNAPSHOT_GUIDE_LINK = 'https://goo.gl/fbAQLP'; const writeSnapshotVersion = () => - `// Jest Snapshot v${SNAPSHOT_VERSION}`; + `// Jest Snapshot v${SNAPSHOT_VERSION}, ${SNAPSHOT_GUIDE_LINK}`; const validateSnapshotVersion = (snapshotContents: string) => { const versionTest = SNAPSHOT_VERSION_REGEXP.exec(snapshotContents); @@ -123,6 +124,7 @@ const saveSnapshotFile = ( module.exports = { SNAPSHOT_EXTENSION, + SNAPSHOT_GUIDE_LINK, SNAPSHOT_VERSION, ensureDirectoryExists, getSnapshotData, diff --git a/packages/jest-util/src/__tests__/__snapshots__/FakeTimers-test.js.snap b/packages/jest-util/src/__tests__/__snapshots__/FakeTimers-test.js.snap index b984e83fde38..235d2ba741f5 100644 --- a/packages/jest-util/src/__tests__/__snapshots__/FakeTimers-test.js.snap +++ b/packages/jest-util/src/__tests__/__snapshots__/FakeTimers-test.js.snap @@ -1,4 +1,4 @@ -// Jest Snapshot v1 +// Jest Snapshot v1, https://goo.gl/fbAQLP exports[`FakeTimers runAllTimers warns when trying to advance timers while real timers are used 1`] = ` "A function to advance timers was called but the timers API is not mocked with fake timers. Call \`jest.useFakeTimers()\` in this test or enable fake timers globally by setting \`\\"timers\\": \\"fake\\"\` in the configuration file. This warning is likely a result of a default configuration change in Jest 15. diff --git a/packages/jest-util/src/__tests__/__snapshots__/validateCLIOptions-test.js.snap b/packages/jest-util/src/__tests__/__snapshots__/validateCLIOptions-test.js.snap index 11909faa9e45..fc92881b4bc8 100644 --- a/packages/jest-util/src/__tests__/__snapshots__/validateCLIOptions-test.js.snap +++ b/packages/jest-util/src/__tests__/__snapshots__/validateCLIOptions-test.js.snap @@ -1,4 +1,4 @@ -// Jest Snapshot v1 +// Jest Snapshot v1, https://goo.gl/fbAQLP exports[`fails for multiple unknown options 1`] = ` "● Unrecognized CLI Parameters: diff --git a/packages/jest-validate/src/__tests__/__snapshots__/validate-test.js.snap b/packages/jest-validate/src/__tests__/__snapshots__/validate-test.js.snap index 3d2398842e4a..21bc4c709443 100644 --- a/packages/jest-validate/src/__tests__/__snapshots__/validate-test.js.snap +++ b/packages/jest-validate/src/__tests__/__snapshots__/validate-test.js.snap @@ -1,4 +1,4 @@ -// Jest Snapshot v1 +// Jest Snapshot v1, https://goo.gl/fbAQLP exports[`displays warning for deprecated config options 1`] = ` "● Deprecation Warning: diff --git a/packages/pretty-format/src/__tests__/__snapshots__/pretty-format-test.js.snap b/packages/pretty-format/src/__tests__/__snapshots__/pretty-format-test.js.snap index 1be2dd0063a1..6a0a533778f5 100644 --- a/packages/pretty-format/src/__tests__/__snapshots__/pretty-format-test.js.snap +++ b/packages/pretty-format/src/__tests__/__snapshots__/pretty-format-test.js.snap @@ -1,4 +1,4 @@ -// Jest Snapshot v1 +// Jest Snapshot v1, https://goo.gl/fbAQLP exports[`prettyFormat() ReactTestComponent and ReactElement plugins ReactElement plugin highlights syntax 1`] = ` " Date: Wed, 15 Feb 2017 22:38:16 +0100 Subject: [PATCH 4/9] Update examples snapshots --- .../react-native/__tests__/__snapshots__/Intro-test.js.snap | 2 +- .../snapshot/__tests__/__snapshots__/Clock.react-test.js.snap | 2 +- .../snapshot/__tests__/__snapshots__/Link.react-test.js.snap | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/react-native/__tests__/__snapshots__/Intro-test.js.snap b/examples/react-native/__tests__/__snapshots__/Intro-test.js.snap index b660ae33f66e..10ea6c84fa8d 100644 --- a/examples/react-native/__tests__/__snapshots__/Intro-test.js.snap +++ b/examples/react-native/__tests__/__snapshots__/Intro-test.js.snap @@ -1,4 +1,4 @@ -// Jest Snapshot v1 +// Jest Snapshot v1, https://goo.gl/fbAQLP exports[`renders correctly 1`] = ` diff --git a/examples/snapshot/__tests__/__snapshots__/Link.react-test.js.snap b/examples/snapshot/__tests__/__snapshots__/Link.react-test.js.snap index 21d9519c91f8..62627f397202 100644 --- a/examples/snapshot/__tests__/__snapshots__/Link.react-test.js.snap +++ b/examples/snapshot/__tests__/__snapshots__/Link.react-test.js.snap @@ -1,4 +1,4 @@ -// Jest Snapshot v1 +// Jest Snapshot v1, https://goo.gl/fbAQLP exports[`changes the class when hovered 1`] = `
Date: Wed, 15 Feb 2017 22:51:51 +0100 Subject: [PATCH 5/9] Add parens for readability --- packages/jest-snapshot/src/utils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/jest-snapshot/src/utils.js b/packages/jest-snapshot/src/utils.js index f080ba1d9360..a4ea9aea80bc 100644 --- a/packages/jest-snapshot/src/utils.js +++ b/packages/jest-snapshot/src/utils.js @@ -30,7 +30,7 @@ const writeSnapshotVersion = () => const validateSnapshotVersion = (snapshotContents: string) => { const versionTest = SNAPSHOT_VERSION_REGEXP.exec(snapshotContents); - const version = versionTest && versionTest[1] || '0'; + const version = (versionTest && versionTest[1]) || '0'; if (version < SNAPSHOT_VERSION) { throw new Error( From 280d442b2f770498a0b10d59939eee8df91c3aa1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Pierzcha=C5=82a?= Date: Wed, 15 Feb 2017 23:22:33 +0100 Subject: [PATCH 6/9] Remove unnecessary -u flag from transform test --- integration_tests/__tests__/transform-test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integration_tests/__tests__/transform-test.js b/integration_tests/__tests__/transform-test.js index 372cd215cbe8..7d173edbc676 100644 --- a/integration_tests/__tests__/transform-test.js +++ b/integration_tests/__tests__/transform-test.js @@ -98,7 +98,7 @@ describe('multiple-transformers', () => { }); it('transforms dependencies using specific transformers', () => { - const {json, stderr} = runJest.json(dir, ['--no-cache', '-u']); + const {json, stderr} = runJest.json(dir, ['--no-cache']); expect(stderr).toMatch(/PASS/); expect(json.numTotalTests).toBe(1); From 6c327a60c971657517170166692405d0bea22c20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Pierzcha=C5=82a?= Date: Wed, 15 Feb 2017 23:56:48 +0100 Subject: [PATCH 7/9] Update snapshot version messages to be more exhaustive --- .../jest-snapshot/src/__tests__/utils-test.js | 38 +++++++++++++++--- packages/jest-snapshot/src/utils.js | 39 +++++++++++++++++-- 2 files changed, 67 insertions(+), 10 deletions(-) diff --git a/packages/jest-snapshot/src/__tests__/utils-test.js b/packages/jest-snapshot/src/__tests__/utils-test.js index 0061762d046f..092c0c3ffcd4 100644 --- a/packages/jest-snapshot/src/__tests__/utils-test.js +++ b/packages/jest-snapshot/src/__tests__/utils-test.js @@ -16,6 +16,7 @@ const { testNameToKey, SNAPSHOT_GUIDE_LINK, SNAPSHOT_VERSION, + SNAPSHOT_VERSION_WARNING, } = require('../utils'); const fs = require('fs'); const path = require('path'); @@ -89,9 +90,11 @@ test('getSnapshotData() throws when no snapshot version', () => { const update = false; expect(() => getSnapshotData(filename, update)).toThrowError( - `Stored snapshot version is outdated.\n` + - `Expected: v${SNAPSHOT_VERSION}, but received: v0\n` + - `Update the snapshot to remove this error.` + `Outdated snapshot: No snapshot header found. ` + + `Jest 19 introduced versioned snapshots to ensure all people on ` + + `a project are using the same version of Jest. ` + + `Please update all snapshots during this upgrade of Jest.\n\n` + + SNAPSHOT_VERSION_WARNING ); }); @@ -104,9 +107,32 @@ test('getSnapshotData() throws for older snapshot version', () => { const update = false; expect(() => getSnapshotData(filename, update)).toThrowError( - `Stored snapshot version is outdated.\n` + - `Expected: v${SNAPSHOT_VERSION}, but received: v0.99\n` + - `Update the snapshot to remove this error.` + `Outdated snapshot: The version of the snapshot file associated ` + + `with this test is outdated. The snapshot file version ensures that ` + + `all people on a project are using the same version of Jest. ` + + `Please update all snapshots during this upgrade of Jest.\n\n` + + `Expected: v${SNAPSHOT_VERSION}\n` + + `Received: v0.99\n\n` + + SNAPSHOT_VERSION_WARNING + ); +}); + +test('getSnapshotData() throws for newer snapshot version', () => { + const filename = path.join(__dirname, 'old-snapshot.snap'); + fs.readFileSync = jest.fn(() => + `// Jest Snapshot v2, ${SNAPSHOT_GUIDE_LINK}\n\n` + + 'exports[`myKey`] = `
\n
`;\n' + ); + const update = false; + + expect(() => getSnapshotData(filename, update)).toThrowError( + `Outdated Jest version: the version of this snapshot file indicates ` + + `that this project is meant to be used with a newer version of Jest. ` + + `The snapshot file version ensures that all people on a project ` + + `are using the same version of Jest. ` + + `Please update your version of Jest and re-run the tests.` + + `Expected: v${SNAPSHOT_VERSION}\n` + + `Received: v2` ); }); diff --git a/packages/jest-snapshot/src/utils.js b/packages/jest-snapshot/src/utils.js index a4ea9aea80bc..e15b7cf8a9b7 100644 --- a/packages/jest-snapshot/src/utils.js +++ b/packages/jest-snapshot/src/utils.js @@ -24,19 +24,49 @@ const SNAPSHOT_EXTENSION = 'snap'; const SNAPSHOT_VERSION = '1'; const SNAPSHOT_VERSION_REGEXP = /^\/\/ Jest Snapshot v(.+),/; const SNAPSHOT_GUIDE_LINK = 'https://goo.gl/fbAQLP'; +const SNAPSHOT_VERSION_WARNING = + `Warning: It is advised to revert any local changes to tests or ` + + `other code during this upgrade to ensure that no invalid state ` + + `is stored as a snapshot.`; const writeSnapshotVersion = () => `// Jest Snapshot v${SNAPSHOT_VERSION}, ${SNAPSHOT_GUIDE_LINK}`; const validateSnapshotVersion = (snapshotContents: string) => { const versionTest = SNAPSHOT_VERSION_REGEXP.exec(snapshotContents); - const version = (versionTest && versionTest[1]) || '0'; + const version = (versionTest && versionTest[1]); + + if (!version) { + throw new Error( + `Outdated snapshot: No snapshot header found. ` + + `Jest 19 introduced versioned snapshots to ensure all people on ` + + `a project are using the same version of Jest. ` + + `Please update all snapshots during this upgrade of Jest.\n\n` + + SNAPSHOT_VERSION_WARNING + ); + } if (version < SNAPSHOT_VERSION) { throw new Error( - `Stored snapshot version is outdated.\n` + - `Expected: v${SNAPSHOT_VERSION}, but received: v${version}\n` + - `Update the snapshot to remove this error.` + `Outdated snapshot: The version of the snapshot file associated ` + + `with this test is outdated. The snapshot file version ensures that ` + + `all people on a project are using the same version of Jest. ` + + `Please update all snapshots during this upgrade of Jest.\n\n` + + `Expected: v${SNAPSHOT_VERSION}\n` + + `Received: v${version}\n\n` + + SNAPSHOT_VERSION_WARNING + ); + } + + if (version > SNAPSHOT_VERSION) { + throw new Error( + `Outdated Jest version: the version of this snapshot file indicates ` + + `that this project is meant to be used with a newer version of Jest. ` + + `The snapshot file version ensures that all people on a project ` + + `are using the same version of Jest. ` + + `Please update your version of Jest and re-run the tests.` + + `Expected: v${SNAPSHOT_VERSION}\n` + + `Received: v${version}` ); } }; @@ -126,6 +156,7 @@ module.exports = { SNAPSHOT_EXTENSION, SNAPSHOT_GUIDE_LINK, SNAPSHOT_VERSION, + SNAPSHOT_VERSION_WARNING, ensureDirectoryExists, getSnapshotData, getSnapshotPath, From 263fd383e59aeec527a571a07fd1574fafec886c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Pierzcha=C5=82a?= Date: Thu, 16 Feb 2017 00:01:43 +0100 Subject: [PATCH 8/9] Fix error formatting --- packages/jest-snapshot/src/__tests__/utils-test.js | 2 +- packages/jest-snapshot/src/utils.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/jest-snapshot/src/__tests__/utils-test.js b/packages/jest-snapshot/src/__tests__/utils-test.js index 092c0c3ffcd4..2996e798f761 100644 --- a/packages/jest-snapshot/src/__tests__/utils-test.js +++ b/packages/jest-snapshot/src/__tests__/utils-test.js @@ -130,7 +130,7 @@ test('getSnapshotData() throws for newer snapshot version', () => { `that this project is meant to be used with a newer version of Jest. ` + `The snapshot file version ensures that all people on a project ` + `are using the same version of Jest. ` + - `Please update your version of Jest and re-run the tests.` + + `Please update your version of Jest and re-run the tests.\n\n` + `Expected: v${SNAPSHOT_VERSION}\n` + `Received: v2` ); diff --git a/packages/jest-snapshot/src/utils.js b/packages/jest-snapshot/src/utils.js index e15b7cf8a9b7..7ab00e4020c4 100644 --- a/packages/jest-snapshot/src/utils.js +++ b/packages/jest-snapshot/src/utils.js @@ -64,7 +64,7 @@ const validateSnapshotVersion = (snapshotContents: string) => { `that this project is meant to be used with a newer version of Jest. ` + `The snapshot file version ensures that all people on a project ` + `are using the same version of Jest. ` + - `Please update your version of Jest and re-run the tests.` + + `Please update your version of Jest and re-run the tests.\n\n` + `Expected: v${SNAPSHOT_VERSION}\n` + `Received: v${version}` ); From 165e0a6a75b6356aa234b049ea71e6a8598305d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Pierzcha=C5=82a?= Date: Thu, 16 Feb 2017 00:26:15 +0100 Subject: [PATCH 9/9] Don't write to fs if not needed --- packages/jest-snapshot/src/State.js | 7 ++++--- packages/jest-snapshot/src/utils.js | 11 ++++++++++- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/packages/jest-snapshot/src/State.js b/packages/jest-snapshot/src/State.js index ef57a268cfa8..d8d1753cad95 100644 --- a/packages/jest-snapshot/src/State.js +++ b/packages/jest-snapshot/src/State.js @@ -46,9 +46,10 @@ class SnapshotState { snapshotPath?: string, expand?: boolean, ) { - this._dirty = false; this._snapshotPath = snapshotPath || getSnapshotPath(testPath); - this._snapshotData = getSnapshotData(this._snapshotPath, update); + const {data, dirty} = getSnapshotData(this._snapshotPath, update); + this._snapshotData = data; + this._dirty = dirty; this._uncheckedKeys = new Set(Object.keys(this._snapshotData)); this._counters = new Map(); this._index = 0; @@ -83,7 +84,7 @@ class SnapshotState { const isEmpty = Object.keys(this._snapshotData).length === 0; - if ((this._dirty || this._uncheckedKeys.size || update) && !isEmpty) { + if ((this._dirty || this._uncheckedKeys.size) && !isEmpty) { saveSnapshotFile(this._snapshotData, this._snapshotPath); status.saved = true; } else if (isEmpty && fileExists(this._snapshotPath)) { diff --git a/packages/jest-snapshot/src/utils.js b/packages/jest-snapshot/src/utils.js index 7ab00e4020c4..09865ab6c4a2 100644 --- a/packages/jest-snapshot/src/utils.js +++ b/packages/jest-snapshot/src/utils.js @@ -90,6 +90,7 @@ const getSnapshotPath = (testPath: Path) => path.join( const getSnapshotData = (snapshotPath: Path, update: boolean) => { const data = Object.create(null); let snapshotContents; + let dirty = false; if (fileExists(snapshotPath)) { try { @@ -103,7 +104,15 @@ const getSnapshotData = (snapshotPath: Path, update: boolean) => { if (!update && snapshotContents) { validateSnapshotVersion(snapshotContents); } - return data; + + if (update && snapshotContents) { + try { + validateSnapshotVersion(snapshotContents); + } catch (error) { + dirty = true; + } + } + return {data, dirty}; }; // Extra line breaks at the beginning and at the end of the snapshot are useful