Skip to content

Commit

Permalink
fix(expect, jest-snapshot): Fix test.failing() not passing with faile…
Browse files Browse the repository at this point in the history
…d snapshots
  • Loading branch information
KhaledElmorsy committed Jul 9, 2023
1 parent 596422e commit 614532b
Show file tree
Hide file tree
Showing 14 changed files with 198 additions and 1 deletion.
31 changes: 31 additions & 0 deletions e2e/__tests__/__snapshots__/testFailingSnapshot.test.js.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`test.failing doesnt update failing snapshots 1`] = `
"// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[\`snapshots not updated 1\`] = \`"1"\`;
exports[\`snapshots not updated 2\`] = \`"1"\`;
"
`;

exports[`test.failing doesnt update failing snapshots 2`] = `
"/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
test.failing('inline snapshot not updated', () => {
// eslint-disable-next-line quotes
expect('0').toMatchInlineSnapshot(\`'1'\`);
});
"
`;
exports[`test.failing should pass when at least one snapshot fails 1`] = `"1"`;
exports[`test.failing should pass when at least one snapshot fails 2`] = `"1"`;
exports[`test.failing should pass when snapshot matchers fails 1`] = `"1"`;
61 changes: 61 additions & 0 deletions e2e/__tests__/testFailingSnapshot.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

import * as path from 'path';
import * as fs from 'graceful-fs';
import runJest from '../runJest';

