Skip to content

Commit 5545730

Browse files
authored
jest-snapshot: Distinguish empty string from internal snapshot not written (#8898)
* jest-snapshot: Distinguish empty string from internal snapshot not written * Update CHANGELOG.md
1 parent 4482e71 commit 5545730

File tree

4 files changed

+83
-9
lines changed

4 files changed

+83
-9
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
- `[jest-mock]` Fix for mockReturnValue overriding mockImplementationOnce ([#8398](https://github.com/facebook/jest/pull/8398))
2020
- `[jest-snapshot]` Remove only the added newlines in multiline snapshots ([#8859](https://github.com/facebook/jest/pull/8859))
2121
- `[jest-snapshot]` Distinguish empty string from external snapshot not written ([#8880](https://github.com/facebook/jest/pull/8880))
22+
- `[jest-snapshot]` [**BREAKING**] Distinguish empty string from internal snapshot not written ([#8898](https://github.com/facebook/jest/pull/8898))
2223

2324
### Chore & Maintenance
2425

e2e/__tests__/toMatchSnapshotWithStringSerializer.test.ts

Lines changed: 65 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
* LICENSE file in the root directory of this source tree.
66
*/
77

8+
import * as fs from 'fs';
89
import * as path from 'path';
910
import {cleanup, makeTemplate, writeFiles} from '../Utils';
1011
import runJest from '../runJest';
@@ -15,9 +16,18 @@ const DIR = path.resolve(
1516
);
1617
const TESTS_DIR = path.resolve(DIR, '__tests__');
1718

19+
const readFile = filename =>
20+
fs.readFileSync(path.join(TESTS_DIR, filename), 'utf8');
21+
1822
beforeEach(() => cleanup(TESTS_DIR));
1923
afterAll(() => cleanup(TESTS_DIR));
2024

25+
// Because the not written error might include Received,
26+
// match Snapshot as either diff annotation or concise label.
27+
const ORDINARY_FAILURE = /- Snapshot|Snapshot:/;
28+
29+
const NOT_WRITTEN = 'not written'; // new snapshot with --ci option
30+
2131
test('empty external', () => {
2232
// Make sure empty string as expected value of external snapshot
2333
// is not confused with new snapshot not written because of --ci option.
@@ -28,7 +38,7 @@ test('empty external', () => {
2838

2939
{
3040
writeFiles(TESTS_DIR, {
31-
[filename]: template(['""']), // empty string
41+
[filename]: template([`''`]),
3242
});
3343
const {stderr, status} = runJest(DIR, ['-w=1', '--ci=false', filename]);
3444
expect(stderr).toMatch('1 snapshot written from 1 test suite.');
@@ -44,12 +54,64 @@ test('empty external', () => {
4454

4555
{
4656
writeFiles(TESTS_DIR, {
47-
[filename]: template(['"non-empty"']),
57+
[filename]: template([`'non-empty'`]),
4858
});
4959
const {stderr, status} = runJest(DIR, ['-w=1', '--ci=false', filename]);
5060
expect(stderr).toMatch('Snapshots: 1 failed, 1 total');
5161
expect(stderr).not.toMatch('not written'); // not confused with --ci option
52-
expect(stderr).toMatch(/- Snapshot|Snapshot:/); // ordinary report
62+
expect(stderr).toMatch(ORDINARY_FAILURE);
63+
expect(status).toBe(1);
64+
}
65+
});
66+
67+
test('empty internal ci false', () => {
68+
// Make sure empty string as expected value of internal snapshot
69+
// is not confused with absence of snapshot.
70+
const filename = 'empty-internal-ci-false.test.js';
71+
const template = makeTemplate(
72+
`test('string serializer', () => { expect($1).toMatchInlineSnapshot(); })`,
73+
);
74+
75+
const received1 = `''`;
76+
const received2 = `'non-empty'`;
77+
78+
{
79+
writeFiles(TESTS_DIR, {
80+
[filename]: template([received1]),
81+
});
82+
const {stderr, status} = runJest(DIR, ['-w=1', '--ci=false', filename]);
83+
expect(stderr).toMatch('1 snapshot written from 1 test suite.');
84+
expect(status).toBe(0);
85+
}
86+
87+
{
88+
writeFiles(TESTS_DIR, {
89+
[filename]: readFile(filename).replace(received1, received2),
90+
});
91+
const {stderr, status} = runJest(DIR, ['-w=1', '--ci=false', filename]);
92+
expect(stderr).toMatch('Snapshots: 1 failed, 1 total');
93+
expect(stderr).not.toMatch('1 snapshot written from 1 test suite.');
94+
expect(stderr).toMatch(ORDINARY_FAILURE);
95+
expect(status).toBe(1);
96+
}
97+
});
98+
99+
test('undefined internal ci true', () => {
100+
// Make sure absence of internal snapshot
101+
// is not confused with ordinary failure for empty string as expected value.
102+
const filename = 'undefined-internal-ci-true.test.js';
103+
const template = makeTemplate(
104+
`test('explicit update', () => { expect($1).toMatchInlineSnapshot(); })`,
105+
);
106+
107+
{
108+
writeFiles(TESTS_DIR, {
109+
[filename]: template([`'non-empty'`]),
110+
});
111+
const {stderr, status} = runJest(DIR, ['-w=1', '--ci=true', filename]);
112+
expect(stderr).toMatch('Snapshots: 1 failed, 1 total');
113+
expect(stderr).not.toMatch(ORDINARY_FAILURE);
114+
expect(stderr).toMatch(NOT_WRITTEN);
53115
expect(status).toBe(1);
54116
}
55117
});

packages/jest-snapshot/src/State.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ export type SnapshotMatchOptions = {
3232
received: any;
3333
key?: string;
3434
inlineSnapshot?: string;
35+
isInline: boolean;
3536
error?: Error;
3637
};
3738

@@ -180,11 +181,11 @@ export default class SnapshotState {
180181
received,
181182
key,
182183
inlineSnapshot,
184+
isInline,
183185
error,
184186
}: SnapshotMatchOptions): SnapshotReturnOptions {
185187
this._counters.set(testName, (this._counters.get(testName) || 0) + 1);
186188
const count = Number(this._counters.get(testName));
187-
const isInline = inlineSnapshot !== undefined;
188189

189190
if (!key) {
190191
key = testNameToKey(testName, count);
@@ -200,9 +201,7 @@ export default class SnapshotState {
200201
const receivedSerialized = serialize(received);
201202
const expected = isInline ? inlineSnapshot : this._snapshotData[key];
202203
const pass = expected === receivedSerialized;
203-
const hasSnapshot = isInline
204-
? inlineSnapshot !== ''
205-
: this._snapshotData[key] !== undefined;
204+
const hasSnapshot = expected !== undefined;
206205
const snapshotIsPersisted = isInline || fs.existsSync(this._snapshotPath);
207206

208207
if (pass && !isInline) {

packages/jest-snapshot/src/index.ts

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ type MatchSnapshotConfig = {
3636
expectedArgument: string;
3737
hint?: string;
3838
inlineSnapshot?: string;
39+
isInline: boolean;
3940
matcherName: string;
4041
options: MatcherHintOptions;
4142
propertyMatchers?: any;
@@ -204,6 +205,7 @@ const toMatchSnapshot = function(
204205
context: this,
205206
expectedArgument,
206207
hint,
208+
isInline: false,
207209
matcherName,
208210
options,
209211
propertyMatchers,
@@ -249,7 +251,11 @@ const toMatchInlineSnapshot = function(
249251
return _toMatchSnapshot({
250252
context: this,
251253
expectedArgument,
252-
inlineSnapshot: stripAddedIndentation(inlineSnapshot || ''),
254+
inlineSnapshot:
255+
inlineSnapshot !== undefined
256+
? stripAddedIndentation(inlineSnapshot)
257+
: undefined,
258+
isInline: true,
253259
matcherName,
254260
options,
255261
propertyMatchers,
@@ -262,6 +268,7 @@ const _toMatchSnapshot = ({
262268
expectedArgument,
263269
hint,
264270
inlineSnapshot,
271+
isInline,
265272
matcherName,
266273
options,
267274
propertyMatchers,
@@ -331,6 +338,7 @@ const _toMatchSnapshot = ({
331338
const result = snapshotState.match({
332339
error: context.error,
333340
inlineSnapshot,
341+
isInline,
334342
received,
335343
testName: fullTestName,
336344
});
@@ -404,6 +412,7 @@ const toThrowErrorMatchingSnapshot = function(
404412
context: this,
405413
expectedArgument,
406414
hint,
415+
isInline: false,
407416
matcherName,
408417
options,
409418
received,
@@ -431,7 +440,8 @@ const toThrowErrorMatchingInlineSnapshot = function(
431440
{
432441
context: this,
433442
expectedArgument,
434-
inlineSnapshot: inlineSnapshot || '',
443+
inlineSnapshot,
444+
isInline: true,
435445
matcherName,
436446
options,
437447
received,
@@ -445,6 +455,7 @@ const _toThrowErrorMatchingSnapshot = (
445455
context,
446456
expectedArgument,
447457
inlineSnapshot,
458+
isInline,
448459
matcherName,
449460
options,
450461
received,
@@ -488,6 +499,7 @@ const _toThrowErrorMatchingSnapshot = (
488499
expectedArgument,
489500
hint,
490501
inlineSnapshot,
502+
isInline,
491503
matcherName,
492504
options,
493505
received: error.message,

0 commit comments

Comments
 (0)