Skip to content

Commit

Permalink
jest-snapshot: Distinguish empty string from internal snapshot not wr…
Browse files Browse the repository at this point in the history
…itten (#8898)

* jest-snapshot: Distinguish empty string from internal snapshot not written

* Update CHANGELOG.md
  • Loading branch information
pedrottimark authored Sep 1, 2019
1 parent 4482e71 commit 5545730
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 9 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
- `[jest-mock]` Fix for mockReturnValue overriding mockImplementationOnce ([#8398](https://github.com/facebook/jest/pull/8398))
- `[jest-snapshot]` Remove only the added newlines in multiline snapshots ([#8859](https://github.com/facebook/jest/pull/8859))
- `[jest-snapshot]` Distinguish empty string from external snapshot not written ([#8880](https://github.com/facebook/jest/pull/8880))
- `[jest-snapshot]` [**BREAKING**] Distinguish empty string from internal snapshot not written ([#8898](https://github.com/facebook/jest/pull/8898))

### Chore & Maintenance

Expand Down
68 changes: 65 additions & 3 deletions e2e/__tests__/toMatchSnapshotWithStringSerializer.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
* LICENSE file in the root directory of this source tree.
*/

import * as fs from 'fs';
import * as path from 'path';
import {cleanup, makeTemplate, writeFiles} from '../Utils';
import runJest from '../runJest';
Expand All @@ -15,9 +16,18 @@ const DIR = path.resolve(
);
const TESTS_DIR = path.resolve(DIR, '__tests__');

const readFile = filename =>
fs.readFileSync(path.join(TESTS_DIR, filename), 'utf8');

beforeEach(() => cleanup(TESTS_DIR));
afterAll(() => cleanup(TESTS_DIR));

// Because the not written error might include Received,
// match Snapshot as either diff annotation or concise label.
const ORDINARY_FAILURE = /- Snapshot|Snapshot:/;

const NOT_WRITTEN = 'not written'; // new snapshot with --ci option

test('empty external', () => {
// Make sure empty string as expected value of external snapshot
// is not confused with new snapshot not written because of --ci option.
Expand All @@ -28,7 +38,7 @@ test('empty external', () => {

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

{
writeFiles(TESTS_DIR, {
[filename]: template(['"non-empty"']),
[filename]: template([`'non-empty'`]),
});
const {stderr, status} = runJest(DIR, ['-w=1', '--ci=false', filename]);
expect(stderr).toMatch('Snapshots: 1 failed, 1 total');
expect(stderr).not.toMatch('not written'); // not confused with --ci option
expect(stderr).toMatch(/- Snapshot|Snapshot:/); // ordinary report
expect(stderr).toMatch(ORDINARY_FAILURE);
expect(status).toBe(1);
}
});

test('empty internal ci false', () => {
// Make sure empty string as expected value of internal snapshot
// is not confused with absence of snapshot.
const filename = 'empty-internal-ci-false.test.js';
const template = makeTemplate(
`test('string serializer', () => { expect($1).toMatchInlineSnapshot(); })`,
);

const received1 = `''`;
const received2 = `'non-empty'`;

{
writeFiles(TESTS_DIR, {
[filename]: template([received1]),
});
const {stderr, status} = runJest(DIR, ['-w=1', '--ci=false', filename]);
expect(stderr).toMatch('1 snapshot written from 1 test suite.');
expect(status).toBe(0);
}

{
writeFiles(TESTS_DIR, {
[filename]: readFile(filename).replace(received1, received2),
});
const {stderr, status} = runJest(DIR, ['-w=1', '--ci=false', filename]);
expect(stderr).toMatch('Snapshots: 1 failed, 1 total');
expect(stderr).not.toMatch('1 snapshot written from 1 test suite.');
expect(stderr).toMatch(ORDINARY_FAILURE);
expect(status).toBe(1);
}
});

test('undefined internal ci true', () => {
// Make sure absence of internal snapshot
// is not confused with ordinary failure for empty string as expected value.
const filename = 'undefined-internal-ci-true.test.js';
const template = makeTemplate(
`test('explicit update', () => { expect($1).toMatchInlineSnapshot(); })`,
);

{
writeFiles(TESTS_DIR, {
[filename]: template([`'non-empty'`]),
});
const {stderr, status} = runJest(DIR, ['-w=1', '--ci=true', filename]);
expect(stderr).toMatch('Snapshots: 1 failed, 1 total');
expect(stderr).not.toMatch(ORDINARY_FAILURE);
expect(stderr).toMatch(NOT_WRITTEN);
expect(status).toBe(1);
}
});
7 changes: 3 additions & 4 deletions packages/jest-snapshot/src/State.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ export type SnapshotMatchOptions = {
received: any;
key?: string;
inlineSnapshot?: string;
isInline: boolean;
error?: Error;
};

Expand Down Expand Up @@ -180,11 +181,11 @@ export default class SnapshotState {
received,
key,
inlineSnapshot,
isInline,
error,
}: SnapshotMatchOptions): SnapshotReturnOptions {
this._counters.set(testName, (this._counters.get(testName) || 0) + 1);
const count = Number(this._counters.get(testName));
const isInline = inlineSnapshot !== undefined;

if (!key) {
key = testNameToKey(testName, count);
Expand All @@ -200,9 +201,7 @@ export default class SnapshotState {
const receivedSerialized = serialize(received);
const expected = isInline ? inlineSnapshot : this._snapshotData[key];
const pass = expected === receivedSerialized;
const hasSnapshot = isInline
? inlineSnapshot !== ''
: this._snapshotData[key] !== undefined;
const hasSnapshot = expected !== undefined;
const snapshotIsPersisted = isInline || fs.existsSync(this._snapshotPath);

if (pass && !isInline) {
Expand Down
16 changes: 14 additions & 2 deletions packages/jest-snapshot/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ type MatchSnapshotConfig = {
expectedArgument: string;
hint?: string;
inlineSnapshot?: string;
isInline: boolean;
matcherName: string;
options: MatcherHintOptions;
propertyMatchers?: any;
Expand Down Expand Up @@ -204,6 +205,7 @@ const toMatchSnapshot = function(
context: this,
expectedArgument,
hint,
isInline: false,
matcherName,
options,
propertyMatchers,
Expand Down Expand Up @@ -249,7 +251,11 @@ const toMatchInlineSnapshot = function(
return _toMatchSnapshot({
context: this,
expectedArgument,
inlineSnapshot: stripAddedIndentation(inlineSnapshot || ''),
inlineSnapshot:
inlineSnapshot !== undefined
? stripAddedIndentation(inlineSnapshot)
: undefined,
isInline: true,
matcherName,
options,
propertyMatchers,
Expand All @@ -262,6 +268,7 @@ const _toMatchSnapshot = ({
expectedArgument,
hint,
inlineSnapshot,
isInline,
matcherName,
options,
propertyMatchers,
Expand Down Expand Up @@ -331,6 +338,7 @@ const _toMatchSnapshot = ({
const result = snapshotState.match({
error: context.error,
inlineSnapshot,
isInline,
received,
testName: fullTestName,
});
Expand Down Expand Up @@ -404,6 +412,7 @@ const toThrowErrorMatchingSnapshot = function(
context: this,
expectedArgument,
hint,
isInline: false,
matcherName,
options,
received,
Expand Down Expand Up @@ -431,7 +440,8 @@ const toThrowErrorMatchingInlineSnapshot = function(
{
context: this,
expectedArgument,
inlineSnapshot: inlineSnapshot || '',
inlineSnapshot,
isInline: true,
matcherName,
options,
received,
Expand All @@ -445,6 +455,7 @@ const _toThrowErrorMatchingSnapshot = (
context,
expectedArgument,
inlineSnapshot,
isInline,
matcherName,
options,
received,
Expand Down Expand Up @@ -488,6 +499,7 @@ const _toThrowErrorMatchingSnapshot = (
expectedArgument,
hint,
inlineSnapshot,
isInline,
matcherName,
options,
received: error.message,
Expand Down

0 comments on commit 5545730

Please sign in to comment.