diff --git a/CHANGELOG.md b/CHANGELOG.md index 8c0004c09728..b33270d10468 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ - `[jest-environment-jsdom]` [**BREAKING**] Upgrade JSDOM to v22 ([#13825](https://github.com/jestjs/jest/pull/13825)) - `[@jest/environment-jsdom-abstract]` Introduce new package which abstracts over the `jsdom` environment, allowing usage of custom versions of JSDOM ([#14717](https://github.com/jestjs/jest/pull/14717)) - `[jest-environment-node]` Update jest environment with dispose symbols `Symbol` ([#14888](https://github.com/jestjs/jest/pull/14888) & [#14909](https://github.com/jestjs/jest/pull/14909)) +- `[expect, @jest/expect]` [**BREAKING**] Add type inference for function parameters in `CalledWith` assertions ([#15129](https://github.com/facebook/jest/pull/15129)) - `[@jest/fake-timers]` [**BREAKING**] Upgrade `@sinonjs/fake-timers` to v11 ([#14544](https://github.com/jestjs/jest/pull/14544)) - `[@jest/fake-timers]` Exposing new modern timers function `advanceTimersToFrame()` which advances all timers by the needed milliseconds to execute callbacks currently scheduled with `requestAnimationFrame` ([#14598](https://github.com/jestjs/jest/pull/14598)) - `[jest-matcher-utils]` Add `SERIALIZABLE_PROPERTIES` to allow custom serialization of objects ([#14893](https://github.com/jestjs/jest/pull/14893)) diff --git a/packages/expect/src/types.ts b/packages/expect/src/types.ts index d29bc6b4a92c..430d4720defd 100644 --- a/packages/expect/src/types.ts +++ b/packages/expect/src/types.ts @@ -8,6 +8,7 @@ import type {EqualsFunction, Tester} from '@jest/expect-utils'; import type * as jestMatcherUtils from 'jest-matcher-utils'; +import type {Mock} from 'jest-mock'; import type {INTERNAL_MATCHER_FLAG} from './jestMatchersObject'; export type SyncExpectationResult = { @@ -231,16 +232,16 @@ export interface Matchers, T = unknown> { /** * Ensure that a mock function is called with specific arguments. */ - toHaveBeenCalledWith(...expected: Array): R; + toHaveBeenCalledWith(...expected: MockParameters): R; /** * Ensure that a mock function is called with specific arguments on an Nth call. */ - toHaveBeenNthCalledWith(nth: number, ...expected: Array): R; + toHaveBeenNthCalledWith(nth: number, ...expected: MockParameters): R; /** * If you have a mock function, you can use `.toHaveBeenLastCalledWith` * to test what arguments it was last called with. */ - toHaveBeenLastCalledWith(...expected: Array): R; + toHaveBeenLastCalledWith(...expected: MockParameters): 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 @@ -307,3 +308,128 @@ export interface Matchers, T = unknown> { */ toThrow(expected?: unknown): R; } + +/** + * Obtains the parameters of the given {@link Mock}'s function type. + * ```ts + * type P = MockParameters void>>; + * + * const params1: P = [1]; // compiles + * const params2: P = ['bar']; // error + * const params3: P = []; // error + * ``` + * + * This is similar to {@link Parameters}, with these notable differences: + * + * 1. Each of the parameters can also accept an {@link AsymmetricMatcher}. + * ```ts + * const params4: P = [expect.anything()]; // compiles + * ``` + * This works with nested types as well: + * ```ts + * type Nested = MockParameters void>>; + * + * const params1: Nested = [{ foo: { a: 1 }}, ['value']]; // compiles + * const params2: Nested = [expect.anything(), expect.anything()]; // compiles + * const params3: Nested = [{ foo: { a: expect.anything() }}, [expect.anything()]]; // compiles + * ``` + * + * 2. This type works with overloaded functions (up to 15 overloads): + * ```ts + * function overloaded(): void; + * function overloaded(foo: number): void; + * function overloaded(foo: number, bar: string): void; + * function overloaded(foo?: number, bar?: string): void {} + * + * type Overloaded = MockParameters>; + * + * const params1: Overloaded = []; // compiles + * const params2: Overloaded = [1]; // compiles + * const params3: Overloaded = [1, 'value']; // compiles + * const params4: Overloaded = ['value']; // error + * const params5: Overloaded = ['value', 1]; // error + * ``` + * + * Mocks generated with the default `Mock` type will evaluate to `Array`: + * ```ts + * MockParameters // Array + * ``` + * + * If the given type is not a `Mock`, this type will evaluate to `Array`: + * ```ts + * MockParameters<() => void> // Array + * ``` + */ +type MockParameters = + MockParametersInternal extends never + ? Array + : MockParametersInternal; + +/** + * 1. If `M` is not a `Mock` -> `never`. + * 2. If the mock function is overloaded or has no parameters -> overloaded form (union of tuples). + * 3. If the mock function has parameters -> simple form. + * 4. else -> `never`. + */ +type MockParametersInternal = + M extends Mock + ? F extends { + (...args: infer P1): any; + (...args: infer P2): any; + (...args: infer P3): any; + (...args: infer P4): any; + (...args: infer P5): any; + (...args: infer P6): any; + (...args: infer P7): any; + (...args: infer P8): any; + (...args: infer P9): any; + (...args: infer P10): any; + (...args: infer P11): any; + (...args: infer P12): any; + (...args: infer P13): any; + (...args: infer P14): any; + (...args: infer P15): any; + } + ? + | WithAsymmetricMatchers + | WithAsymmetricMatchers + | WithAsymmetricMatchers + | WithAsymmetricMatchers + | WithAsymmetricMatchers + | WithAsymmetricMatchers + | WithAsymmetricMatchers + | WithAsymmetricMatchers + | WithAsymmetricMatchers + | WithAsymmetricMatchers + | WithAsymmetricMatchers + | WithAsymmetricMatchers + | WithAsymmetricMatchers + | WithAsymmetricMatchers + | WithAsymmetricMatchers + : F extends (...args: infer P) => any + ? WithAsymmetricMatchers

+ : never + : never; + +/** + * The condition here "catches" the parameters of the default `Mock` type ({@link UnknownFunction}), + * evaluating to `never`, and later "wrapped" by `MockParameters` and finally evaluates to `Array`. + */ +type WithAsymmetricMatchers

> = + Array extends P + ? never + : {[K in keyof P]: DeepAsymmetricMatcher}; + +/** + * Replaces `T` with `T | AsymmetricMatcher`. + * + * If `T` is an object or an array, recursively replaces all nested types with the same logic: + * ```ts + * type DeepAsymmetricMatcher; // AsymmetricMatcher | boolean + * type DeepAsymmetricMatcher<{ foo: number }>; // AsymmetricMatcher | { foo: AsymmetricMatcher | number } + * type DeepAsymmetricMatcher<[string]>; // AsymmetricMatcher | [AsymmetricMatcher | string] + * ``` + */ +type DeepAsymmetricMatcher = T extends object + ? AsymmetricMatcher | {[K in keyof T]: DeepAsymmetricMatcher} + : AsymmetricMatcher | T; diff --git a/packages/jest-snapshot/src/__tests__/throwMatcher.test.ts b/packages/jest-snapshot/src/__tests__/throwMatcher.test.ts index 9293e8e24762..3f6a42924df3 100644 --- a/packages/jest-snapshot/src/__tests__/throwMatcher.test.ts +++ b/packages/jest-snapshot/src/__tests__/throwMatcher.test.ts @@ -7,7 +7,9 @@ import {type Context, toThrowErrorMatchingSnapshot} from '../'; -const mockedMatch = jest.fn(() => ({ +const mockedMatch = jest.fn< + (args: {received: string; testName: string}) => unknown +>(() => ({ actual: 'coconut', expected: 'coconut', })); diff --git a/packages/jest-types/__typetests__/expect.test.ts b/packages/jest-types/__typetests__/expect.test.ts index 15bd00f847d8..0338b5a865ce 100644 --- a/packages/jest-types/__typetests__/expect.test.ts +++ b/packages/jest-types/__typetests__/expect.test.ts @@ -307,6 +307,249 @@ expect( ), ).type.toBeVoid(); +expect( + jestExpect(jest.fn<() => void>()).toHaveBeenCalledWith(), +).type.toBeVoid(); +expect( + jestExpect(jest.fn<() => void>()).toHaveBeenCalledWith(123), +).type.toRaiseError(); + +expect( + jestExpect(jest.fn<(n?: number) => void>()).toHaveBeenCalledWith(), +).type.toBeVoid(); +expect( + jestExpect(jest.fn<(n?: number) => void>()).toHaveBeenCalledWith(123), +).type.toBeVoid(); +expect( + jestExpect(jest.fn<(n?: number) => void>()).toHaveBeenCalledWith('value'), +).type.toRaiseError(); + +expect( + jestExpect(jest.fn<(n: number) => void>()).toHaveBeenCalledWith(123), +).type.toBeVoid(); +expect( + jestExpect(jest.fn<(n: number) => void>()).toHaveBeenCalledWith(), +).type.toRaiseError(); +expect( + jestExpect(jest.fn<(n: number) => void>()).toHaveBeenCalledWith('value'), +).type.toRaiseError(); + +expect( + jestExpect(jest.fn<(s: string) => void>()).toHaveBeenCalledWith('value'), +).type.toBeVoid(); +expect( + jestExpect(jest.fn<(s: string) => void>()).toHaveBeenCalledWith(), +).type.toRaiseError(); +expect( + jestExpect(jest.fn<(s: string) => void>()).toHaveBeenCalledWith(123), +).type.toRaiseError(); + +expect( + jestExpect(jest.fn<(n: number, s: string) => void>()).toHaveBeenCalledWith( + 123, + 'value', + ), +).type.toBeVoid(); +expect( + jestExpect(jest.fn<(n: number, s: string) => void>()).toHaveBeenCalledWith(), +).type.toRaiseError(); +expect( + jestExpect(jest.fn<(n: number, s: string) => void>()).toHaveBeenCalledWith( + 123, + ), +).type.toRaiseError(); +expect( + jestExpect(jest.fn<(n: number, s: string) => void>()).toHaveBeenCalledWith( + 123, + 123, + ), +).type.toRaiseError(); +expect( + jestExpect(jest.fn<(n: number, s: string) => void>()).toHaveBeenCalledWith( + 'value', + 'value', + ), +).type.toRaiseError(); +expect( + jestExpect(jest.fn<(n: number, s: string) => void>()).toHaveBeenCalledWith( + 'value', + 123, + ), +).type.toRaiseError(); + +expect( + jestExpect(jest.fn<(n: number, s?: string) => void>()).toHaveBeenCalledWith( + 123, + 'value', + ), +).type.toBeVoid(); +expect( + jestExpect(jest.fn<(n: number, s?: string) => void>()).toHaveBeenCalledWith( + 123, + ), +).type.toBeVoid(); +expect( + jestExpect(jest.fn<(n: number, s?: string) => void>()).toHaveBeenCalledWith(), +).type.toRaiseError(); +expect( + jestExpect(jest.fn<(n: number, s?: string) => void>()).toHaveBeenCalledWith( + 'value', + ), +).type.toRaiseError(); +expect( + jestExpect(jest.fn<(n: number, s?: string) => void>()).toHaveBeenCalledWith( + 'value', + 'value', + ), +).type.toRaiseError(); +expect( + jestExpect(jest.fn<(n: number, s?: string) => void>()).toHaveBeenCalledWith( + 'value', + 123, + ), +).type.toRaiseError(); +expect( + jestExpect(jest.fn<(n: number, s?: string) => void>()).toHaveBeenCalledWith( + 123, + 123, + ), +).type.toRaiseError(); + +function overloaded(): void; +// eslint-disable-next-line @typescript-eslint/unified-signatures +function overloaded(n: number): void; +// eslint-disable-next-line @typescript-eslint/unified-signatures +function overloaded(n: number, s: string): void; +// eslint-disable-next-line @typescript-eslint/unified-signatures +function overloaded(n: number, b: boolean): void; +function overloaded(n?: number, sOrB?: string | boolean): void { + // noop +} + +expect( + jestExpect(jest.fn()).toHaveBeenCalledWith(), +).type.toBeVoid(); +expect( + jestExpect(jest.fn()).toHaveBeenCalledWith(123), +).type.toBeVoid(); +expect( + jestExpect(jest.fn()).toHaveBeenCalledWith(123, 'value'), +).type.toBeVoid(); +expect( + jestExpect(jest.fn()).toHaveBeenCalledWith(123, true), +).type.toBeVoid(); +expect( + jestExpect(jest.fn()).toHaveBeenCalledWith(123, 123), +).type.toRaiseError(); +expect( + jestExpect(jest.fn()).toHaveBeenCalledWith('value'), +).type.toRaiseError(); +expect( + jestExpect(jest.fn()).toHaveBeenCalledWith(true), +).type.toRaiseError(); +expect( + jestExpect(jest.fn()).toHaveBeenCalledWith( + 'value', + 'value', + ), +).type.toRaiseError(); +expect( + jestExpect(jest.fn()).toHaveBeenCalledWith(true, false), +).type.toRaiseError(); + +expect( + jestExpect( + jest.fn<(date: Date, name?: [string, string]) => void>(), + ).toHaveBeenCalledWith(jestExpect.any(Date), [ + jestExpect.any(String), + jestExpect.any(String), + ]), +).type.toBeVoid(); +expect( + jestExpect( + jest.fn<(date: Date, name?: [string, string]) => void>(), + ).toHaveBeenCalledWith(jestExpect.any(Date), jestExpect.any(Array)), +).type.toBeVoid(); +expect( + jestExpect( + jest.fn<(date: Date, name?: [string, string]) => void>(), + ).toHaveBeenCalledWith(jestExpect.any(Date)), +).type.toBeVoid(); +expect( + jestExpect( + jest.fn<(date: Date, name?: [string, string]) => void>(), + ).toHaveBeenCalledWith(jestExpect.any(Date), []), +).type.toRaiseError(); +expect( + jestExpect( + jest.fn<(date: Date, name?: [string, string]) => void>(), + ).toHaveBeenCalledWith(jestExpect.any(Date), [jestExpect.any(String)]), +).type.toRaiseError(); +expect( + jestExpect( + jest.fn<(date: Date, name?: [string, string]) => void>(), + ).toHaveBeenCalledWith(jestExpect.any(Date), [jestExpect.any(String), 123]), +).type.toRaiseError(); + +expect( + jestExpect( + jest.fn<(date: Date, name: {foo: string}) => void>(), + ).toHaveBeenCalledWith(jestExpect.any(Date), {foo: jestExpect.any(String)}), +).type.toBeVoid(); +expect( + jestExpect( + jest.fn<(date: Date, name: {foo: string}) => void>(), + ).toHaveBeenCalledWith(jestExpect.any(Date), jestExpect.any(Object)), +).type.toBeVoid(); +expect( + jestExpect( + jest.fn<(date: Date, name: {foo: string}) => void>(), + ).toHaveBeenCalledWith(jestExpect.any(Date)), +).type.toRaiseError(); +expect( + jestExpect( + jest.fn<(date: Date, name: {foo: string}) => void>(), + ).toHaveBeenCalledWith(jestExpect.any(Date), {bar: jestExpect.any(String)}), +).type.toRaiseError(); +expect( + jestExpect( + jest.fn<(date: Date, name: {foo: string}) => void>(), + ).toHaveBeenCalledWith(jestExpect.any(Date), { + bar: jestExpect.any(String), + foo: jestExpect.any(String), + }), +).type.toRaiseError(); + +expect( + jestExpect( + jest.fn<(date: Date, name: [string, [string]]) => void>(), + ).toHaveBeenCalledWith(jestExpect.any(Date), [ + jestExpect.any(String), + [jestExpect.any(String)], + ]), +).type.toBeVoid(); +expect( + jestExpect( + jest.fn<(date: Date, name: [string, [string]]) => void>(), + ).toHaveBeenCalledWith(jestExpect.any(Date), [ + 'value', + [jestExpect.any(String)], + ]), +).type.toBeVoid(); +expect( + jestExpect( + jest.fn<(date: Date, name: [string, [string]]) => void>(), + ).toHaveBeenCalledWith(jestExpect.any(Date), [ + jestExpect.any(String), + ['value'], + ]), +).type.toBeVoid(); +expect( + jestExpect( + jest.fn<(date: Date, name: [string, [string]]) => void>(), + ).toHaveBeenCalledWith(jestExpect.any(Date), ['value', ['value']]), +).type.toBeVoid(); + expect(jestExpect(jest.fn()).toHaveBeenLastCalledWith()).type.toBeVoid(); expect(jestExpect(jest.fn()).toHaveBeenLastCalledWith('value')).type.toBeVoid(); expect(jestExpect(jest.fn()).toHaveBeenLastCalledWith(123)).type.toBeVoid(); @@ -322,6 +565,247 @@ expect( ).toHaveBeenLastCalledWith(jestExpect.stringContaining('value'), 123), ).type.toBeVoid(); +expect( + jestExpect(jest.fn<() => void>()).toHaveBeenLastCalledWith(), +).type.toBeVoid(); +expect( + jestExpect(jest.fn<() => void>()).toHaveBeenLastCalledWith(1), +).type.toRaiseError(); + +expect( + jestExpect(jest.fn<(n?: number) => void>()).toHaveBeenLastCalledWith(), +).type.toBeVoid(); +expect( + jestExpect(jest.fn<(n?: number) => void>()).toHaveBeenLastCalledWith(123), +).type.toBeVoid(); +expect( + jestExpect(jest.fn<(n?: number) => void>()).toHaveBeenLastCalledWith('value'), +).type.toRaiseError(); + +expect( + jestExpect(jest.fn<(n: number) => void>()).toHaveBeenLastCalledWith(123), +).type.toBeVoid(); +expect( + jestExpect(jest.fn<(n: number) => void>()).toHaveBeenLastCalledWith(), +).type.toRaiseError(); +expect( + jestExpect(jest.fn<(n: number) => void>()).toHaveBeenLastCalledWith('value'), +).type.toRaiseError(); + +expect( + jestExpect(jest.fn<(s: string) => void>()).toHaveBeenLastCalledWith('value'), +).type.toBeVoid(); +expect( + jestExpect(jest.fn<(s: string) => void>()).toHaveBeenLastCalledWith(), +).type.toRaiseError(); +expect( + jestExpect(jest.fn<(s: string) => void>()).toHaveBeenLastCalledWith(123), +).type.toRaiseError(); + +expect( + jestExpect( + jest.fn<(n: number, s: string) => void>(), + ).toHaveBeenLastCalledWith(123, 'value'), +).type.toBeVoid(); +expect( + jestExpect( + jest.fn<(n: number, s: string) => void>(), + ).toHaveBeenLastCalledWith(), +).type.toRaiseError(); +expect( + jestExpect( + jest.fn<(n: number, s: string) => void>(), + ).toHaveBeenLastCalledWith(123), +).type.toRaiseError(); +expect( + jestExpect( + jest.fn<(n: number, s: string) => void>(), + ).toHaveBeenLastCalledWith(123, 123), +).type.toRaiseError(); +expect( + jestExpect( + jest.fn<(n: number, s: string) => void>(), + ).toHaveBeenLastCalledWith('value', 'value'), +).type.toRaiseError(); +expect( + jestExpect( + jest.fn<(n: number, s: string) => void>(), + ).toHaveBeenLastCalledWith('value', 123), +).type.toRaiseError(); + +expect( + jestExpect( + jest.fn<(n: number, s?: string) => void>(), + ).toHaveBeenLastCalledWith(123, 'value'), +).type.toBeVoid(); +expect( + jestExpect( + jest.fn<(n: number, s?: string) => void>(), + ).toHaveBeenLastCalledWith(123), +).type.toBeVoid(); +expect( + jestExpect( + jest.fn<(n: number, s?: string) => void>(), + ).toHaveBeenLastCalledWith(), +).type.toRaiseError(); +expect( + jestExpect( + jest.fn<(n: number, s?: string) => void>(), + ).toHaveBeenLastCalledWith('value'), +).type.toRaiseError(); +expect( + jestExpect( + jest.fn<(n: number, s?: string) => void>(), + ).toHaveBeenLastCalledWith('value', 'value'), +).type.toRaiseError(); +expect( + jestExpect( + jest.fn<(n: number, s?: string) => void>(), + ).toHaveBeenLastCalledWith('value', 123), +).type.toRaiseError(); +expect( + jestExpect( + jest.fn<(n: number, s?: string) => void>(), + ).toHaveBeenLastCalledWith(123, 123), +).type.toRaiseError(); + +expect( + jestExpect(jest.fn()).toHaveBeenLastCalledWith(), +).type.toBeVoid(); +expect( + jestExpect(jest.fn()).toHaveBeenLastCalledWith(123), +).type.toBeVoid(); +expect( + jestExpect(jest.fn()).toHaveBeenLastCalledWith( + 123, + 'value', + ), +).type.toBeVoid(); +expect( + jestExpect(jest.fn()).toHaveBeenLastCalledWith(123, true), +).type.toBeVoid(); +expect( + jestExpect(jest.fn()).toHaveBeenLastCalledWith(123, 123), +).type.toRaiseError(); +expect( + jestExpect(jest.fn()).toHaveBeenLastCalledWith('value'), +).type.toRaiseError(); +expect( + jestExpect(jest.fn()).toHaveBeenLastCalledWith(true), +).type.toRaiseError(); +expect( + jestExpect(jest.fn()).toHaveBeenLastCalledWith( + 'value', + 'value', + ), +).type.toRaiseError(); +expect( + jestExpect(jest.fn()).toHaveBeenLastCalledWith( + true, + false, + ), +).type.toRaiseError(); + +expect( + jestExpect( + jest.fn<(date: Date, name?: [string, string]) => void>(), + ).toHaveBeenLastCalledWith(jestExpect.any(Date), [ + jestExpect.any(String), + jestExpect.any(String), + ]), +).type.toBeVoid(); +expect( + jestExpect( + jest.fn<(date: Date, name?: [string, string]) => void>(), + ).toHaveBeenLastCalledWith(jestExpect.any(Date), jestExpect.any(Array)), +).type.toBeVoid(); +expect( + jestExpect( + jest.fn<(date: Date, name?: [string, string]) => void>(), + ).toHaveBeenLastCalledWith(jestExpect.any(Date)), +).type.toBeVoid(); +expect( + jestExpect( + jest.fn<(date: Date, name?: [string, string]) => void>(), + ).toHaveBeenLastCalledWith(jestExpect.any(Date), []), +).type.toRaiseError(); +expect( + jestExpect( + jest.fn<(date: Date, name?: [string, string]) => void>(), + ).toHaveBeenLastCalledWith(jestExpect.any(Date), [jestExpect.any(String)]), +).type.toRaiseError(); +expect( + jestExpect( + jest.fn<(date: Date, name?: [string, string]) => void>(), + ).toHaveBeenLastCalledWith(jestExpect.any(Date), [ + jestExpect.any(String), + 123, + ]), +).type.toRaiseError(); + +expect( + jestExpect( + jest.fn<(date: Date, name: {foo: string}) => void>(), + ).toHaveBeenLastCalledWith(jestExpect.any(Date), { + foo: jestExpect.any(String), + }), +).type.toBeVoid(); +expect( + jestExpect( + jest.fn<(date: Date, name: {foo: string}) => void>(), + ).toHaveBeenLastCalledWith(jestExpect.any(Date), jestExpect.any(Object)), +).type.toBeVoid(); +expect( + jestExpect( + jest.fn<(date: Date, name: {foo: string}) => void>(), + ).toHaveBeenLastCalledWith(jestExpect.any(Date)), +).type.toRaiseError(); +expect( + jestExpect( + jest.fn<(date: Date, name: {foo: string}) => void>(), + ).toHaveBeenLastCalledWith(jestExpect.any(Date), { + bar: jestExpect.any(String), + }), +).type.toRaiseError(); +expect( + jestExpect( + jest.fn<(date: Date, name: {foo: string}) => void>(), + ).toHaveBeenLastCalledWith(jestExpect.any(Date), { + bar: jestExpect.any(String), + foo: jestExpect.any(String), + }), +).type.toRaiseError(); + +expect( + jestExpect( + jest.fn<(date: Date, name: [string, [string]]) => void>(), + ).toHaveBeenLastCalledWith(jestExpect.any(Date), [ + jestExpect.any(String), + [jestExpect.any(String)], + ]), +).type.toBeVoid(); +expect( + jestExpect( + jest.fn<(date: Date, name: [string, [string]]) => void>(), + ).toHaveBeenLastCalledWith(jestExpect.any(Date), [ + 'value', + [jestExpect.any(String)], + ]), +).type.toBeVoid(); +expect( + jestExpect( + jest.fn<(date: Date, name: [string, [string]]) => void>(), + ).toHaveBeenLastCalledWith(jestExpect.any(Date), [ + jestExpect.any(String), + ['value'], + ]), +).type.toBeVoid(); +expect( + jestExpect( + jest.fn<(date: Date, name: [string, [string]]) => void>(), + ).toHaveBeenLastCalledWith(jestExpect.any(Date), ['value', ['value']]), +).type.toBeVoid(); + expect(jestExpect(jest.fn()).toHaveBeenNthCalledWith(2)).type.toBeVoid(); expect( jestExpect(jest.fn()).toHaveBeenNthCalledWith(1, 'value'), @@ -338,6 +822,272 @@ expect( ).type.toBeVoid(); expect(jestExpect(jest.fn()).toHaveBeenNthCalledWith()).type.toRaiseError(); +expect( + jestExpect(jest.fn<() => void>()).toHaveBeenNthCalledWith(1), +).type.toBeVoid(); +expect( + jestExpect(jest.fn<() => void>()).toHaveBeenNthCalledWith(1, 123), +).type.toRaiseError(); + +expect( + jestExpect(jest.fn<(n?: number) => void>()).toHaveBeenNthCalledWith(1), +).type.toBeVoid(); +expect( + jestExpect(jest.fn<(n?: number) => void>()).toHaveBeenNthCalledWith(1, 123), +).type.toBeVoid(); +expect( + jestExpect(jest.fn<(n?: number) => void>()).toHaveBeenNthCalledWith( + 1, + 'value', + ), +).type.toRaiseError(); + +expect( + jestExpect(jest.fn<(n: number) => void>()).toHaveBeenNthCalledWith(1, 123), +).type.toBeVoid(); +expect( + jestExpect(jest.fn<(n: number) => void>()).toHaveBeenNthCalledWith(1), +).type.toRaiseError(); +expect( + jestExpect(jest.fn<(n: number) => void>()).toHaveBeenNthCalledWith( + 1, + 'value', + ), +).type.toRaiseError(); + +expect( + jestExpect(jest.fn<(s: string) => void>()).toHaveBeenNthCalledWith( + 1, + 'value', + ), +).type.toBeVoid(); +expect( + jestExpect(jest.fn<(s: string) => void>()).toHaveBeenNthCalledWith(1), +).type.toRaiseError(); +expect( + jestExpect(jest.fn<(s: string) => void>()).toHaveBeenNthCalledWith(1, 123), +).type.toRaiseError(); + +expect( + jestExpect(jest.fn<(n: number, s: string) => void>()).toHaveBeenNthCalledWith( + 1, + 123, + 'value', + ), +).type.toBeVoid(); +expect( + jestExpect(jest.fn<(n: number, s: string) => void>()).toHaveBeenNthCalledWith( + 1, + ), +).type.toRaiseError(); +expect( + jestExpect(jest.fn<(n: number, s: string) => void>()).toHaveBeenNthCalledWith( + 1, + 123, + ), +).type.toRaiseError(); +expect( + jestExpect(jest.fn<(n: number, s: string) => void>()).toHaveBeenNthCalledWith( + 1, + 123, + 123, + ), +).type.toRaiseError(); +expect( + jestExpect(jest.fn<(n: number, s: string) => void>()).toHaveBeenNthCalledWith( + 1, + 'value', + 'value', + ), +).type.toRaiseError(); +expect( + jestExpect(jest.fn<(n: number, s: string) => void>()).toHaveBeenNthCalledWith( + 1, + 'value', + 123, + ), +).type.toRaiseError(); + +expect( + jestExpect( + jest.fn<(n: number, s?: string) => void>(), + ).toHaveBeenNthCalledWith(1, 123, 'value'), +).type.toBeVoid(); +expect( + jestExpect( + jest.fn<(n: number, s?: string) => void>(), + ).toHaveBeenNthCalledWith(1, 123), +).type.toBeVoid(); +expect( + jestExpect( + jest.fn<(n: number, s?: string) => void>(), + ).toHaveBeenNthCalledWith(1), +).type.toRaiseError(); +expect( + jestExpect( + jest.fn<(n: number, s?: string) => void>(), + ).toHaveBeenNthCalledWith(1, 'value'), +).type.toRaiseError(); +expect( + jestExpect( + jest.fn<(n: number, s?: string) => void>(), + ).toHaveBeenNthCalledWith(1, 'value', 'value'), +).type.toRaiseError(); +expect( + jestExpect( + jest.fn<(n: number, s?: string) => void>(), + ).toHaveBeenNthCalledWith(1, 'value', 123), +).type.toRaiseError(); +expect( + jestExpect( + jest.fn<(n: number, s?: string) => void>(), + ).toHaveBeenNthCalledWith(1, 123, 123), +).type.toRaiseError(); + +expect( + jestExpect(jest.fn()).toHaveBeenNthCalledWith(1), +).type.toBeVoid(); +expect( + jestExpect(jest.fn()).toHaveBeenNthCalledWith(1, 123), +).type.toBeVoid(); +expect( + jestExpect(jest.fn()).toHaveBeenNthCalledWith( + 1, + 123, + 'value', + ), +).type.toBeVoid(); +expect( + jestExpect(jest.fn()).toHaveBeenNthCalledWith( + 1, + 123, + true, + ), +).type.toBeVoid(); +expect( + jestExpect(jest.fn()).toHaveBeenNthCalledWith(1, 123, 123), +).type.toRaiseError(); +expect( + jestExpect(jest.fn()).toHaveBeenNthCalledWith(1, 'value'), +).type.toRaiseError(); +expect( + jestExpect(jest.fn()).toHaveBeenNthCalledWith(1, true), +).type.toRaiseError(); +expect( + jestExpect(jest.fn()).toHaveBeenNthCalledWith( + 1, + 'value', + 'value', + ), +).type.toRaiseError(); +expect( + jestExpect(jest.fn()).toHaveBeenNthCalledWith( + 1, + true, + false, + ), +).type.toRaiseError(); + +expect( + jestExpect( + jest.fn<(date: Date, name?: [string, string]) => void>(), + ).toHaveBeenNthCalledWith(1, jestExpect.any(Date), [ + jestExpect.any(String), + jestExpect.any(String), + ]), +).type.toBeVoid(); +expect( + jestExpect( + jest.fn<(date: Date, name?: [string, string]) => void>(), + ).toHaveBeenNthCalledWith(1, jestExpect.any(Date), jestExpect.any(Array)), +).type.toBeVoid(); +expect( + jestExpect( + jest.fn<(date: Date, name?: [string, string]) => void>(), + ).toHaveBeenNthCalledWith(1, jestExpect.any(Date)), +).type.toBeVoid(); +expect( + jestExpect( + jest.fn<(date: Date, name?: [string, string]) => void>(), + ).toHaveBeenNthCalledWith(1, jestExpect.any(Date), []), +).type.toRaiseError(); +expect( + jestExpect( + jest.fn<(date: Date, name?: [string, string]) => void>(), + ).toHaveBeenNthCalledWith(1, jestExpect.any(Date), [jestExpect.any(String)]), +).type.toRaiseError(); +expect( + jestExpect( + jest.fn<(date: Date, name?: [string, string]) => void>(), + ).toHaveBeenNthCalledWith(1, jestExpect.any(Date), [ + jestExpect.any(String), + 123, + ]), +).type.toRaiseError(); + +expect( + jestExpect( + jest.fn<(date: Date, name: {foo: string}) => void>(), + ).toHaveBeenNthCalledWith(1, jestExpect.any(Date), { + foo: jestExpect.any(String), + }), +).type.toBeVoid(); +expect( + jestExpect( + jest.fn<(date: Date, name: {foo: string}) => void>(), + ).toHaveBeenNthCalledWith(1, jestExpect.any(Date), jestExpect.any(Object)), +).type.toBeVoid(); +expect( + jestExpect( + jest.fn<(date: Date, name: {foo: string}) => void>(), + ).toHaveBeenNthCalledWith(1, jestExpect.any(Date)), +).type.toRaiseError(); +expect( + jestExpect( + jest.fn<(date: Date, name: {foo: string}) => void>(), + ).toHaveBeenNthCalledWith(1, jestExpect.any(Date), { + bar: jestExpect.any(String), + }), +).type.toRaiseError(); +expect( + jestExpect( + jest.fn<(date: Date, name: {foo: string}) => void>(), + ).toHaveBeenNthCalledWith(1, jestExpect.any(Date), { + bar: jestExpect.any(String), + foo: jestExpect.any(String), + }), +).type.toRaiseError(); + +expect( + jestExpect( + jest.fn<(date: Date, name: [string, [string]]) => void>(), + ).toHaveBeenNthCalledWith(1, jestExpect.any(Date), [ + jestExpect.any(String), + [jestExpect.any(String)], + ]), +).type.toBeVoid(); +expect( + jestExpect( + jest.fn<(date: Date, name: [string, [string]]) => void>(), + ).toHaveBeenNthCalledWith(1, jestExpect.any(Date), [ + 'value', + [jestExpect.any(String)], + ]), +).type.toBeVoid(); +expect( + jestExpect( + jest.fn<(date: Date, name: [string, [string]]) => void>(), + ).toHaveBeenNthCalledWith(1, jestExpect.any(Date), [ + jestExpect.any(String), + ['value'], + ]), +).type.toBeVoid(); +expect( + jestExpect( + jest.fn<(date: Date, name: [string, [string]]) => void>(), + ).toHaveBeenNthCalledWith(1, jestExpect.any(Date), ['value', ['value']]), +).type.toBeVoid(); + expect(jestExpect(jest.fn()).toHaveReturned()).type.toBeVoid(); expect(jestExpect(jest.fn()).toHaveReturned('value')).type.toRaiseError(); expect(jestExpect(jest.fn()).toHaveReturned(false)).type.toRaiseError(); diff --git a/packages/jest-worker/src/__tests__/Farm.test.ts b/packages/jest-worker/src/__tests__/Farm.test.ts index 4a2268fb7f5d..6fb134839b98 100644 --- a/packages/jest-worker/src/__tests__/Farm.test.ts +++ b/packages/jest-worker/src/__tests__/Farm.test.ts @@ -120,7 +120,9 @@ describe('Farm', () => { }); it('handles null computeWorkerKey, sending to first worker', async () => { - const computeWorkerKey = jest.fn(() => null); + const computeWorkerKey = jest.fn< + (method: string, ...args: Array) => string | null + >(() => null); const farm = new Farm(4, callback, {computeWorkerKey}); @@ -144,7 +146,7 @@ describe('Farm', () => { it('sends the same worker key to the same worker', async () => { const computeWorkerKey = jest - .fn<() => string>() + .fn<(method: string, ...args: Array) => string | null>() .mockReturnValueOnce('one') .mockReturnValueOnce('two') .mockReturnValueOnce('one'); diff --git a/packages/jest-worker/src/base/__tests__/BaseWorkerPool.test.ts b/packages/jest-worker/src/base/__tests__/BaseWorkerPool.test.ts index a1fa6978f6db..0c67ce4892ef 100644 --- a/packages/jest-worker/src/base/__tests__/BaseWorkerPool.test.ts +++ b/packages/jest-worker/src/base/__tests__/BaseWorkerPool.test.ts @@ -13,7 +13,10 @@ import { } from '../../types'; import BaseWorkerPool from '../BaseWorkerPool'; -const Worker = jest.fn<(workerOptions: WorkerOptions) => WorkerInterface>(); +const Worker = + jest.fn< + (workerOptions: Omit) => WorkerInterface + >(); const mockSend = jest.fn();