diff --git a/CHANGELOG.md b/CHANGELOG.md index dfff58ba0d49..e6feea165a2b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ ### Fixes +- `[expect, @jest/expect]` Revert buggy inference of argument types for `*CalledWith` and `*ReturnedWith` matchers introduced in 29.1.0 ([#13339](https://github.com/facebook/jest/pull/13339)) + ### Chore & Maintenance ### Performance @@ -18,7 +20,7 @@ ### Features -- `[expect, @jest/expect]` support type inference for function parameters in `CalledWith` assertions ([#13268](https://github.com/facebook/jest/pull/13268)) +- `[expect, @jest/expect]` Support type inference for function parameters in `CalledWith` assertions ([#13268](https://github.com/facebook/jest/pull/13268)) - `[expect, @jest/expect]` Infer type of `*ReturnedWith` matchers argument ([#13278](https://github.com/facebook/jest/pull/13278)) - `[@jest/environment, jest-runtime]` Allow `jest.requireActual` and `jest.requireMock` to take a type argument ([#13253](https://github.com/facebook/jest/pull/13253)) - `[@jest/environment]` Allow `jest.mock` and `jest.doMock` to take a type argument ([#13254](https://github.com/facebook/jest/pull/13254)) diff --git a/packages/expect/__typetests__/expect.test.ts b/packages/expect/__typetests__/expect.test.ts index 6c5119eff56c..9bc1ccae24cb 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/types.ts b/packages/expect/src/types.ts index 649b235a7acc..24c063f4022d 100644 --- a/packages/expect/src/types.ts +++ b/packages/expect/src/types.ts @@ -94,9 +94,9 @@ export interface BaseExpect { } export type Expect = { - (actual: T): Matchers & - Inverse> & - PromiseMatchers; + (actual: T): Matchers & + Inverse> & + PromiseMatchers; } & BaseExpect & AsymmetricMatchers & Inverse>; @@ -118,38 +118,36 @@ 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> & Inverse, 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> & Inverse, T>>; + resolves: Matchers> & Inverse>>; }; -type EnsureFunctionLike = T extends (...args: any) => any ? T : never; - -export interface Matchers, T = unknown> { +export interface Matchers> { /** * Ensures the last call to a mock function was provided specific args. */ - lastCalledWith(...expected: Parameters>): R; + lastCalledWith(...expected: Array): R; /** * Ensure that the last call to a mock function has returned a specified value. */ - lastReturnedWith(expected: ReturnType>): R; + lastReturnedWith(expected: unknown): R; /** * Ensure that a mock function is called with specific arguments on an Nth call. */ - nthCalledWith(nth: number, ...expected: Parameters>): R; + nthCalledWith(nth: number, ...expected: Array): R; /** * Ensure that the nth call to a mock function has returned a specified value. */ - nthReturnedWith(nth: number, expected: ReturnType>): R; + nthReturnedWith(nth: number, expected: unknown): R; /** * Checks that a value is what you expect. It calls `Object.is` to compare values. * Don't use `toBe` with floating-point numbers. @@ -166,7 +164,7 @@ export interface Matchers, T = unknown> { /** * Ensure that a mock function is called with specific arguments. */ - toBeCalledWith(...expected: Parameters>): R; + toBeCalledWith(...expected: Array): R; /** * Using exact equality with floating point numbers is a bad idea. * Rounding means that intuitive things fail. @@ -249,25 +247,22 @@ export interface Matchers, T = unknown> { /** * Ensure that a mock function is called with specific arguments. */ - toHaveBeenCalledWith(...expected: Parameters>): R; + toHaveBeenCalledWith(...expected: Array): R; /** * Ensure that a mock function is called with specific arguments on an Nth call. */ - toHaveBeenNthCalledWith( - nth: number, - ...expected: Parameters> - ): R; + toHaveBeenNthCalledWith(nth: number, ...expected: Array): R; /** * If you have a mock function, you can use `.toHaveBeenLastCalledWith` * to test what arguments it was last called with. */ - toHaveBeenLastCalledWith(...expected: Parameters>): R; + toHaveBeenLastCalledWith(...expected: Array): R; /** * Use to test the specific value that a mock function last returned. * If the last call to the mock function threw an error, then this matcher will fail * no matter what value you provided as the expected return value. */ - toHaveLastReturnedWith(expected: ReturnType>): R; + toHaveLastReturnedWith(expected: unknown): R; /** * Used to check that an object has a `.length` property * and it is set to a certain numeric value. @@ -278,10 +273,7 @@ export interface Matchers, T = unknown> { * If the nth call to the mock function threw an error, then this matcher will fail * no matter what value you provided as the expected return value. */ - toHaveNthReturnedWith( - nth: number, - expected: ReturnType>, - ): R; + toHaveNthReturnedWith(nth: number, expected: unknown): R; /** * Use to check if property at provided reference keyPath exists for an object. * For checking deeply nested properties in an object you may use dot notation or an array containing @@ -311,7 +303,7 @@ export interface Matchers, T = unknown> { /** * Use to ensure that a mock function returned a specific value. */ - toHaveReturnedWith(expected: ReturnType>): R; + toHaveReturnedWith(expected: unknown): R; /** * Check that a string matches a regular expression. */ @@ -333,7 +325,7 @@ export interface Matchers, T = unknown> { /** * Ensure that a mock function has returned a specified value at least once. */ - toReturnWith(expected: ReturnType>): R; + toReturnWith(expected: unknown): R; /** * Use to test that objects have the same types as well as structure. */ diff --git a/packages/jest-expect/src/types.ts b/packages/jest-expect/src/types.ts index d1ba64a7f66f..10739da8481e 100644 --- a/packages/jest-expect/src/types.ts +++ b/packages/jest-expect/src/types.ts @@ -29,7 +29,7 @@ type Inverse = { not: Matchers; }; -type JestMatchers, T> = Matchers & +type JestMatchers, T> = Matchers & SnapshotMatchers; type PromiseMatchers = { diff --git a/packages/jest-types/__typetests__/expect.test.ts b/packages/jest-types/__typetests__/expect.test.ts index d7cdf40d56b1..37db168c7aab 100644 --- a/packages/jest-types/__typetests__/expect.test.ts +++ b/packages/jest-types/__typetests__/expect.test.ts @@ -214,55 +214,65 @@ expectError(expect(jest.fn()).toHaveBeenCalledTimes()); expectType(expect(jest.fn()).toBeCalledWith()); expectType(expect(jest.fn()).toBeCalledWith('value')); expectType(expect(jest.fn()).toBeCalledWith('value', 123)); +expectType( + expect(jest.fn<(a: string, b: number) => void>()).toBeCalledWith( + expect.stringContaining('value'), + 123, + ), +); + expectType(expect(jest.fn()).toHaveBeenCalledWith()); expectType(expect(jest.fn()).toHaveBeenCalledWith(123)); expectType(expect(jest.fn()).toHaveBeenCalledWith(123, 'value')); - -/** - * type inference for "CalledWith" matchers parameters - */ -expectError(expect(jest.fn<(a: string) => void>()).toHaveBeenCalledWith(123)); -expectError( - expect(jest.fn<(a: string) => void>()).toHaveBeenNthCalledWith(1, 123), -); -expectError( - expect(jest.fn<(a: string) => void>()).toHaveBeenLastCalledWith(123), -); -expectType( - expect( - jest.fn<(a: string, b: number, c?: boolean) => void>(), - ).toHaveBeenCalledWith('value', 123), -); expectType( - expect( - jest.fn<(a: string, b: number, c?: boolean) => void>(), - ).toHaveBeenCalledWith('value', 123, true), -); -expectError( - expect( - jest.fn<(a: string, b: number, c?: boolean) => void>(), - ).toHaveBeenCalledWith(123, 'value'), -); -expectError( - expect( - jest.fn<(a: string, b: number, c?: boolean) => void>(), - ).toHaveBeenCalledWith('value', 123, 'not a boolean'), + expect(jest.fn<(a: string, b: number) => void>()).toHaveBeenCalledWith( + expect.stringContaining('value'), + 123, + ), ); expectType(expect(jest.fn()).lastCalledWith()); expectType(expect(jest.fn()).lastCalledWith('value')); expectType(expect(jest.fn()).lastCalledWith('value', 123)); +expectType( + expect(jest.fn<(a: string, b: number) => void>()).lastCalledWith( + expect.stringContaining('value'), + 123, + ), +); + expectType(expect(jest.fn()).toHaveBeenLastCalledWith()); expectType(expect(jest.fn()).toHaveBeenLastCalledWith(123)); expectType(expect(jest.fn()).toHaveBeenLastCalledWith(123, 'value')); +expectType( + expect(jest.fn<(a: string, b: number) => void>()).lastCalledWith( + expect.stringContaining('value'), + 123, + ), +); expectType(expect(jest.fn()).nthCalledWith(2)); expectType(expect(jest.fn()).nthCalledWith(1, 'value')); expectType(expect(jest.fn()).nthCalledWith(1, 'value', 123)); +expectType( + expect(jest.fn<(a: string, b: number) => void>()).nthCalledWith( + 1, + expect.stringContaining('value'), + 123, + ), +); expectError(expect(jest.fn()).nthCalledWith()); + expectType(expect(jest.fn()).toHaveBeenNthCalledWith(2)); expectType(expect(jest.fn()).toHaveBeenNthCalledWith(1, 'value')); expectType(expect(jest.fn()).toHaveBeenNthCalledWith(1, 'value', 123)); +expectType( + expect(jest.fn<(a: string, b: number) => void>()).toHaveBeenNthCalledWith( + 1, + expect.stringContaining('value'), + 123, + ), +); expectError(expect(jest.fn()).toHaveBeenNthCalledWith()); expectType(expect(jest.fn()).toReturn()); @@ -278,43 +288,55 @@ expectError(expect(jest.fn()).toHaveReturnedTimes(true)); expectError(expect(jest.fn()).toHaveReturnedTimes()); expectType(expect(jest.fn()).toReturnWith('value')); -expectType(expect(jest.fn<() => string>()).toReturnWith('value')); -expectError(expect(jest.fn<() => number>()).toReturnWith('value')); -expectError(expect(123).toReturnWith('value')); +expectType( + expect(jest.fn<() => string>()).toReturnWith( + expect.stringContaining('value'), + ), +); expectError(expect(jest.fn()).toReturnWith()); expectType(expect(jest.fn()).toHaveReturnedWith(123)); -expectType(expect(jest.fn<() => number>()).toHaveReturnedWith(123)); -expectError(expect(jest.fn<() => string>()).toHaveReturnedWith(123)); -expectError(expect(123).toHaveReturnedWith(123)); +expectType( + expect(jest.fn<() => string>()).toHaveReturnedWith( + expect.stringContaining('value'), + ), +); expectError(expect(jest.fn()).toHaveReturnedWith()); expectType(expect(jest.fn()).lastReturnedWith('value')); -expectType(expect(jest.fn<() => string>()).lastReturnedWith('value')); -expectError(expect(jest.fn<() => number>()).lastReturnedWith('value')); -expectError(expect(123).lastReturnedWith('value')); +expectType( + expect(jest.fn<() => string>()).lastReturnedWith( + expect.stringContaining('value'), + ), +); expectError(expect(jest.fn()).lastReturnedWith()); expectType(expect(jest.fn()).toHaveLastReturnedWith(123)); -expectType(expect(jest.fn<() => number>()).toHaveLastReturnedWith(123)); -expectError(expect(jest.fn<() => string>()).toHaveLastReturnedWith(123)); -expectError(expect(123).toHaveLastReturnedWith(123)); +expectType( + expect(jest.fn<() => string>()).toHaveLastReturnedWith( + expect.stringContaining('value'), + ), +); expectError(expect(jest.fn()).toHaveLastReturnedWith()); expectType(expect(jest.fn()).nthReturnedWith(1, 'value')); -expectType(expect(jest.fn<() => string>()).nthReturnedWith(2, 'value')); -expectError(expect(jest.fn<() => number>()).nthReturnedWith(3, 'value')); -expectError(expect(123).nthReturnedWith(4, 'value')); -expectError(expect(123).nthReturnedWith(5)); +expectType( + expect(jest.fn<() => string>()).nthReturnedWith( + 2, + expect.stringContaining('value'), + ), +); +expectError(expect(123).nthReturnedWith(3)); expectError(expect(jest.fn()).nthReturnedWith()); -expectType(expect(jest.fn()).toHaveNthReturnedWith(1, 'value')); +expectType(expect(jest.fn()).nthReturnedWith(1, 'value')); expectType( - expect(jest.fn<() => string>()).toHaveNthReturnedWith(2, 'value'), + expect(jest.fn<() => string>()).nthReturnedWith( + 2, + expect.stringContaining('value'), + ), ); -expectError(expect(jest.fn<() => number>()).toHaveNthReturnedWith(3, 'value')); -expectError(expect(123).toHaveNthReturnedWith(4, 'value')); -expectError(expect(123).toHaveNthReturnedWith(5)); +expectError(expect(123).toHaveNthReturnedWith(3)); expectError(expect(jest.fn()).toHaveNthReturnedWith()); // snapshot matchers