From 6ccd1dccd93bb043d90788baca9848d1a4be921c Mon Sep 17 00:00:00 2001 From: mrazauskas <72159681+mrazauskas@users.noreply.github.com> Date: Wed, 16 Feb 2022 10:41:18 +0200 Subject: [PATCH 01/20] introduce @jest/expect --- packages/expect/__typetests__/expect.test.ts | 3 +- packages/expect/src/asymmetricMatchers.ts | 10 +-- packages/expect/src/index.ts | 7 +- packages/expect/src/jestMatchersObject.ts | 12 ++- packages/expect/src/types.ts | 88 +++++------------- packages/jest-circus/package.json | 1 + .../jestAdapterInit.ts | 20 ++--- packages/jest-circus/tsconfig.json | 1 + packages/jest-expect/.npmignore | 5 ++ packages/jest-expect/package.json | 30 +++++++ .../src/index.ts} | 19 ++-- packages/jest-expect/src/types.ts | 89 +++++++++++++++++++ packages/jest-expect/tsconfig.json | 14 +++ packages/jest-globals/package.json | 4 +- packages/jest-globals/src/index.ts | 4 +- packages/jest-globals/tsconfig.json | 2 +- packages/jest-jasmine2/src/jestExpect.ts | 1 + .../jest-jasmine2/src/setup_jest_globals.ts | 2 +- yarn.lock | 12 +++ 19 files changed, 213 insertions(+), 111 deletions(-) create mode 100644 packages/jest-expect/.npmignore create mode 100644 packages/jest-expect/package.json rename packages/{jest-circus/src/legacy-code-todo-rewrite/jestExpect.ts => jest-expect/src/index.ts} (60%) create mode 100644 packages/jest-expect/src/types.ts create mode 100644 packages/jest-expect/tsconfig.json diff --git a/packages/expect/__typetests__/expect.test.ts b/packages/expect/__typetests__/expect.test.ts index 6f5d73bcced0..6b90bc9b9d93 100644 --- a/packages/expect/__typetests__/expect.test.ts +++ b/packages/expect/__typetests__/expect.test.ts @@ -16,8 +16,7 @@ import { } from 'expect'; import type * as jestMatcherUtils from 'jest-matcher-utils'; -type M = Matchers; -type N = Matchers; +type M = Matchers; expectError(() => { type E = Matchers; diff --git a/packages/expect/src/asymmetricMatchers.ts b/packages/expect/src/asymmetricMatchers.ts index fc8e043be269..874925b9fb97 100644 --- a/packages/expect/src/asymmetricMatchers.ts +++ b/packages/expect/src/asymmetricMatchers.ts @@ -62,22 +62,20 @@ export function hasProperty(obj: object | null, property: string): boolean { return hasProperty(getPrototype(obj), property); } -export abstract class AsymmetricMatcher< - T, - State extends MatcherState = MatcherState, -> implements AsymmetricMatcherInterface +export abstract class AsymmetricMatcher + implements AsymmetricMatcherInterface { $$typeof = Symbol.for('jest.asymmetricMatcher'); constructor(protected sample: T, protected inverse = false) {} - protected getMatcherContext(): State { + protected getMatcherContext(): MatcherState { return { ...getState(), equals, isNot: this.inverse, utils, - } as State; + }; } abstract asymmetricMatch(other: unknown): boolean; diff --git a/packages/expect/src/index.ts b/packages/expect/src/index.ts index 855339906134..a85fe7c4c297 100644 --- a/packages/expect/src/index.ts +++ b/packages/expect/src/index.ts @@ -51,6 +51,7 @@ import type { export type { AsymmetricMatchers, + BaseExpect, Expect, MatcherFunction, MatcherFunctionWithState, @@ -363,9 +364,8 @@ const makeThrowingMatcher = ( } }; -expect.extend = ( - matchers: MatchersObject, -) => setMatchers(matchers, false, expect); +expect.extend = (matchers: MatchersObject) => + setMatchers(matchers, false, expect); expect.anything = anything; expect.any = any; @@ -431,7 +431,6 @@ setMatchers(matchers, true, expect); setMatchers(spyMatchers, true, expect); setMatchers(toThrowMatchers, true, expect); -expect.addSnapshotSerializer = () => void 0; expect.assertions = assertions; expect.hasAssertions = hasAssertions; expect.getState = getState; diff --git a/packages/expect/src/jestMatchersObject.ts b/packages/expect/src/jestMatchersObject.ts index 544530bbe398..758909b40909 100644 --- a/packages/expect/src/jestMatchersObject.ts +++ b/packages/expect/src/jestMatchersObject.ts @@ -46,12 +46,11 @@ export const setState = ( Object.assign((global as any)[JEST_MATCHERS_OBJECT].state, state); }; -export const getMatchers = < - State extends MatcherState = MatcherState, ->(): MatchersObject => (global as any)[JEST_MATCHERS_OBJECT].matchers; +export const getMatchers = (): MatchersObject => + (global as any)[JEST_MATCHERS_OBJECT].matchers; -export const setMatchers = ( - matchers: MatchersObject, +export const setMatchers = ( + matchers: MatchersObject, isInternal: boolean, expect: Expect, ): void => { @@ -65,8 +64,7 @@ export const setMatchers = ( // expect is defined class CustomMatcher extends AsymmetricMatcher< - [unknown, ...Array], - State + [unknown, ...Array] > { constructor(inverse = false, ...sample: [unknown, ...Array]) { super(sample, inverse); diff --git a/packages/expect/src/types.ts b/packages/expect/src/types.ts index 94a03e70f127..0cc4a79114ec 100644 --- a/packages/expect/src/types.ts +++ b/packages/expect/src/types.ts @@ -35,8 +35,8 @@ export type RawMatcherFn = { [INTERNAL_MATCHER_FLAG]?: boolean; }; -export type MatchersObject = { - [name: string]: RawMatcherFn; +export type MatchersObject = { + [name: string]: RawMatcherFn; }; export type ThrowingMatcherFn = (actual: any) => void; @@ -76,27 +76,28 @@ export type ExpectedAssertionsErrors = Array<{ expected: string; }>; -export type Expect = { - (actual: T): Matchers & - InverseMatchers & - PromiseMatchers; - // TODO: this is added by test runners, not `expect` itself - addSnapshotSerializer(serializer: unknown): void; +export type BaseExpect = { assertions(numberOfAssertions: number): void; - // TODO: remove this `T extends` - should get from some interface merging - extend(matchers: MatchersObject): void; + extend(matchers: MatchersObject): void; extractExpectedAssertionsErrors(): ExpectedAssertionsErrors; - getState(): State; + getState(): MatcherState; hasAssertions(): void; - setState(state: Partial): void; -} & AsymmetricMatchers & - InverseAsymmetricMatchers; + setState(state: Partial): void; +}; + +export type Expect = { + (actual: T): Matchers & + Inverse> & + PromiseMatchers; +} & BaseExpect & + AsymmetricMatchers & + Inverse>; -type InverseAsymmetricMatchers = { +type Inverse = { /** * Inverse next matcher. If you know how to test something, `.not` lets you test its opposite. */ - not: Omit; + not: Matchers; }; export interface AsymmetricMatchers { @@ -109,28 +110,21 @@ export interface AsymmetricMatchers { stringMatching(sample: string | RegExp): AsymmetricMatcher; } -type PromiseMatchers = { +type PromiseMatchers = { /** * Unwraps the reason of a rejected promise so any other matcher can be chained. * If the promise is fulfilled the assertion fails. */ - rejects: Matchers, T> & InverseMatchers, T>; + rejects: Matchers> & Inverse>>; /** * Unwraps the value of a fulfilled promise so any other matcher can be chained. * If the promise is rejected the assertion fails. */ - resolves: Matchers, T> & InverseMatchers, T>; -}; - -type InverseMatchers, T = unknown> = { - /** - * Inverse next matcher. If you know how to test something, `.not` lets you test its opposite. - */ - not: Matchers; + resolves: Matchers> & Inverse>>; }; // This is a copy from https://github.com/DefinitelyTyped/DefinitelyTyped/blob/de6730f4463cba69904698035fafd906a72b9664/types/jest/index.d.ts#L570-L817 -export interface Matchers, T = unknown> { +export interface Matchers> { /** * Ensures the last call to a mock function was provided specific args. */ @@ -340,44 +334,4 @@ export interface Matchers, T = unknown> { * If you want to test that a specific error is thrown inside a function. */ toThrowError(expected?: unknown): R; - - /* TODO: START snapshot matchers are not from `expect`, the types should not be here */ - /** - * This ensures that a value matches the most recent snapshot with property matchers. - * Check out [the Snapshot Testing guide](https://jestjs.io/docs/snapshot-testing) for more information. - */ - toMatchSnapshot(hint?: string): R; - /** - * This ensures that a value matches the most recent snapshot. - * Check out [the Snapshot Testing guide](https://jestjs.io/docs/snapshot-testing) for more information. - */ - toMatchSnapshot>( - propertyMatchers: Partial, - hint?: string, - ): R; - /** - * This ensures that a value matches the most recent snapshot with property matchers. - * Instead of writing the snapshot value to a .snap file, it will be written into the source code automatically. - * Check out [the Snapshot Testing guide](https://jestjs.io/docs/snapshot-testing) for more information. - */ - toMatchInlineSnapshot(snapshot?: string): R; - /** - * This ensures that a value matches the most recent snapshot with property matchers. - * Instead of writing the snapshot value to a .snap file, it will be written into the source code automatically. - * Check out [the Snapshot Testing guide](https://jestjs.io/docs/snapshot-testing) for more information. - */ - toMatchInlineSnapshot>( - propertyMatchers: Partial, - snapshot?: string, - ): R; - /** - * Used to test that a function throws a error matching the most recent snapshot when it is called. - */ - toThrowErrorMatchingSnapshot(hint?: string): R; - /** - * Used to test that a function throws a error matching the most recent snapshot when it is called. - * Instead of writing the snapshot value to a .snap file, it will be written into the source code automatically. - */ - toThrowErrorMatchingInlineSnapshot(snapshot?: string): R; - /* TODO: END snapshot matchers are not from `expect`, the types should not be here */ } diff --git a/packages/jest-circus/package.json b/packages/jest-circus/package.json index 3f5d8c933a21..d4b2a9d1eb4e 100644 --- a/packages/jest-circus/package.json +++ b/packages/jest-circus/package.json @@ -19,6 +19,7 @@ }, "dependencies": { "@jest/environment": "^28.0.0-alpha.1", + "@jest/expect": "^28.0.0-alpha.1", "@jest/test-result": "^28.0.0-alpha.1", "@jest/types": "^28.0.0-alpha.1", "@types/node": "*", diff --git a/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapterInit.ts b/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapterInit.ts index 6e4e01f7da2c..17439f6329ab 100644 --- a/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapterInit.ts +++ b/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapterInit.ts @@ -7,6 +7,7 @@ import throat from 'throat'; import type {JestEnvironment} from '@jest/environment'; +import {createJestExpect, type JestExpect} from '@jest/expect'; import { AssertionResult, Status, @@ -15,7 +16,7 @@ import { createEmptyTestResult, } from '@jest/test-result'; import type {Circus, Config, Global} from '@jest/types'; -import {Expect, expect} from 'expect'; +import {expect} from 'expect'; import {bind} from 'jest-each'; import {formatExecError, formatResultsErrors} from 'jest-message-util'; import { @@ -33,12 +34,9 @@ import { } from '../state'; import testCaseReportHandler from '../testCaseReportHandler'; import {getTestID} from '../utils'; -import createExpect from './jestExpect'; -type Process = NodeJS.Process; - -interface JestGlobals extends Global.TestFrameworkGlobals { - expect: Expect; +interface RuntimeGlobals extends Global.TestFrameworkGlobals { + expect: JestExpect; } export const initialize = async ({ @@ -56,9 +54,9 @@ export const initialize = async ({ globalConfig: Config.GlobalConfig; localRequire: (path: Config.Path) => T; testPath: Config.Path; - parentProcess: Process; + parentProcess: NodeJS.Process; sendMessageToJest?: TestFileEvent; - setGlobalsForRuntime: (globals: JestGlobals) => void; + setGlobalsForRuntime: (globals: RuntimeGlobals) => void; }): Promise<{ globals: Global.TestFrameworkGlobals; snapshotState: SnapshotState; @@ -124,9 +122,9 @@ export const initialize = async ({ addEventHandler(environment.handleTestEvent.bind(environment)); } - const runtimeGlobals: JestGlobals = { + const runtimeGlobals: RuntimeGlobals = { ...globalsObject, - expect: createExpect(globalConfig), + expect: createJestExpect(globalConfig), }; setGlobalsForRuntime(runtimeGlobals); @@ -161,7 +159,7 @@ export const initialize = async ({ snapshotFormat: config.snapshotFormat, updateSnapshot, }); - // @ts-expect-error: snapshotState is a jest extension of `expect` + expect.setState({snapshotState, testPath}); addEventHandler(handleSnapshotStateAfterRetry(snapshotState)); diff --git a/packages/jest-circus/tsconfig.json b/packages/jest-circus/tsconfig.json index 4e6535abac08..96e0db1b3bd0 100644 --- a/packages/jest-circus/tsconfig.json +++ b/packages/jest-circus/tsconfig.json @@ -10,6 +10,7 @@ {"path": "../expect"}, {"path": "../jest-each"}, {"path": "../jest-environment"}, + {"path": "../jest-expect"}, {"path": "../jest-matcher-utils"}, {"path": "../jest-message-util"}, {"path": "../jest-runtime"}, diff --git a/packages/jest-expect/.npmignore b/packages/jest-expect/.npmignore new file mode 100644 index 000000000000..8ea2d7d53d29 --- /dev/null +++ b/packages/jest-expect/.npmignore @@ -0,0 +1,5 @@ +**/__tests__/** +src +tsconfig.json +tsconfig.tsbuildinfo +api-extractor.json diff --git a/packages/jest-expect/package.json b/packages/jest-expect/package.json new file mode 100644 index 000000000000..d722187400f6 --- /dev/null +++ b/packages/jest-expect/package.json @@ -0,0 +1,30 @@ +{ + "name": "@jest/expect", + "version": "28.0.0-alpha.1", + "repository": { + "type": "git", + "url": "https://github.com/facebook/jest.git", + "directory": "packages/jest-expect" + }, + "license": "MIT", + "main": "./build/index.js", + "types": "./build/index.d.ts", + "exports": { + ".": { + "types": "./build/index.d.ts", + "default": "./build/index.js" + }, + "./package.json": "./package.json" + }, + "dependencies": { + "@jest/types": "^28.0.0-alpha.1", + "expect": "^28.0.0-alpha.1", + "jest-snapshot": "^28.0.0-alpha.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.13.0 || >=17.0.0" + }, + "publishConfig": { + "access": "public" + } +} diff --git a/packages/jest-circus/src/legacy-code-todo-rewrite/jestExpect.ts b/packages/jest-expect/src/index.ts similarity index 60% rename from packages/jest-circus/src/legacy-code-todo-rewrite/jestExpect.ts rename to packages/jest-expect/src/index.ts index 6f6332f72490..fc61b486b7a2 100644 --- a/packages/jest-circus/src/legacy-code-todo-rewrite/jestExpect.ts +++ b/packages/jest-expect/src/index.ts @@ -6,7 +6,7 @@ */ import type {Config} from '@jest/types'; -import {Expect, expect} from 'expect'; +import {expect} from 'expect'; import { addSerializer, toMatchInlineSnapshot, @@ -14,19 +14,22 @@ import { toThrowErrorMatchingInlineSnapshot, toThrowErrorMatchingSnapshot, } from 'jest-snapshot'; +import type {JestExpect} from './types'; -export default function jestExpect( - config: Pick, -): Expect { - expect.setState({expand: config.expand}); - expect.extend({ +export type {JestExpect} from './types'; + +export function createJestExpect({expand}: Config.GlobalConfig): JestExpect { + const jestExpect = expect as JestExpect; + + jestExpect.setState({expand}); + jestExpect.extend({ toMatchInlineSnapshot, toMatchSnapshot, toThrowErrorMatchingInlineSnapshot, toThrowErrorMatchingSnapshot, }); - expect.addSnapshotSerializer = addSerializer; + jestExpect.addSnapshotSerializer = addSerializer; - return expect; + return jestExpect; } diff --git a/packages/jest-expect/src/types.ts b/packages/jest-expect/src/types.ts new file mode 100644 index 000000000000..53c8253edb72 --- /dev/null +++ b/packages/jest-expect/src/types.ts @@ -0,0 +1,89 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import type {AsymmetricMatchers, BaseExpect, Matchers} from 'expect'; +import type {SnapshotState, addSerializer} from 'jest-snapshot'; + +export type JestExpect = { + (actual: T): JestMatchers & + Inverse> & + PromiseMatchers; + addSnapshotSerializer: typeof addSerializer; +} & BaseExpect & + AsymmetricMatchers & + Inverse>; + +type Inverse = { + /** + * Inverse next matcher. If you know how to test something, `.not` lets you test its opposite. + */ + not: Matchers; +}; + +type JestMatchers, T> = Matchers & + SnapshotMatchers; + +type PromiseMatchers = { + /** + * Unwraps the reason of a rejected promise so any other matcher can be chained. + * If the promise is fulfilled the assertion fails. + */ + rejects: JestMatchers, T> & + Inverse, T>>; + /** + * Unwraps the value of a fulfilled promise so any other matcher can be chained. + * If the promise is rejected the assertion fails. + */ + resolves: JestMatchers, T> & + Inverse, T>>; +}; + +interface SnapshotMatchers, T> { + /** + * This ensures that a value matches the most recent snapshot with property matchers. + * Check out [the Snapshot Testing guide](https://jestjs.io/docs/snapshot-testing) for more information. + */ + toMatchSnapshot(hint?: string): R; + /** + * This ensures that a value matches the most recent snapshot. + * Check out [the Snapshot Testing guide](https://jestjs.io/docs/snapshot-testing) for more information. + */ + toMatchSnapshot>( + propertyMatchers: Partial, + hint?: string, + ): R; + /** + * This ensures that a value matches the most recent snapshot with property matchers. + * Instead of writing the snapshot value to a .snap file, it will be written into the source code automatically. + * Check out [the Snapshot Testing guide](https://jestjs.io/docs/snapshot-testing) for more information. + */ + toMatchInlineSnapshot(snapshot?: string): R; + /** + * This ensures that a value matches the most recent snapshot with property matchers. + * Instead of writing the snapshot value to a .snap file, it will be written into the source code automatically. + * Check out [the Snapshot Testing guide](https://jestjs.io/docs/snapshot-testing) for more information. + */ + toMatchInlineSnapshot>( + propertyMatchers: Partial, + snapshot?: string, + ): R; + /** + * Used to test that a function throws a error matching the most recent snapshot when it is called. + */ + toThrowErrorMatchingSnapshot(hint?: string): R; + /** + * Used to test that a function throws a error matching the most recent snapshot when it is called. + * Instead of writing the snapshot value to a .snap file, it will be written into the source code automatically. + */ + toThrowErrorMatchingInlineSnapshot(snapshot?: string): R; +} + +declare module 'expect' { + interface MatcherState { + snapshotState: SnapshotState; + } +} diff --git a/packages/jest-expect/tsconfig.json b/packages/jest-expect/tsconfig.json new file mode 100644 index 000000000000..36568fbd370b --- /dev/null +++ b/packages/jest-expect/tsconfig.json @@ -0,0 +1,14 @@ +{ + "extends": "../../tsconfig", + "compilerOptions": { + "outDir": "build", + "rootDir": "src" + }, + "include": ["./src/**/*"], + "exclude": ["./**/__tests__/**/*"], + "references": [ + {"path": "../expect"}, + {"path": "../jest-snapshot"}, + {"path": "../jest-types"} + ] +} diff --git a/packages/jest-globals/package.json b/packages/jest-globals/package.json index ebc40a85f2ad..4f64d0a8cd1d 100644 --- a/packages/jest-globals/package.json +++ b/packages/jest-globals/package.json @@ -21,8 +21,8 @@ }, "dependencies": { "@jest/environment": "^28.0.0-alpha.1", - "@jest/types": "^28.0.0-alpha.1", - "expect": "^28.0.0-alpha.1" + "@jest/expect": "^28.0.0-alpha.1", + "@jest/types": "^28.0.0-alpha.1" }, "publishConfig": { "access": "public" diff --git a/packages/jest-globals/src/index.ts b/packages/jest-globals/src/index.ts index 5d84d89125d1..90f50d9665ec 100644 --- a/packages/jest-globals/src/index.ts +++ b/packages/jest-globals/src/index.ts @@ -6,12 +6,12 @@ */ import type {Jest} from '@jest/environment'; +import type {JestExpect} from '@jest/expect'; import type {Global} from '@jest/types'; -import type {Expect} from 'expect'; export declare const jest: Jest; -export declare const expect: Expect; +export declare const expect: JestExpect; export declare const it: Global.GlobalAdditions['it']; export declare const test: Global.GlobalAdditions['test']; diff --git a/packages/jest-globals/tsconfig.json b/packages/jest-globals/tsconfig.json index ef7d4e629e02..16a7adbc92db 100644 --- a/packages/jest-globals/tsconfig.json +++ b/packages/jest-globals/tsconfig.json @@ -9,8 +9,8 @@ "include": ["./src/**/*"], "exclude": ["./**/__tests__/**/*"], "references": [ - {"path": "../expect"}, {"path": "../jest-environment"}, + {"path": "../jest-expect"}, {"path": "../jest-types"} ] } diff --git a/packages/jest-jasmine2/src/jestExpect.ts b/packages/jest-jasmine2/src/jestExpect.ts index 579b6a7de605..32e1dc1128b7 100644 --- a/packages/jest-jasmine2/src/jestExpect.ts +++ b/packages/jest-jasmine2/src/jestExpect.ts @@ -26,6 +26,7 @@ export default function jestExpect(config: {expand: boolean}): void { toThrowErrorMatchingInlineSnapshot, toThrowErrorMatchingSnapshot, }); + // @ts-expect-error: TODO expect.addSnapshotSerializer = addSerializer; const jasmine = global.jasmine; diff --git a/packages/jest-jasmine2/src/setup_jest_globals.ts b/packages/jest-jasmine2/src/setup_jest_globals.ts index ceddb98beba6..e44e78ebc81d 100644 --- a/packages/jest-jasmine2/src/setup_jest_globals.ts +++ b/packages/jest-jasmine2/src/setup_jest_globals.ts @@ -111,7 +111,7 @@ export default async function setupJestGlobals({ snapshotFormat, updateSnapshot, }); - // @ts-expect-error: snapshotState is a jest extension of `expect` + expect.setState({snapshotState, testPath}); // Return it back to the outer scope (test runner outside the VM). return snapshotState; diff --git a/yarn.lock b/yarn.lock index d72e8c0a8e57..cdf0a53e81af 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2589,6 +2589,16 @@ __metadata: languageName: unknown linkType: soft +"@jest/expect@^28.0.0-alpha.1, @jest/expect@workspace:packages/jest-expect": + version: 0.0.0-use.local + resolution: "@jest/expect@workspace:packages/jest-expect" + dependencies: + "@jest/types": ^28.0.0-alpha.1 + expect: ^28.0.0-alpha.1 + jest-snapshot: ^28.0.0-alpha.1 + languageName: unknown + linkType: soft + "@jest/fake-timers@^28.0.0-alpha.1, @jest/fake-timers@workspace:packages/jest-fake-timers": version: 0.0.0-use.local resolution: "@jest/fake-timers@workspace:packages/jest-fake-timers" @@ -2608,6 +2618,7 @@ __metadata: resolution: "@jest/globals@workspace:packages/jest-globals" dependencies: "@jest/environment": ^28.0.0-alpha.1 + "@jest/expect": ^28.0.0-alpha.1 "@jest/types": ^28.0.0-alpha.1 expect: ^28.0.0-alpha.1 languageName: unknown @@ -12854,6 +12865,7 @@ __metadata: "@babel/core": ^7.1.0 "@babel/register": ^7.0.0 "@jest/environment": ^28.0.0-alpha.1 + "@jest/expect": ^28.0.0-alpha.1 "@jest/test-result": ^28.0.0-alpha.1 "@jest/types": ^28.0.0-alpha.1 "@types/co": ^4.6.0 From 7b2bea6fa00b734d34b3b2009ead97a64a866ddc Mon Sep 17 00:00:00 2001 From: mrazauskas <72159681+mrazauskas@users.noreply.github.com> Date: Wed, 16 Feb 2022 10:52:46 +0200 Subject: [PATCH 02/20] fix lock --- yarn.lock | 1 - 1 file changed, 1 deletion(-) diff --git a/yarn.lock b/yarn.lock index cdf0a53e81af..10f14f92f49b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2620,7 +2620,6 @@ __metadata: "@jest/environment": ^28.0.0-alpha.1 "@jest/expect": ^28.0.0-alpha.1 "@jest/types": ^28.0.0-alpha.1 - expect: ^28.0.0-alpha.1 languageName: unknown linkType: soft From e7ca2a20fb3539372340f0a40a93069ebb9fc7a1 Mon Sep 17 00:00:00 2001 From: mrazauskas <72159681+mrazauskas@users.noreply.github.com> Date: Wed, 16 Feb 2022 11:05:27 +0200 Subject: [PATCH 03/20] fix lint --- .../jest-circus/src/legacy-code-todo-rewrite/jestAdapterInit.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapterInit.ts b/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapterInit.ts index 17439f6329ab..a22bcfb58fed 100644 --- a/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapterInit.ts +++ b/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapterInit.ts @@ -7,7 +7,7 @@ import throat from 'throat'; import type {JestEnvironment} from '@jest/environment'; -import {createJestExpect, type JestExpect} from '@jest/expect'; +import {type JestExpect, createJestExpect} from '@jest/expect'; import { AssertionResult, Status, From c22b8393f50145573c4ef20feb91d818f3bb7e6d Mon Sep 17 00:00:00 2001 From: mrazauskas <72159681+mrazauskas@users.noreply.github.com> Date: Wed, 16 Feb 2022 11:46:34 +0200 Subject: [PATCH 04/20] clean up --- packages/expect/src/index.ts | 2 +- packages/expect/src/types.ts | 4 ++-- packages/jest-circus/tsconfig.json | 4 +++- packages/jest-jasmine2/tsconfig.json | 6 +++--- 4 files changed, 9 insertions(+), 7 deletions(-) diff --git a/packages/expect/src/index.ts b/packages/expect/src/index.ts index a85fe7c4c297..c459e0a5ad99 100644 --- a/packages/expect/src/index.ts +++ b/packages/expect/src/index.ts @@ -80,7 +80,7 @@ const createToThrowErrorMatchingSnapshotMatcher = function ( }; }; -const getPromiseMatcher = (name: string, matcher: any) => { +const getPromiseMatcher = (name: string, matcher: RawMatcherFn) => { if (name === 'toThrow' || name === 'toThrowError') { return createThrowMatcher(name, true); } else if ( diff --git a/packages/expect/src/types.ts b/packages/expect/src/types.ts index 0cc4a79114ec..5b839fe1c7a3 100644 --- a/packages/expect/src/types.ts +++ b/packages/expect/src/types.ts @@ -63,12 +63,12 @@ export interface MatcherState { }; } -export interface AsymmetricMatcher { +export type AsymmetricMatcher = { asymmetricMatch(other: unknown): boolean; toString(): string; getExpectedType?(): string; toAsymmetricMatcher?(): string; -} +}; export type ExpectedAssertionsErrors = Array<{ actual: string | number; diff --git a/packages/jest-circus/tsconfig.json b/packages/jest-circus/tsconfig.json index 96e0db1b3bd0..2c06aaab31cf 100644 --- a/packages/jest-circus/tsconfig.json +++ b/packages/jest-circus/tsconfig.json @@ -2,7 +2,9 @@ "extends": "../../tsconfig", "compilerOptions": { "outDir": "build", - "rootDir": "src" + "rootDir": "src", + // we don't want `@types/jest` to be referenced + "types": [] }, "include": ["./src/**/*"], "exclude": ["./**/__mocks__/**/*", "./**/__tests__/**/*"], diff --git a/packages/jest-jasmine2/tsconfig.json b/packages/jest-jasmine2/tsconfig.json index f7813a30ad7a..a09361901761 100644 --- a/packages/jest-jasmine2/tsconfig.json +++ b/packages/jest-jasmine2/tsconfig.json @@ -1,10 +1,10 @@ { "extends": "../../tsconfig", "compilerOptions": { - // we don't want `@types/jest` to be referenced - "types": [], "rootDir": "src", - "outDir": "build" + "outDir": "build", + // we don't want `@types/jest` to be referenced + "types": [] }, "include": ["./src/**/*"], "exclude": ["./**/__tests__/**/*"], From d033c5e3279613c0b1179d0f07c246cf1bc48a75 Mon Sep 17 00:00:00 2001 From: mrazauskas <72159681+mrazauskas@users.noreply.github.com> Date: Wed, 16 Feb 2022 12:03:37 +0200 Subject: [PATCH 05/20] remove expect dependency from circus --- packages/jest-circus/package.json | 1 - .../legacy-code-todo-rewrite/jestAdapterInit.ts | 17 +++++++++-------- packages/jest-circus/src/types.ts | 2 -- packages/jest-circus/tsconfig.json | 1 - packages/jest-expect/package.json | 1 - packages/jest-expect/src/index.ts | 6 +++--- packages/jest-expect/tsconfig.json | 6 +----- yarn.lock | 2 -- 8 files changed, 13 insertions(+), 23 deletions(-) diff --git a/packages/jest-circus/package.json b/packages/jest-circus/package.json index d4b2a9d1eb4e..110f2aaebec2 100644 --- a/packages/jest-circus/package.json +++ b/packages/jest-circus/package.json @@ -26,7 +26,6 @@ "chalk": "^4.0.0", "co": "^4.6.0", "dedent": "^0.7.0", - "expect": "^28.0.0-alpha.1", "is-generator-fn": "^2.0.0", "jest-each": "^28.0.0-alpha.1", "jest-matcher-utils": "^28.0.0-alpha.1", diff --git a/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapterInit.ts b/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapterInit.ts index a22bcfb58fed..00bc2529bb69 100644 --- a/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapterInit.ts +++ b/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapterInit.ts @@ -7,7 +7,7 @@ import throat from 'throat'; import type {JestEnvironment} from '@jest/environment'; -import {type JestExpect, createJestExpect} from '@jest/expect'; +import {type JestExpect, jestExpect} from '@jest/expect'; import { AssertionResult, Status, @@ -16,7 +16,6 @@ import { createEmptyTestResult, } from '@jest/test-result'; import type {Circus, Config, Global} from '@jest/types'; -import {expect} from 'expect'; import {bind} from 'jest-each'; import {formatExecError, formatResultsErrors} from 'jest-message-util'; import { @@ -122,9 +121,11 @@ export const initialize = async ({ addEventHandler(environment.handleTestEvent.bind(environment)); } + jestExpect.setState({expand: globalConfig.expand}); + const runtimeGlobals: RuntimeGlobals = { ...globalsObject, - expect: createJestExpect(globalConfig), + expect: jestExpect, }; setGlobalsForRuntime(runtimeGlobals); @@ -160,7 +161,7 @@ export const initialize = async ({ updateSnapshot, }); - expect.setState({snapshotState, testPath}); + jestExpect.setState({snapshotState, testPath}); addEventHandler(handleSnapshotStateAfterRetry(snapshotState)); if (sendMessageToJest) { @@ -277,7 +278,7 @@ const handleSnapshotStateAfterRetry = const eventHandler = async (event: Circus.Event) => { switch (event.name) { case 'test_start': { - expect.setState({currentTestName: getTestID(event.test)}); + jestExpect.setState({currentTestName: getTestID(event.test)}); break; } case 'test_done': { @@ -289,7 +290,7 @@ const eventHandler = async (event: Circus.Event) => { }; const _addExpectedAssertionErrors = (test: Circus.TestEntry) => { - const failures = expect.extractExpectedAssertionsErrors(); + const failures = jestExpect.extractExpectedAssertionsErrors(); const errors = failures.map(failure => failure.error); test.errors = test.errors.concat(errors); }; @@ -298,8 +299,8 @@ const _addExpectedAssertionErrors = (test: Circus.TestEntry) => { // test execution and add them to the test result, potentially failing // a passing test. const _addSuppressedErrors = (test: Circus.TestEntry) => { - const {suppressedErrors} = expect.getState(); - expect.setState({suppressedErrors: []}); + const {suppressedErrors} = jestExpect.getState(); + jestExpect.setState({suppressedErrors: []}); if (suppressedErrors.length) { test.errors = test.errors.concat(suppressedErrors); } diff --git a/packages/jest-circus/src/types.ts b/packages/jest-circus/src/types.ts index 92d47eb16983..babde014441c 100644 --- a/packages/jest-circus/src/types.ts +++ b/packages/jest-circus/src/types.ts @@ -6,7 +6,6 @@ */ import type {Circus} from '@jest/types'; -import type {Expect} from 'expect'; export const STATE_SYM = Symbol( 'JEST_STATE_SYMBOL', @@ -25,7 +24,6 @@ declare global { STATE_SYM_SYMBOL: Circus.State; RETRY_TIMES_SYMBOL: string; TEST_TIMEOUT_SYMBOL: number; - expect: Expect; } } } diff --git a/packages/jest-circus/tsconfig.json b/packages/jest-circus/tsconfig.json index 2c06aaab31cf..67941a37790e 100644 --- a/packages/jest-circus/tsconfig.json +++ b/packages/jest-circus/tsconfig.json @@ -9,7 +9,6 @@ "include": ["./src/**/*"], "exclude": ["./**/__mocks__/**/*", "./**/__tests__/**/*"], "references": [ - {"path": "../expect"}, {"path": "../jest-each"}, {"path": "../jest-environment"}, {"path": "../jest-expect"}, diff --git a/packages/jest-expect/package.json b/packages/jest-expect/package.json index d722187400f6..6c0aa6a9a001 100644 --- a/packages/jest-expect/package.json +++ b/packages/jest-expect/package.json @@ -17,7 +17,6 @@ "./package.json": "./package.json" }, "dependencies": { - "@jest/types": "^28.0.0-alpha.1", "expect": "^28.0.0-alpha.1", "jest-snapshot": "^28.0.0-alpha.1" }, diff --git a/packages/jest-expect/src/index.ts b/packages/jest-expect/src/index.ts index fc61b486b7a2..197bc1ead788 100644 --- a/packages/jest-expect/src/index.ts +++ b/packages/jest-expect/src/index.ts @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. */ -import type {Config} from '@jest/types'; import {expect} from 'expect'; import { addSerializer, @@ -18,10 +17,9 @@ import type {JestExpect} from './types'; export type {JestExpect} from './types'; -export function createJestExpect({expand}: Config.GlobalConfig): JestExpect { +export function createJestExpect(): JestExpect { const jestExpect = expect as JestExpect; - jestExpect.setState({expand}); jestExpect.extend({ toMatchInlineSnapshot, toMatchSnapshot, @@ -33,3 +31,5 @@ export function createJestExpect({expand}: Config.GlobalConfig): JestExpect { return jestExpect; } + +export const jestExpect = createJestExpect(); diff --git a/packages/jest-expect/tsconfig.json b/packages/jest-expect/tsconfig.json index 36568fbd370b..b04915822b89 100644 --- a/packages/jest-expect/tsconfig.json +++ b/packages/jest-expect/tsconfig.json @@ -6,9 +6,5 @@ }, "include": ["./src/**/*"], "exclude": ["./**/__tests__/**/*"], - "references": [ - {"path": "../expect"}, - {"path": "../jest-snapshot"}, - {"path": "../jest-types"} - ] + "references": [{"path": "../expect"}, {"path": "../jest-snapshot"}] } diff --git a/yarn.lock b/yarn.lock index 10f14f92f49b..d077faaf08d9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2593,7 +2593,6 @@ __metadata: version: 0.0.0-use.local resolution: "@jest/expect@workspace:packages/jest-expect" dependencies: - "@jest/types": ^28.0.0-alpha.1 expect: ^28.0.0-alpha.1 jest-snapshot: ^28.0.0-alpha.1 languageName: unknown @@ -12876,7 +12875,6 @@ __metadata: co: ^4.6.0 dedent: ^0.7.0 execa: ^5.0.0 - expect: ^28.0.0-alpha.1 graceful-fs: ^4.2.9 is-generator-fn: ^2.0.0 jest-each: ^28.0.0-alpha.1 From 969d35e203dc97b29b16efc423ea368416ad0f22 Mon Sep 17 00:00:00 2001 From: mrazauskas <72159681+mrazauskas@users.noreply.github.com> Date: Wed, 16 Feb 2022 13:02:23 +0200 Subject: [PATCH 06/20] refactor jasmine --- packages/jest-jasmine2/package.json | 3 +- packages/jest-jasmine2/src/jestExpect.ts | 42 +++++-------------- .../jest-jasmine2/src/setup_jest_globals.ts | 12 +++--- packages/jest-jasmine2/src/types.ts | 6 +-- packages/jest-jasmine2/tsconfig.json | 3 +- yarn.lock | 3 +- 6 files changed, 23 insertions(+), 46 deletions(-) diff --git a/packages/jest-jasmine2/package.json b/packages/jest-jasmine2/package.json index 7e74e8cf5d9e..2c7794754844 100644 --- a/packages/jest-jasmine2/package.json +++ b/packages/jest-jasmine2/package.json @@ -18,19 +18,18 @@ }, "dependencies": { "@jest/environment": "^28.0.0-alpha.1", + "@jest/expect": "^28.0.0-alpha.1", "@jest/source-map": "^28.0.0-alpha.0", "@jest/test-result": "^28.0.0-alpha.1", "@jest/types": "^28.0.0-alpha.1", "@types/node": "*", "chalk": "^4.0.0", "co": "^4.6.0", - "expect": "^28.0.0-alpha.1", "is-generator-fn": "^2.0.0", "jest-each": "^28.0.0-alpha.1", "jest-matcher-utils": "^28.0.0-alpha.1", "jest-message-util": "^28.0.0-alpha.1", "jest-runtime": "^28.0.0-alpha.1", - "jest-snapshot": "^28.0.0-alpha.1", "jest-util": "^28.0.0-alpha.1", "pretty-format": "^28.0.0-alpha.1", "throat": "^6.0.1" diff --git a/packages/jest-jasmine2/src/jestExpect.ts b/packages/jest-jasmine2/src/jestExpect.ts index 32e1dc1128b7..722283c633cc 100644 --- a/packages/jest-jasmine2/src/jestExpect.ts +++ b/packages/jest-jasmine2/src/jestExpect.ts @@ -5,44 +5,24 @@ * LICENSE file in the root directory of this source tree. */ -/* eslint-disable local/prefer-spread-eventually */ - -import {type MatcherState, expect} from 'expect'; -import { - addSerializer, - toMatchInlineSnapshot, - toMatchSnapshot, - toThrowErrorMatchingInlineSnapshot, - toThrowErrorMatchingSnapshot, -} from 'jest-snapshot'; +import {jestExpect} from '@jest/expect'; import type {JasmineMatchersObject} from './types'; -export default function jestExpect(config: {expand: boolean}): void { - global.expect = expect; - expect.setState({expand: config.expand}); - expect.extend({ - toMatchInlineSnapshot, - toMatchSnapshot, - toThrowErrorMatchingInlineSnapshot, - toThrowErrorMatchingSnapshot, - }); - // @ts-expect-error: TODO - expect.addSnapshotSerializer = addSerializer; +export default function jestExpectAdapter(config: {expand: boolean}): void { + global.expect = jestExpect; + jestExpect.setState({expand: config.expand}); const jasmine = global.jasmine; - jasmine.anything = expect.anything; - jasmine.any = expect.any; - jasmine.objectContaining = expect.objectContaining; - jasmine.arrayContaining = expect.arrayContaining; - jasmine.stringMatching = expect.stringMatching; + jasmine.anything = jestExpect.anything; + jasmine.any = jestExpect.any; + jasmine.objectContaining = jestExpect.objectContaining; + jasmine.arrayContaining = jestExpect.arrayContaining; + jasmine.stringMatching = jestExpect.stringMatching; jasmine.addMatchers = (jasmineMatchersObject: JasmineMatchersObject) => { const jestMatchersObject = Object.create(null); Object.keys(jasmineMatchersObject).forEach(name => { - jestMatchersObject[name] = function ( - this: MatcherState, - ...args: Array - ) { + jestMatchersObject[name] = function (...args: Array) { // use "expect.extend" if you need to use equality testers (via this.equal) const result = jasmineMatchersObject[name](null, null); // if there is no 'negativeCompare', both should be handled by `compare` @@ -54,6 +34,6 @@ export default function jestExpect(config: {expand: boolean}): void { }; }); - expect.extend(jestMatchersObject); + jestExpect.extend(jestMatchersObject); }; } diff --git a/packages/jest-jasmine2/src/setup_jest_globals.ts b/packages/jest-jasmine2/src/setup_jest_globals.ts index e44e78ebc81d..183a972b705c 100644 --- a/packages/jest-jasmine2/src/setup_jest_globals.ts +++ b/packages/jest-jasmine2/src/setup_jest_globals.ts @@ -6,7 +6,7 @@ */ import type {Config} from '@jest/types'; -import {expect} from 'expect'; +import {jestExpect} from '@jest/expect'; import { SnapshotState, addSerializer, @@ -30,8 +30,8 @@ export type SetupOptions = { // test execution and add them to the test result, potentially failing // a passing test. const addSuppressedErrors = (result: SpecResult) => { - const {suppressedErrors} = expect.getState(); - expect.setState({suppressedErrors: []}); + const {suppressedErrors} = jestExpect.getState(); + jestExpect.setState({suppressedErrors: []}); if (suppressedErrors.length) { result.status = 'failed'; @@ -49,7 +49,7 @@ const addSuppressedErrors = (result: SpecResult) => { }; const addAssertionErrors = (result: SpecResult) => { - const assertionErrors = expect.extractExpectedAssertionsErrors(); + const assertionErrors = jestExpect.extractExpectedAssertionsErrors(); if (assertionErrors.length) { const jasmineErrors = assertionErrors.map(({actual, error, expected}) => ({ actual, @@ -74,7 +74,7 @@ const patchJasmine = () => { }; const onStart = attr.onStart; attr.onStart = (context: JasmineSpec) => { - expect.setState({currentTestName: context.getFullName()}); + jestExpect.setState({currentTestName: context.getFullName()}); onStart && onStart.call(attr, context); }; super(attr); @@ -112,7 +112,7 @@ export default async function setupJestGlobals({ updateSnapshot, }); - expect.setState({snapshotState, testPath}); + jestExpect.setState({snapshotState, testPath}); // Return it back to the outer scope (test runner outside the VM). return snapshotState; } diff --git a/packages/jest-jasmine2/src/types.ts b/packages/jest-jasmine2/src/types.ts index c444f8e77a98..5575b6230d90 100644 --- a/packages/jest-jasmine2/src/types.ts +++ b/packages/jest-jasmine2/src/types.ts @@ -6,8 +6,8 @@ */ import type {AssertionError} from 'assert'; +import type {JestExpect} from '@jest/expect'; import type {Config} from '@jest/types'; -import type {Expect} from 'expect'; import type CallTracker from './jasmine/CallTracker'; import type Env from './jasmine/Env'; import type JsApiReporter from './jasmine/JsApiReporter'; @@ -70,13 +70,13 @@ export type Jasmine = { version: string; testPath: Config.Path; addMatchers: (matchers: JasmineMatchersObject) => void; -} & Expect & +} & JestExpect & typeof globalThis; declare global { namespace NodeJS { interface Global { - expect: Expect; + expect: JestExpect; jasmine: Jasmine; } } diff --git a/packages/jest-jasmine2/tsconfig.json b/packages/jest-jasmine2/tsconfig.json index a09361901761..eb160d0e7dea 100644 --- a/packages/jest-jasmine2/tsconfig.json +++ b/packages/jest-jasmine2/tsconfig.json @@ -9,13 +9,12 @@ "include": ["./src/**/*"], "exclude": ["./**/__tests__/**/*"], "references": [ - {"path": "../expect"}, {"path": "../jest-each"}, {"path": "../jest-environment"}, + {"path": "../jest-expect"}, {"path": "../jest-matcher-utils"}, {"path": "../jest-message-util"}, {"path": "../jest-runtime"}, - {"path": "../jest-snapshot"}, {"path": "../jest-source-map"}, {"path": "../jest-test-result"}, {"path": "../jest-types"}, diff --git a/yarn.lock b/yarn.lock index d077faaf08d9..afd938f5aa87 100644 --- a/yarn.lock +++ b/yarn.lock @@ -13105,6 +13105,7 @@ __metadata: resolution: "jest-jasmine2@workspace:packages/jest-jasmine2" dependencies: "@jest/environment": ^28.0.0-alpha.1 + "@jest/expect": ^28.0.0-alpha.1 "@jest/source-map": ^28.0.0-alpha.0 "@jest/test-result": ^28.0.0-alpha.1 "@jest/types": ^28.0.0-alpha.1 @@ -13112,13 +13113,11 @@ __metadata: "@types/node": "*" chalk: ^4.0.0 co: ^4.6.0 - expect: ^28.0.0-alpha.1 is-generator-fn: ^2.0.0 jest-each: ^28.0.0-alpha.1 jest-matcher-utils: ^28.0.0-alpha.1 jest-message-util: ^28.0.0-alpha.1 jest-runtime: ^28.0.0-alpha.1 - jest-snapshot: ^28.0.0-alpha.1 jest-util: ^28.0.0-alpha.1 pretty-format: ^28.0.0-alpha.1 throat: ^6.0.1 From f22b639ba4bd5a8be16fc27860e0265f60078884 Mon Sep 17 00:00:00 2001 From: mrazauskas <72159681+mrazauskas@users.noreply.github.com> Date: Wed, 16 Feb 2022 13:11:52 +0200 Subject: [PATCH 07/20] fix lint --- packages/jest-jasmine2/src/setup_jest_globals.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/jest-jasmine2/src/setup_jest_globals.ts b/packages/jest-jasmine2/src/setup_jest_globals.ts index 183a972b705c..4d3321ea1976 100644 --- a/packages/jest-jasmine2/src/setup_jest_globals.ts +++ b/packages/jest-jasmine2/src/setup_jest_globals.ts @@ -5,8 +5,8 @@ * LICENSE file in the root directory of this source tree. */ -import type {Config} from '@jest/types'; import {jestExpect} from '@jest/expect'; +import type {Config} from '@jest/types'; import { SnapshotState, addSerializer, From 1e230f01975310f99052f7f7242cbba7fb44824c Mon Sep 17 00:00:00 2001 From: mrazauskas <72159681+mrazauskas@users.noreply.github.com> Date: Wed, 16 Feb 2022 13:25:03 +0200 Subject: [PATCH 08/20] move SnapshotMatchers --- packages/jest-expect/src/types.ts | 46 ++++------------------------- packages/jest-snapshot/src/index.ts | 1 + packages/jest-snapshot/src/types.ts | 40 +++++++++++++++++++++++++ 3 files changed, 46 insertions(+), 41 deletions(-) diff --git a/packages/jest-expect/src/types.ts b/packages/jest-expect/src/types.ts index 53c8253edb72..8bbe08fbbed1 100644 --- a/packages/jest-expect/src/types.ts +++ b/packages/jest-expect/src/types.ts @@ -6,7 +6,11 @@ */ import type {AsymmetricMatchers, BaseExpect, Matchers} from 'expect'; -import type {SnapshotState, addSerializer} from 'jest-snapshot'; +import type { + SnapshotMatchers, + SnapshotState, + addSerializer, +} from 'jest-snapshot'; export type JestExpect = { (actual: T): JestMatchers & @@ -42,46 +46,6 @@ type PromiseMatchers = { Inverse, T>>; }; -interface SnapshotMatchers, T> { - /** - * This ensures that a value matches the most recent snapshot with property matchers. - * Check out [the Snapshot Testing guide](https://jestjs.io/docs/snapshot-testing) for more information. - */ - toMatchSnapshot(hint?: string): R; - /** - * This ensures that a value matches the most recent snapshot. - * Check out [the Snapshot Testing guide](https://jestjs.io/docs/snapshot-testing) for more information. - */ - toMatchSnapshot>( - propertyMatchers: Partial, - hint?: string, - ): R; - /** - * This ensures that a value matches the most recent snapshot with property matchers. - * Instead of writing the snapshot value to a .snap file, it will be written into the source code automatically. - * Check out [the Snapshot Testing guide](https://jestjs.io/docs/snapshot-testing) for more information. - */ - toMatchInlineSnapshot(snapshot?: string): R; - /** - * This ensures that a value matches the most recent snapshot with property matchers. - * Instead of writing the snapshot value to a .snap file, it will be written into the source code automatically. - * Check out [the Snapshot Testing guide](https://jestjs.io/docs/snapshot-testing) for more information. - */ - toMatchInlineSnapshot>( - propertyMatchers: Partial, - snapshot?: string, - ): R; - /** - * Used to test that a function throws a error matching the most recent snapshot when it is called. - */ - toThrowErrorMatchingSnapshot(hint?: string): R; - /** - * Used to test that a function throws a error matching the most recent snapshot when it is called. - * Instead of writing the snapshot value to a .snap file, it will be written into the source code automatically. - */ - toThrowErrorMatchingInlineSnapshot(snapshot?: string): R; -} - declare module 'expect' { interface MatcherState { snapshotState: SnapshotState; diff --git a/packages/jest-snapshot/src/index.ts b/packages/jest-snapshot/src/index.ts index 5af2cbdf69e7..eb7b91d443ba 100644 --- a/packages/jest-snapshot/src/index.ts +++ b/packages/jest-snapshot/src/index.ts @@ -42,6 +42,7 @@ export { } from './SnapshotResolver'; export type {SnapshotResolver} from './SnapshotResolver'; export {default as SnapshotState} from './State'; +export type {SnapshotMatchers} from './types'; const DID_NOT_THROW = 'Received function did not throw'; // same as toThrow const NOT_SNAPSHOT_MATCHERS = `Snapshot matchers cannot be used with ${BOLD_WEIGHT( diff --git a/packages/jest-snapshot/src/types.ts b/packages/jest-snapshot/src/types.ts index 0013a08d081f..2f47b96a3ed0 100644 --- a/packages/jest-snapshot/src/types.ts +++ b/packages/jest-snapshot/src/types.ts @@ -23,3 +23,43 @@ export type MatchSnapshotConfig = { }; export type SnapshotData = Record; + +export interface SnapshotMatchers, T> { + /** + * This ensures that a value matches the most recent snapshot with property matchers. + * Check out [the Snapshot Testing guide](https://jestjs.io/docs/snapshot-testing) for more information. + */ + toMatchSnapshot(hint?: string): R; + /** + * This ensures that a value matches the most recent snapshot. + * Check out [the Snapshot Testing guide](https://jestjs.io/docs/snapshot-testing) for more information. + */ + toMatchSnapshot>( + propertyMatchers: Partial, + hint?: string, + ): R; + /** + * This ensures that a value matches the most recent snapshot with property matchers. + * Instead of writing the snapshot value to a .snap file, it will be written into the source code automatically. + * Check out [the Snapshot Testing guide](https://jestjs.io/docs/snapshot-testing) for more information. + */ + toMatchInlineSnapshot(snapshot?: string): R; + /** + * This ensures that a value matches the most recent snapshot with property matchers. + * Instead of writing the snapshot value to a .snap file, it will be written into the source code automatically. + * Check out [the Snapshot Testing guide](https://jestjs.io/docs/snapshot-testing) for more information. + */ + toMatchInlineSnapshot>( + propertyMatchers: Partial, + snapshot?: string, + ): R; + /** + * Used to test that a function throws a error matching the most recent snapshot when it is called. + */ + toThrowErrorMatchingSnapshot(hint?: string): R; + /** + * Used to test that a function throws a error matching the most recent snapshot when it is called. + * Instead of writing the snapshot value to a .snap file, it will be written into the source code automatically. + */ + toThrowErrorMatchingInlineSnapshot(snapshot?: string): R; +} From c2f0a81f95e14d6f9c8e82fb078693bb9e42d3a2 Mon Sep 17 00:00:00 2001 From: mrazauskas <72159681+mrazauskas@users.noreply.github.com> Date: Wed, 16 Feb 2022 13:32:43 +0200 Subject: [PATCH 09/20] tweak types --- packages/expect/src/types.ts | 4 ++-- packages/jest-expect/src/index.ts | 8 +++----- packages/jest-expect/src/types.ts | 4 +++- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/expect/src/types.ts b/packages/expect/src/types.ts index 5b839fe1c7a3..efee1eef055d 100644 --- a/packages/expect/src/types.ts +++ b/packages/expect/src/types.ts @@ -76,14 +76,14 @@ export type ExpectedAssertionsErrors = Array<{ expected: string; }>; -export type BaseExpect = { +export interface BaseExpect { assertions(numberOfAssertions: number): void; extend(matchers: MatchersObject): void; extractExpectedAssertionsErrors(): ExpectedAssertionsErrors; getState(): MatcherState; hasAssertions(): void; setState(state: Partial): void; -}; +} export type Expect = { (actual: T): Matchers & diff --git a/packages/jest-expect/src/index.ts b/packages/jest-expect/src/index.ts index 197bc1ead788..3086a8fe447a 100644 --- a/packages/jest-expect/src/index.ts +++ b/packages/jest-expect/src/index.ts @@ -18,18 +18,16 @@ import type {JestExpect} from './types'; export type {JestExpect} from './types'; export function createJestExpect(): JestExpect { - const jestExpect = expect as JestExpect; - - jestExpect.extend({ + expect.extend({ toMatchInlineSnapshot, toMatchSnapshot, toThrowErrorMatchingInlineSnapshot, toThrowErrorMatchingSnapshot, }); - jestExpect.addSnapshotSerializer = addSerializer; + expect.addSnapshotSerializer = addSerializer; - return jestExpect; + return expect as JestExpect; } export const jestExpect = createJestExpect(); diff --git a/packages/jest-expect/src/types.ts b/packages/jest-expect/src/types.ts index 8bbe08fbbed1..99146a5ba369 100644 --- a/packages/jest-expect/src/types.ts +++ b/packages/jest-expect/src/types.ts @@ -16,7 +16,6 @@ export type JestExpect = { (actual: T): JestMatchers & Inverse> & PromiseMatchers; - addSnapshotSerializer: typeof addSerializer; } & BaseExpect & AsymmetricMatchers & Inverse>; @@ -50,4 +49,7 @@ declare module 'expect' { interface MatcherState { snapshotState: SnapshotState; } + interface BaseExpect { + addSnapshotSerializer: typeof addSerializer; + } } From 4dc3760efc832bfc663db8a26705b1c7a3411c72 Mon Sep 17 00:00:00 2001 From: mrazauskas <72159681+mrazauskas@users.noreply.github.com> Date: Wed, 16 Feb 2022 14:07:35 +0200 Subject: [PATCH 10/20] add minimal readme --- packages/jest-expect/README.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 packages/jest-expect/README.md diff --git a/packages/jest-expect/README.md b/packages/jest-expect/README.md new file mode 100644 index 000000000000..68b2bb366f69 --- /dev/null +++ b/packages/jest-expect/README.md @@ -0,0 +1,5 @@ +# @jest/expect + +This package extends `expect` library with `jest-snapshot` matchers. It export `jestExpect`, which can be used as standalone replacement of `expect`, and `createJestExpect` factory function, which returns an instance of `jestExpect`. + +The `jestExpect` function used in [Jest](https://jestjs.io/). You can find its documentation [on Jest's website](https://jestjs.io/docs/expect). From 0352b7f212bc4dd1550421a670c8e0ad9135dee6 Mon Sep 17 00:00:00 2001 From: mrazauskas <72159681+mrazauskas@users.noreply.github.com> Date: Wed, 16 Feb 2022 14:16:00 +0200 Subject: [PATCH 11/20] add changelog entry --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ce1923b04bec..74ecb66b586f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ - `[jest-environment-jsdom]` [**BREAKING**] Upgrade jsdom to 19.0.0 ([#12290](https://github.com/facebook/jest/pull/12290)) - `[jest-environment-jsdom]` [**BREAKING**] Add default `browser` condition to `exportConditions` for `jsdom` environment ([#11924](https://github.com/facebook/jest/pull/11924)) - `[jest-environment-node]` [**BREAKING**] Add default `node` and `node-addon` conditions to `exportConditions` for `node` environment ([#11924](https://github.com/facebook/jest/pull/11924)) +- `[@jest/expect]` [**BREAKING**] New module which extends `expect` with `jest-snapshot` matchers ([#12404](https://github.com/facebook/jest/pull/12404)) - `[@jest/expect-utils]` New module exporting utils for `expect` ([#12323](https://github.com/facebook/jest/pull/12323)) - `[jest-resolver]` [**BREAKING**] Add support for `package.json` `exports` ([11961](https://github.com/facebook/jest/pull/11961)) - `[jest-resolve, jest-runtime]` Add support for `data:` URI import and mock ([#12392](https://github.com/facebook/jest/pull/12392)) From 102031b82fe3de60eed4c00b6f1adca95cca9ffe Mon Sep 17 00:00:00 2001 From: mrazauskas <72159681+mrazauskas@users.noreply.github.com> Date: Wed, 16 Feb 2022 14:16:41 +0200 Subject: [PATCH 12/20] eslint comment --- packages/jest-jasmine2/src/jestExpect.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/jest-jasmine2/src/jestExpect.ts b/packages/jest-jasmine2/src/jestExpect.ts index 722283c633cc..b95a661206b2 100644 --- a/packages/jest-jasmine2/src/jestExpect.ts +++ b/packages/jest-jasmine2/src/jestExpect.ts @@ -5,6 +5,8 @@ * LICENSE file in the root directory of this source tree. */ +/* eslint-disable local/prefer-spread-eventually */ + import {jestExpect} from '@jest/expect'; import type {JasmineMatchersObject} from './types'; From b9a27c2e1d2fb8b5faf6c2b89d703a0d05fce2c4 Mon Sep 17 00:00:00 2001 From: mrazauskas <72159681+mrazauskas@users.noreply.github.com> Date: Wed, 16 Feb 2022 14:49:59 +0200 Subject: [PATCH 13/20] tweak readme --- packages/jest-expect/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/jest-expect/README.md b/packages/jest-expect/README.md index 68b2bb366f69..ed84274db617 100644 --- a/packages/jest-expect/README.md +++ b/packages/jest-expect/README.md @@ -1,5 +1,5 @@ # @jest/expect -This package extends `expect` library with `jest-snapshot` matchers. It export `jestExpect`, which can be used as standalone replacement of `expect`, and `createJestExpect` factory function, which returns an instance of `jestExpect`. +This package extends `expect` library with `jest-snapshot` matchers. It export `jestExpect` object, which can be used as standalone replacement of `expect`, and `createJestExpect` factory function, which returns an instance of `jestExpect`. The `jestExpect` function used in [Jest](https://jestjs.io/). You can find its documentation [on Jest's website](https://jestjs.io/docs/expect). From de38ed25e5a6e9ae10f4d19e6d95a0e1229b065b Mon Sep 17 00:00:00 2001 From: mrazauskas <72159681+mrazauskas@users.noreply.github.com> Date: Wed, 16 Feb 2022 14:50:07 +0200 Subject: [PATCH 14/20] clean up --- .../src/legacy-code-todo-rewrite/jestAdapterInit.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapterInit.ts b/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapterInit.ts index 7bd7076b0faa..6723ae7d74ab 100644 --- a/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapterInit.ts +++ b/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapterInit.ts @@ -151,14 +151,13 @@ export const initialize = async ({ .reverse() .forEach(path => addSerializer(localRequire(path))); - const {expand, updateSnapshot} = globalConfig; const snapshotResolver = await buildSnapshotResolver(config, localRequire); const snapshotPath = snapshotResolver.resolveSnapshotPath(testPath); const snapshotState = new SnapshotState(snapshotPath, { - expand, + expand: globalConfig.expand, prettierPath: config.prettierPath, snapshotFormat: config.snapshotFormat, - updateSnapshot, + updateSnapshot: globalConfig.updateSnapshot, }); jestExpect.setState({snapshotState, testPath}); From e582a9ae95acb944aac4b6826f6cede87606a8f5 Mon Sep 17 00:00:00 2001 From: mrazauskas <72159681+mrazauskas@users.noreply.github.com> Date: Wed, 16 Feb 2022 14:56:04 +0200 Subject: [PATCH 15/20] bring back jest-snapshot --- packages/jest-jasmine2/package.json | 1 + packages/jest-jasmine2/tsconfig.json | 1 + yarn.lock | 1 + 3 files changed, 3 insertions(+) diff --git a/packages/jest-jasmine2/package.json b/packages/jest-jasmine2/package.json index 2c7794754844..1935dff545e4 100644 --- a/packages/jest-jasmine2/package.json +++ b/packages/jest-jasmine2/package.json @@ -30,6 +30,7 @@ "jest-matcher-utils": "^28.0.0-alpha.1", "jest-message-util": "^28.0.0-alpha.1", "jest-runtime": "^28.0.0-alpha.1", + "jest-snapshot": "^28.0.0-alpha.1", "jest-util": "^28.0.0-alpha.1", "pretty-format": "^28.0.0-alpha.1", "throat": "^6.0.1" diff --git a/packages/jest-jasmine2/tsconfig.json b/packages/jest-jasmine2/tsconfig.json index eb160d0e7dea..3d2268f04774 100644 --- a/packages/jest-jasmine2/tsconfig.json +++ b/packages/jest-jasmine2/tsconfig.json @@ -15,6 +15,7 @@ {"path": "../jest-matcher-utils"}, {"path": "../jest-message-util"}, {"path": "../jest-runtime"}, + {"path": "../jest-snapshot"}, {"path": "../jest-source-map"}, {"path": "../jest-test-result"}, {"path": "../jest-types"}, diff --git a/yarn.lock b/yarn.lock index c096a055b5ac..fe4a51fa5f20 100644 --- a/yarn.lock +++ b/yarn.lock @@ -13115,6 +13115,7 @@ __metadata: jest-matcher-utils: ^28.0.0-alpha.1 jest-message-util: ^28.0.0-alpha.1 jest-runtime: ^28.0.0-alpha.1 + jest-snapshot: ^28.0.0-alpha.1 jest-util: ^28.0.0-alpha.1 pretty-format: ^28.0.0-alpha.1 throat: ^6.0.1 From fa3e1c6f1b8b3717330f3e38ef292078b657d9c3 Mon Sep 17 00:00:00 2001 From: Simen Bekkhus Date: Wed, 16 Feb 2022 14:25:00 +0100 Subject: [PATCH 16/20] ensure snapshot matchers are gone from base expect, but present in jest --- packages/expect/__typetests__/expect.test.ts | 4 ++++ .../__typetests__/jest-expect.test.ts | 16 ++++++++++++++++ packages/jest-expect/__typetests__/tsconfig.json | 9 +++++++++ packages/jest-expect/package.json | 4 ++++ yarn.lock | 2 ++ 5 files changed, 35 insertions(+) create mode 100644 packages/jest-expect/__typetests__/jest-expect.test.ts create mode 100644 packages/jest-expect/__typetests__/tsconfig.json diff --git a/packages/expect/__typetests__/expect.test.ts b/packages/expect/__typetests__/expect.test.ts index 6b90bc9b9d93..36e94f6272e5 100644 --- a/packages/expect/__typetests__/expect.test.ts +++ b/packages/expect/__typetests__/expect.test.ts @@ -210,3 +210,7 @@ const customStateAndExpected: MatcherFunctionWithState< }; expectAssignable(customStateAndExpected); + +expectError(() => { + expect({}).toMatchSnapshot(); +}); diff --git a/packages/jest-expect/__typetests__/jest-expect.test.ts b/packages/jest-expect/__typetests__/jest-expect.test.ts new file mode 100644 index 000000000000..1b9dcb9fd0b4 --- /dev/null +++ b/packages/jest-expect/__typetests__/jest-expect.test.ts @@ -0,0 +1,16 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import {expectError, expectType} from 'tsd-lite'; +import {jestExpect} from '@jest/expect'; +import {expect} from 'expect'; + +expectType(jestExpect({}).toMatchSnapshot()); + +expectError(() => { + expect({}).toMatchSnapshot(); +}); diff --git a/packages/jest-expect/__typetests__/tsconfig.json b/packages/jest-expect/__typetests__/tsconfig.json new file mode 100644 index 000000000000..b7577781b384 --- /dev/null +++ b/packages/jest-expect/__typetests__/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "../../../tsconfig.json", + "compilerOptions": { + "noUnusedLocals": false, + "noUnusedParameters": false, + "skipLibCheck": true + }, + "include": ["./**/*"] +} diff --git a/packages/jest-expect/package.json b/packages/jest-expect/package.json index 6c0aa6a9a001..a8a938f03479 100644 --- a/packages/jest-expect/package.json +++ b/packages/jest-expect/package.json @@ -20,6 +20,10 @@ "expect": "^28.0.0-alpha.1", "jest-snapshot": "^28.0.0-alpha.1" }, + "devDependencies": { + "@tsd/typescript": "~4.5.5", + "tsd-lite": "^0.5.1" + }, "engines": { "node": "^12.13.0 || ^14.15.0 || ^16.13.0 || >=17.0.0" }, diff --git a/yarn.lock b/yarn.lock index fe4a51fa5f20..ca22e60a5e6b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2593,8 +2593,10 @@ __metadata: version: 0.0.0-use.local resolution: "@jest/expect@workspace:packages/jest-expect" dependencies: + "@tsd/typescript": ~4.5.5 expect: ^28.0.0-alpha.1 jest-snapshot: ^28.0.0-alpha.1 + tsd-lite: ^0.5.1 languageName: unknown linkType: soft From f1078f1bf7ec31f673a55087ff8fd920ea0301a7 Mon Sep 17 00:00:00 2001 From: Simen Bekkhus Date: Wed, 16 Feb 2022 14:30:31 +0100 Subject: [PATCH 17/20] assignability --- packages/jest-expect/__typetests__/jest-expect.test.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/jest-expect/__typetests__/jest-expect.test.ts b/packages/jest-expect/__typetests__/jest-expect.test.ts index 1b9dcb9fd0b4..4ddca08b5e1d 100644 --- a/packages/jest-expect/__typetests__/jest-expect.test.ts +++ b/packages/jest-expect/__typetests__/jest-expect.test.ts @@ -5,7 +5,12 @@ * LICENSE file in the root directory of this source tree. */ -import {expectError, expectType} from 'tsd-lite'; +import { + expectAssignable, + expectError, + expectNotAssignable, + expectType, +} from 'tsd-lite'; import {jestExpect} from '@jest/expect'; import {expect} from 'expect'; @@ -14,3 +19,6 @@ expectType(jestExpect({}).toMatchSnapshot()); expectError(() => { expect({}).toMatchSnapshot(); }); + +expectAssignable(jestExpect); +expectNotAssignable(expect); From c7fa36c25bbd6d1e9295e127c63525aec7225636 Mon Sep 17 00:00:00 2001 From: mrazauskas <72159681+mrazauskas@users.noreply.github.com> Date: Wed, 16 Feb 2022 16:03:08 +0200 Subject: [PATCH 18/20] addSnapshotSerializer test --- packages/jest-expect/__typetests__/jest-expect.test.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/jest-expect/__typetests__/jest-expect.test.ts b/packages/jest-expect/__typetests__/jest-expect.test.ts index 4ddca08b5e1d..63711307f39e 100644 --- a/packages/jest-expect/__typetests__/jest-expect.test.ts +++ b/packages/jest-expect/__typetests__/jest-expect.test.ts @@ -20,5 +20,11 @@ expectError(() => { expect({}).toMatchSnapshot(); }); +expectType(jestExpect.addSnapshotSerializer({} as any)); + +expectError(() => { + expect.addSnapshotSerializer(); +}); + expectAssignable(jestExpect); expectNotAssignable(expect); From f282d5097675c875d2728681623703e6e204f56e Mon Sep 17 00:00:00 2001 From: mrazauskas <72159681+mrazauskas@users.noreply.github.com> Date: Wed, 16 Feb 2022 16:37:21 +0200 Subject: [PATCH 19/20] fix lost addSnapshotSerializer type --- packages/jest-expect/__typetests__/jest-expect.test.ts | 3 ++- packages/jest-expect/src/types.ts | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/jest-expect/__typetests__/jest-expect.test.ts b/packages/jest-expect/__typetests__/jest-expect.test.ts index 63711307f39e..ac1d0193565c 100644 --- a/packages/jest-expect/__typetests__/jest-expect.test.ts +++ b/packages/jest-expect/__typetests__/jest-expect.test.ts @@ -13,6 +13,7 @@ import { } from 'tsd-lite'; import {jestExpect} from '@jest/expect'; import {expect} from 'expect'; +import type {Plugin} from 'pretty-format'; expectType(jestExpect({}).toMatchSnapshot()); @@ -20,7 +21,7 @@ expectError(() => { expect({}).toMatchSnapshot(); }); -expectType(jestExpect.addSnapshotSerializer({} as any)); +expectType(jestExpect.addSnapshotSerializer({} as Plugin)); expectError(() => { expect.addSnapshotSerializer(); diff --git a/packages/jest-expect/src/types.ts b/packages/jest-expect/src/types.ts index 99146a5ba369..cd88743f746a 100644 --- a/packages/jest-expect/src/types.ts +++ b/packages/jest-expect/src/types.ts @@ -16,6 +16,7 @@ export type JestExpect = { (actual: T): JestMatchers & Inverse> & PromiseMatchers; + addSnapshotSerializer: typeof addSerializer; } & BaseExpect & AsymmetricMatchers & Inverse>; From 5262e2a317f466c36988ec5327347fad50f86a0b Mon Sep 17 00:00:00 2001 From: Simen Bekkhus Date: Wed, 16 Feb 2022 16:21:48 +0100 Subject: [PATCH 20/20] Update packages/jest-expect/src/types.ts --- packages/jest-expect/src/types.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/jest-expect/src/types.ts b/packages/jest-expect/src/types.ts index cd88743f746a..10739da8481e 100644 --- a/packages/jest-expect/src/types.ts +++ b/packages/jest-expect/src/types.ts @@ -16,6 +16,7 @@ export type JestExpect = { (actual: T): JestMatchers & Inverse> & PromiseMatchers; + // Duplicated due to https://github.com/microsoft/rushstack/issues/1709 addSnapshotSerializer: typeof addSerializer; } & BaseExpect & AsymmetricMatchers &