describe('test.failing', () => {
describe('should pass when', () => {
test.failing('snapshot matchers fails', () => {
expect('0').toMatchSnapshot();
});

test.failing('snapshot doesnt exist', () => {
expect('0').toMatchSnapshot();
});

test.failing('inline snapshot matchers fails', () => {
expect('0').toMatchInlineSnapshot('0');
});

test.failing('at least one snapshot fails', () => {
expect('1').toMatchSnapshot();
expect('0').toMatchSnapshot();
});
});

describe('should fail when', () => {
test.each([
['snapshot', 'snapshot'],
['inline snapshot', 'inlineSnapshot'],
])('%s matchers pass', (_, fileName) => {
const dir = path.resolve(__dirname, '../test-failing-snapshot-all-pass');
const result = runJest(dir, [`./__tests__/${fileName}.test.js`]);
expect(result.exitCode).toBe(1);
});
});

it('doesnt update failing snapshots', () => {
const dir = path.resolve(__dirname, '../test-failing-snapshot');
const result = runJest(dir, ['-u']);
expect(result.exitCode).toBe(0);
expect(result.stdout).not.toMatch(/snapshots? (written|removed|obsolete)/);

const snapshot = fs
.readFileSync(
path.resolve(dir, './__tests__/__snapshots__/snapshot.test.js.snap'),
)
.toString();
expect(snapshot).toMatchSnapshot();

const inlineSnapshot = fs
.readFileSync(path.resolve(dir, './__tests__/inlineSnapshot.test.js'))
.toString();
expect(inlineSnapshot).toMatchSnapshot();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`snapshots not updated 1`] = `"1"`;

exports[`snapshots not updated 2`] = `"1"`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

test.failing('inline snapshot not updated', () => {
// eslint-disable-next-line quotes
expect('1').toMatchInlineSnapshot(`"1"`);
});
11 changes: 11 additions & 0 deletions e2e/test-failing-snapshot-all-pass/__tests__/snapshot.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

test.failing('snapshots not updated', () => {
expect('1').toMatchSnapshot();
expect('1').toMatchSnapshot();
});
5 changes: 5 additions & 0 deletions e2e/test-failing-snapshot-all-pass/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"jest": {
"testEnvironment": "node"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`snapshots not updated 1`] = `"1"`;

exports[`snapshots not updated 2`] = `"1"`;
11 changes: 11 additions & 0 deletions e2e/test-failing-snapshot/__tests__/inlineSnapshot.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

test.failing('inline snapshot not updated', () => {
// eslint-disable-next-line quotes
expect('0').toMatchInlineSnapshot(`'1'`);
});
11 changes: 11 additions & 0 deletions e2e/test-failing-snapshot/__tests__/snapshot.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

test.failing('snapshots not updated', () => {
expect('1').toMatchSnapshot();
expect('0').toMatchSnapshot();
});
5 changes: 5 additions & 0 deletions e2e/test-failing-snapshot/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"jest": {
"testEnvironment": "node"
}
}
2 changes: 2 additions & 0 deletions packages/expect/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
/* eslint-disable local/prefer-spread-eventually */

import {equals, iterableEquality, subsetEquality} from '@jest/expect-utils';
import {getState as getRunnerState} from 'jest-circus';
import * as matcherUtils from 'jest-matcher-utils';
import {isPromise} from 'jest-util';
import {
Expand Down Expand Up @@ -288,6 +289,7 @@ const makeThrowingMatcher = (
// failures in a test.
dontThrow: () => (throws = false),
equals,
runnerState: getRunnerState(),
utils,
};

Expand Down
2 changes: 2 additions & 0 deletions packages/expect/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

import type {AsyncLocalStorage} from 'async_hooks';
import type {EqualsFunction, Tester} from '@jest/expect-utils';
import type {State} from 'jest-circus';
import type * as jestMatcherUtils from 'jest-matcher-utils';
import {INTERNAL_MATCHER_FLAG} from './jestMatchersObject';

Expand Down Expand Up @@ -54,6 +55,7 @@ export interface MatcherUtils {
iterableEquality: Tester;
subsetEquality: Tester;
};
runnerState: State;
}

export interface MatcherState {
Expand Down
19 changes: 19 additions & 0 deletions packages/jest-snapshot/src/State.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ export type SnapshotMatchOptions = {
readonly inlineSnapshot?: string;
readonly isInline: boolean;
readonly error?: Error;
readonly pure?: boolean;
};

type SnapshotReturnOptions = {
Expand Down Expand Up @@ -197,6 +198,7 @@ export default class SnapshotState {
inlineSnapshot,
isInline,
error,
pure = false,
}: SnapshotMatchOptions): SnapshotReturnOptions {
this._counters.set(testName, (this._counters.get(testName) || 0) + 1);
const count = Number(this._counters.get(testName));
Expand Down Expand Up @@ -230,6 +232,23 @@ export default class SnapshotState {
this._snapshotData[key] = receivedSerialized;
}

// In pure runs, return the match result while skipping any side effects
// and special reporting.
if (pure) {
if (hasSnapshot && !isInline) {
// Retain current snapshot values.
this._addSnapshot(key, expected, {error, isInline});
}
return {
actual: removeExtraLineBreaks(receivedSerialized),
count,
expected:
expected !== undefined ? removeExtraLineBreaks(expected) : undefined,
key,
pass,
};
}

// These are the conditions on when to write snapshots:
// * There's no snapshot file in a non-CI environment.
// * There is a snapshot file and we decided to update the snapshot.
Expand Down
20 changes: 19 additions & 1 deletion packages/jest-snapshot/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,24 @@ const _toMatchSnapshot = (config: MatchSnapshotConfig) => {
config;
let {received} = config;

context.dontThrow && context.dontThrow();
/** If a test was ran with `test.failing`. Needs Circus runner. */
const testShouldFail =
context.runnerState?.currentlyRunningTest?.failing ?? false;

/**
* Run the snapshot matcher as a normal throwing matcher with
* no side effects and no error supression.
*
* Skipped side effects occur in {@link snapshotState.match}
* and include updating the snapshot and reporting passed/failed
* snapshots in the snapshot counter.
*/
const pure = testShouldFail;

if (!pure && context.dontThrow) {
// Supress errors while running tests
context.dontThrow();
}

const {currentConcurrentTestName, isNot, snapshotState} = context;
const currentTestName =
Expand Down Expand Up @@ -358,6 +375,7 @@ const _toMatchSnapshot = (config: MatchSnapshotConfig) => {
error: context.error,
inlineSnapshot,
isInline,
pure,
received,
testName: fullTestName,
});
Expand Down

0 comments on commit 614532b

Please sign in to comment.