From 7dfe361ed1a0a08114ba66ac1dcae888fa432bf4 Mon Sep 17 00:00:00 2001 From: Art Date: Tue, 4 Apr 2023 14:18:20 +0700 Subject: [PATCH] add to throw error matching named snapshot with e2e --- .../toThrowErrorMatchingNamedSnapshot.test.ts | 109 ++++++++++++++++++ .../toThrowErrorMatchingSnapshot.test.ts | 5 +- .../package.json | 5 + .../package.json | 5 + packages/expect/src/index.ts | 3 +- packages/jest-expect/src/index.ts | 2 + packages/jest-snapshot/src/index.ts | 30 ++++- packages/jest-snapshot/src/types.ts | 12 +- 8 files changed, 164 insertions(+), 7 deletions(-) create mode 100644 e2e/__tests__/toThrowErrorMatchingNamedSnapshot.test.ts create mode 100644 e2e/to-match-named-snapshot-with-retries/package.json create mode 100644 e2e/to-throw-error-matching-named-snapshot/package.json diff --git a/e2e/__tests__/toThrowErrorMatchingNamedSnapshot.test.ts b/e2e/__tests__/toThrowErrorMatchingNamedSnapshot.test.ts new file mode 100644 index 000000000000..d3ea510df58b --- /dev/null +++ b/e2e/__tests__/toThrowErrorMatchingNamedSnapshot.test.ts @@ -0,0 +1,109 @@ +/** + * 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 {cleanup, makeTemplate, writeFiles} from '../Utils'; +import runJest from '../runJest'; + +const DIR = path.resolve( + __dirname, + '../to-throw-error-matching-named-snapshot', +); +const TESTS_DIR = path.resolve(DIR, '__tests__'); + +beforeEach(() => cleanup(TESTS_DIR)); +afterAll(() => cleanup(TESTS_DIR)); + +test('works fine when function throws error', () => { + const filename = 'works-fine-when-function-throws-error.test.js'; + const template = + makeTemplate(`test('works fine when function throws error', () => { + expect(() => { throw new Error('apple'); }) + .toThrowErrorMatchingNamedSnapshot('works-fine'); + }); + `); + + { + writeFiles(TESTS_DIR, {[filename]: template()}); + const {stderr, exitCode} = runJest(DIR, ['-w=1', '--ci=false', filename]); + expect(stderr).toMatch('1 snapshot written from 1 test suite.'); + expect(exitCode).toBe(0); + } +}); + +test("throws the error if tested function didn't throw error", () => { + const filename = 'throws-if-tested-function-did-not-throw.test.js'; + const template = + makeTemplate(`test('throws the error if tested function did not throw error', () => { + expect(() => {}).toThrowErrorMatchingNamedSnapshot('error if did not throw error'); + }); + `); + + { + writeFiles(TESTS_DIR, {[filename]: template()}); + const {stderr, exitCode} = runJest(DIR, ['-w=1', '--ci=false', filename]); + expect(stderr).toMatch('Received function did not throw'); + expect(exitCode).toBe(1); + } +}); + +test('accepts custom snapshot name', () => { + const filename = 'accept-custom-snapshot-name.test.js'; + const template = makeTemplate(`test('accepts custom snapshot name', () => { + expect(() => { throw new Error('apple'); }) + .toThrowErrorMatchingNamedSnapshot('custom-name'); + }); + `); + + { + writeFiles(TESTS_DIR, {[filename]: template()}); + const {stderr, exitCode} = runJest(DIR, ['-w=1', '--ci=false', filename]); + expect(stderr).toMatch('1 snapshot written from 1 test suite.'); + expect(exitCode).toBe(0); + } +}); + +test('cannot be used with .not', () => { + const filename = 'cannot-be-used-with-not.test.js'; + const template = makeTemplate(`test('cannot be used with .not', () => { + expect(() => { throw new Error('apple'); }) + .not + .toThrowErrorMatchingNamedSnapshot('cannot-used-with-not'); + }); + `); + + { + writeFiles(TESTS_DIR, {[filename]: template()}); + const {stderr, exitCode} = runJest(DIR, ['-w=1', '--ci=false', filename]); + expect(stderr).toMatch('Snapshot matchers cannot be used with not'); + expect(exitCode).toBe(1); + } +}); + +test('should support rejecting promises', () => { + const filename = 'should-support-rejecting-promises.test.js'; + const template = + makeTemplate(`test('should support rejecting promises', () => { + return expect(Promise.reject(new Error('octopus'))).rejects.toThrowErrorMatchingNamedSnapshot('support-reject'); + }); + `); + + { + writeFiles(TESTS_DIR, {[filename]: template()}); + const {stderr, exitCode} = runJest(DIR, ['-w=1', '--ci=false', filename]); + + const snapshot = fs.readFileSync( + `${TESTS_DIR}/__snapshots__/${filename}.snap`, + 'utf8', + ); + + expect(stderr).toMatch('1 snapshot written from 1 test suite.'); + expect(snapshot).toMatchNamedSnapshot('support-reject'); + expect(exitCode).toBe(0); + } +}); diff --git a/e2e/__tests__/toThrowErrorMatchingSnapshot.test.ts b/e2e/__tests__/toThrowErrorMatchingSnapshot.test.ts index 0137be8037a5..e02e394919a6 100644 --- a/e2e/__tests__/toThrowErrorMatchingSnapshot.test.ts +++ b/e2e/__tests__/toThrowErrorMatchingSnapshot.test.ts @@ -49,11 +49,11 @@ test("throws the error if tested function didn't throw error", () => { } }); -test('accepts custom snapshot name', () => { +test('accepts custom snapshot hint', () => { const filename = 'accept-custom-snapshot-name.test.js'; const template = makeTemplate(`test('accepts custom snapshot name', () => { expect(() => { throw new Error('apple'); }) - .toThrowErrorMatchingSnapshot('custom-name'); + .toThrowErrorMatchingSnapshot('custom-hint'); }); `); @@ -93,6 +93,7 @@ test('should support rejecting promises', () => { { writeFiles(TESTS_DIR, {[filename]: template()}); const {stderr, exitCode} = runJest(DIR, ['-w=1', '--ci=false', filename]); + console.log(stderr); const snapshot = fs.readFileSync( `${TESTS_DIR}/__snapshots__/${filename}.snap`, diff --git a/e2e/to-match-named-snapshot-with-retries/package.json b/e2e/to-match-named-snapshot-with-retries/package.json new file mode 100644 index 000000000000..148788b25446 --- /dev/null +++ b/e2e/to-match-named-snapshot-with-retries/package.json @@ -0,0 +1,5 @@ +{ + "jest": { + "testEnvironment": "node" + } +} diff --git a/e2e/to-throw-error-matching-named-snapshot/package.json b/e2e/to-throw-error-matching-named-snapshot/package.json new file mode 100644 index 000000000000..148788b25446 --- /dev/null +++ b/e2e/to-throw-error-matching-named-snapshot/package.json @@ -0,0 +1,5 @@ +{ + "jest": { + "testEnvironment": "node" + } +} diff --git a/packages/expect/src/index.ts b/packages/expect/src/index.ts index 5cc2cd68f6c3..eda221ff209b 100644 --- a/packages/expect/src/index.ts +++ b/packages/expect/src/index.ts @@ -91,7 +91,8 @@ const getPromiseMatcher = (name: string, matcher: RawMatcherFn) => { return createThrowMatcher(name, true); } else if ( name === 'toThrowErrorMatchingSnapshot' || - name === 'toThrowErrorMatchingInlineSnapshot' + name === 'toThrowErrorMatchingInlineSnapshot' || + name === 'toThrowErrorMatchingNamedSnapshot' ) { return createToThrowErrorMatchingSnapshotMatcher(matcher); } diff --git a/packages/jest-expect/src/index.ts b/packages/jest-expect/src/index.ts index a5324c3804fb..bac4d4c5c37d 100644 --- a/packages/jest-expect/src/index.ts +++ b/packages/jest-expect/src/index.ts @@ -12,6 +12,7 @@ import { toMatchNamedSnapshot, toMatchSnapshot, toThrowErrorMatchingInlineSnapshot, + toThrowErrorMatchingNamedSnapshot, toThrowErrorMatchingSnapshot, } from 'jest-snapshot'; import type {JestExpect} from './types'; @@ -33,6 +34,7 @@ function createJestExpect(): JestExpect { toMatchNamedSnapshot, toMatchSnapshot, toThrowErrorMatchingInlineSnapshot, + toThrowErrorMatchingNamedSnapshot, toThrowErrorMatchingSnapshot, }); diff --git a/packages/jest-snapshot/src/index.ts b/packages/jest-snapshot/src/index.ts index 02ae771fff17..08932443ad5f 100644 --- a/packages/jest-snapshot/src/index.ts +++ b/packages/jest-snapshot/src/index.ts @@ -546,12 +546,37 @@ export const toThrowErrorMatchingInlineSnapshot: MatcherFunctionWithContext< ); }; +export const toThrowErrorMatchingNamedSnapshot: MatcherFunctionWithContext< + Context, + [snapshotName?: string, fromPromise?: boolean] +> = function (received, snapshotName, fromPromise) { + const matcherName = 'toThrowErrorMatchingNamedSnapshot'; + + return _toThrowErrorMatchingSnapshot( + { + context: this, + isInline: false, + matcherName, + received, + snapshotName, + }, + fromPromise, + ); +}; + const _toThrowErrorMatchingSnapshot = ( config: MatchSnapshotConfig, fromPromise?: boolean, ) => { - const {context, hint, inlineSnapshot, isInline, matcherName, received} = - config; + const { + context, + hint, + inlineSnapshot, + isInline, + matcherName, + snapshotName, + received, + } = config; context.dontThrow && context.dontThrow(); @@ -606,5 +631,6 @@ const _toThrowErrorMatchingSnapshot = ( isInline, matcherName, received: error.message, + snapshotName, }); }; diff --git a/packages/jest-snapshot/src/types.ts b/packages/jest-snapshot/src/types.ts index 2cab7378d9d5..69ccae322464 100644 --- a/packages/jest-snapshot/src/types.ts +++ b/packages/jest-snapshot/src/types.ts @@ -55,7 +55,8 @@ export interface SnapshotMatchers, T> { hint?: string, ): R; /** - * This ensures that a value matches the most recent snapshot. + * This ensures that a value matches the specific snapshot. + * Instead of use current test name in global state, it will use the specific name to find the snapshot. * Check out [the Snapshot Testing guide](https://jestjs.io/docs/snapshot-testing) for more information. */ toMatchNamedSnapshot>( @@ -63,7 +64,8 @@ export interface SnapshotMatchers, T> { snapshot?: string, ): R; /** - * This ensures that a value matches the most recent snapshot. + * This ensures that a value matches the specific snapshot. + * Instead of use current test name in global state, it will use the specific name to find the snapshot. * Check out [the Snapshot Testing guide](https://jestjs.io/docs/snapshot-testing) for more information. */ toMatchNamedSnapshot(snapshotName?: string): R; @@ -91,6 +93,12 @@ export interface SnapshotMatchers, T> { * Instead of writing the snapshot value to a .snap file, it will be written into the source code automatically. */ toThrowErrorMatchingInlineSnapshot(snapshot?: string): R; + + /** + * Used to test that a function throws a error matching the specific snapshot. + * Instead of use current test name in global state, it will use the specific name to find the snapshot. + */ + toThrowErrorMatchingNamedSnapshot(name?: string): R; } export type SnapshotFormat = Omit;