Skip to content

Commit be0d4d1

Browse files
authored
fix(expect, @jest/expect): do not infer argument types of *CalledWith and *ReturnedWith matchers (#13339)
1 parent e574964 commit be0d4d1

File tree

5 files changed

+96
-81
lines changed

5 files changed

+96
-81
lines changed

CHANGELOG.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
### Fixes
66

7+
- `[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))
8+
79
### Chore & Maintenance
810

911
### Performance
@@ -18,7 +20,7 @@
1820

1921
### Features
2022

21-
- `[expect, @jest/expect]` support type inference for function parameters in `CalledWith` assertions ([#13268](https://github.com/facebook/jest/pull/13268))
23+
- `[expect, @jest/expect]` Support type inference for function parameters in `CalledWith` assertions ([#13268](https://github.com/facebook/jest/pull/13268))
2224
- `[expect, @jest/expect]` Infer type of `*ReturnedWith` matchers argument ([#13278](https://github.com/facebook/jest/pull/13278))
2325
- `[@jest/environment, jest-runtime]` Allow `jest.requireActual` and `jest.requireMock` to take a type argument ([#13253](https://github.com/facebook/jest/pull/13253))
2426
- `[@jest/environment]` Allow `jest.mock` and `jest.doMock` to take a type argument ([#13254](https://github.com/facebook/jest/pull/13254))

packages/expect/__typetests__/expect.test.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,7 @@ import {
1616
} from 'expect';
1717
import type * as jestMatcherUtils from 'jest-matcher-utils';
1818

19-
type M = Matchers<void, unknown>;
20-
type N = Matchers<void>;
19+
type M = Matchers<void>;
2120

2221
expectError(() => {
2322
type E = Matchers;

packages/expect/src/types.ts

Lines changed: 19 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -94,9 +94,9 @@ export interface BaseExpect {
9494
}
9595

9696
export type Expect = {
97-
<T = unknown>(actual: T): Matchers<void, T> &
98-
Inverse<Matchers<void, T>> &
99-
PromiseMatchers<T>;
97+
<T = unknown>(actual: T): Matchers<void> &
98+
Inverse<Matchers<void>> &
99+
PromiseMatchers;
100100
} & BaseExpect &
101101
AsymmetricMatchers &
102102
Inverse<Omit<AsymmetricMatchers, 'any' | 'anything'>>;
@@ -118,38 +118,36 @@ export interface AsymmetricMatchers {
118118
stringMatching(sample: string | RegExp): AsymmetricMatcher;
119119
}
120120

121-
type PromiseMatchers<T = unknown> = {
121+
type PromiseMatchers = {
122122
/**
123123
* Unwraps the reason of a rejected promise so any other matcher can be chained.
124124
* If the promise is fulfilled the assertion fails.
125125
*/
126-
rejects: Matchers<Promise<void>> & Inverse<Matchers<Promise<void>, T>>;
126+
rejects: Matchers<Promise<void>> & Inverse<Matchers<Promise<void>>>;
127127
/**
128128
* Unwraps the value of a fulfilled promise so any other matcher can be chained.
129129
* If the promise is rejected the assertion fails.
130130
*/
131-
resolves: Matchers<Promise<void>> & Inverse<Matchers<Promise<void>, T>>;
131+
resolves: Matchers<Promise<void>> & Inverse<Matchers<Promise<void>>>;
132132
};
133133

134-
type EnsureFunctionLike<T> = T extends (...args: any) => any ? T : never;
135-
136-
export interface Matchers<R extends void | Promise<void>, T = unknown> {
134+
export interface Matchers<R extends void | Promise<void>> {
137135
/**
138136
* Ensures the last call to a mock function was provided specific args.
139137
*/
140-
lastCalledWith(...expected: Parameters<EnsureFunctionLike<T>>): R;
138+
lastCalledWith(...expected: Array<unknown>): R;
141139
/**
142140
* Ensure that the last call to a mock function has returned a specified value.
143141
*/
144-
lastReturnedWith(expected: ReturnType<EnsureFunctionLike<T>>): R;
142+
lastReturnedWith(expected: unknown): R;
145143
/**
146144
* Ensure that a mock function is called with specific arguments on an Nth call.
147145
*/
148-
nthCalledWith(nth: number, ...expected: Parameters<EnsureFunctionLike<T>>): R;
146+
nthCalledWith(nth: number, ...expected: Array<unknown>): R;
149147
/**
150148
* Ensure that the nth call to a mock function has returned a specified value.
151149
*/
152-
nthReturnedWith(nth: number, expected: ReturnType<EnsureFunctionLike<T>>): R;
150+
nthReturnedWith(nth: number, expected: unknown): R;
153151
/**
154152
* Checks that a value is what you expect. It calls `Object.is` to compare values.
155153
* Don't use `toBe` with floating-point numbers.
@@ -166,7 +164,7 @@ export interface Matchers<R extends void | Promise<void>, T = unknown> {
166164
/**
167165
* Ensure that a mock function is called with specific arguments.
168166
*/
169-
toBeCalledWith(...expected: Parameters<EnsureFunctionLike<T>>): R;
167+
toBeCalledWith(...expected: Array<unknown>): R;
170168
/**
171169
* Using exact equality with floating point numbers is a bad idea.
172170
* Rounding means that intuitive things fail.
@@ -249,25 +247,22 @@ export interface Matchers<R extends void | Promise<void>, T = unknown> {
249247
/**
250248
* Ensure that a mock function is called with specific arguments.
251249
*/
252-
toHaveBeenCalledWith(...expected: Parameters<EnsureFunctionLike<T>>): R;
250+
toHaveBeenCalledWith(...expected: Array<unknown>): R;
253251
/**
254252
* Ensure that a mock function is called with specific arguments on an Nth call.
255253
*/
256-
toHaveBeenNthCalledWith(
257-
nth: number,
258-
...expected: Parameters<EnsureFunctionLike<T>>
259-
): R;
254+
toHaveBeenNthCalledWith(nth: number, ...expected: Array<unknown>): R;
260255
/**
261256
* If you have a mock function, you can use `.toHaveBeenLastCalledWith`
262257
* to test what arguments it was last called with.
263258
*/
264-
toHaveBeenLastCalledWith(...expected: Parameters<EnsureFunctionLike<T>>): R;
259+
toHaveBeenLastCalledWith(...expected: Array<unknown>): R;
265260
/**
266261
* Use to test the specific value that a mock function last returned.
267262
* If the last call to the mock function threw an error, then this matcher will fail
268263
* no matter what value you provided as the expected return value.
269264
*/
270-
toHaveLastReturnedWith(expected: ReturnType<EnsureFunctionLike<T>>): R;
265+
toHaveLastReturnedWith(expected: unknown): R;
271266
/**
272267
* Used to check that an object has a `.length` property
273268
* and it is set to a certain numeric value.
@@ -278,10 +273,7 @@ export interface Matchers<R extends void | Promise<void>, T = unknown> {
278273
* If the nth call to the mock function threw an error, then this matcher will fail
279274
* no matter what value you provided as the expected return value.
280275
*/
281-
toHaveNthReturnedWith(
282-
nth: number,
283-
expected: ReturnType<EnsureFunctionLike<T>>,
284-
): R;
276+
toHaveNthReturnedWith(nth: number, expected: unknown): R;
285277
/**
286278
* Use to check if property at provided reference keyPath exists for an object.
287279
* For checking deeply nested properties in an object you may use dot notation or an array containing
@@ -311,7 +303,7 @@ export interface Matchers<R extends void | Promise<void>, T = unknown> {
311303
/**
312304
* Use to ensure that a mock function returned a specific value.
313305
*/
314-
toHaveReturnedWith(expected: ReturnType<EnsureFunctionLike<T>>): R;
306+
toHaveReturnedWith(expected: unknown): R;
315307
/**
316308
* Check that a string matches a regular expression.
317309
*/
@@ -333,7 +325,7 @@ export interface Matchers<R extends void | Promise<void>, T = unknown> {
333325
/**
334326
* Ensure that a mock function has returned a specified value at least once.
335327
*/
336-
toReturnWith(expected: ReturnType<EnsureFunctionLike<T>>): R;
328+
toReturnWith(expected: unknown): R;
337329
/**
338330
* Use to test that objects have the same types as well as structure.
339331
*/

packages/jest-expect/src/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ type Inverse<Matchers> = {
2929
not: Matchers;
3030
};
3131

32-
type JestMatchers<R extends void | Promise<void>, T> = Matchers<R, T> &
32+
type JestMatchers<R extends void | Promise<void>, T> = Matchers<R> &
3333
SnapshotMatchers<R, T>;
3434

3535
type PromiseMatchers<T = unknown> = {

packages/jest-types/__typetests__/expect.test.ts

Lines changed: 72 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -214,55 +214,65 @@ expectError(expect(jest.fn()).toHaveBeenCalledTimes());
214214
expectType<void>(expect(jest.fn()).toBeCalledWith());
215215
expectType<void>(expect(jest.fn()).toBeCalledWith('value'));
216216
expectType<void>(expect(jest.fn()).toBeCalledWith('value', 123));
217+
expectType<void>(
218+
expect(jest.fn<(a: string, b: number) => void>()).toBeCalledWith(
219+
expect.stringContaining('value'),
220+
123,
221+
),
222+
);
223+
217224
expectType<void>(expect(jest.fn()).toHaveBeenCalledWith());
218225
expectType<void>(expect(jest.fn()).toHaveBeenCalledWith(123));
219226
expectType<void>(expect(jest.fn()).toHaveBeenCalledWith(123, 'value'));
220-
221-
/**
222-
* type inference for "CalledWith" matchers parameters
223-
*/
224-
expectError(expect(jest.fn<(a: string) => void>()).toHaveBeenCalledWith(123));
225-
expectError(
226-
expect(jest.fn<(a: string) => void>()).toHaveBeenNthCalledWith(1, 123),
227-
);
228-
expectError(
229-
expect(jest.fn<(a: string) => void>()).toHaveBeenLastCalledWith(123),
230-
);
231-
expectType<void>(
232-
expect(
233-
jest.fn<(a: string, b: number, c?: boolean) => void>(),
234-
).toHaveBeenCalledWith('value', 123),
235-
);
236227
expectType<void>(
237-
expect(
238-
jest.fn<(a: string, b: number, c?: boolean) => void>(),
239-
).toHaveBeenCalledWith('value', 123, true),
240-
);
241-
expectError(
242-
expect(
243-
jest.fn<(a: string, b: number, c?: boolean) => void>(),
244-
).toHaveBeenCalledWith(123, 'value'),
245-
);
246-
expectError(
247-
expect(
248-
jest.fn<(a: string, b: number, c?: boolean) => void>(),
249-
).toHaveBeenCalledWith('value', 123, 'not a boolean'),
228+
expect(jest.fn<(a: string, b: number) => void>()).toHaveBeenCalledWith(
229+
expect.stringContaining('value'),
230+
123,
231+
),
250232
);
251233

252234
expectType<void>(expect(jest.fn()).lastCalledWith());
253235
expectType<void>(expect(jest.fn()).lastCalledWith('value'));
254236
expectType<void>(expect(jest.fn()).lastCalledWith('value', 123));
237+
expectType<void>(
238+
expect(jest.fn<(a: string, b: number) => void>()).lastCalledWith(
239+
expect.stringContaining('value'),
240+
123,
241+
),
242+
);
243+
255244
expectType<void>(expect(jest.fn()).toHaveBeenLastCalledWith());
256245
expectType<void>(expect(jest.fn()).toHaveBeenLastCalledWith(123));
257246
expectType<void>(expect(jest.fn()).toHaveBeenLastCalledWith(123, 'value'));
247+
expectType<void>(
248+
expect(jest.fn<(a: string, b: number) => void>()).lastCalledWith(
249+
expect.stringContaining('value'),
250+
123,
251+
),
252+
);
258253

259254
expectType<void>(expect(jest.fn()).nthCalledWith(2));
260255
expectType<void>(expect(jest.fn()).nthCalledWith(1, 'value'));
261256
expectType<void>(expect(jest.fn()).nthCalledWith(1, 'value', 123));
257+
expectType<void>(
258+
expect(jest.fn<(a: string, b: number) => void>()).nthCalledWith(
259+
1,
260+
expect.stringContaining('value'),
261+
123,
262+
),
263+
);
262264
expectError(expect(jest.fn()).nthCalledWith());
265+
263266
expectType<void>(expect(jest.fn()).toHaveBeenNthCalledWith(2));
264267
expectType<void>(expect(jest.fn()).toHaveBeenNthCalledWith(1, 'value'));
265268
expectType<void>(expect(jest.fn()).toHaveBeenNthCalledWith(1, 'value', 123));
269+
expectType<void>(
270+
expect(jest.fn<(a: string, b: number) => void>()).toHaveBeenNthCalledWith(
271+
1,
272+
expect.stringContaining('value'),
273+
123,
274+
),
275+
);
266276
expectError(expect(jest.fn()).toHaveBeenNthCalledWith());
267277

268278
expectType<void>(expect(jest.fn()).toReturn());
@@ -278,43 +288,55 @@ expectError(expect(jest.fn()).toHaveReturnedTimes(true));
278288
expectError(expect(jest.fn()).toHaveReturnedTimes());
279289

280290
expectType<void>(expect(jest.fn()).toReturnWith('value'));
281-
expectType<void>(expect(jest.fn<() => string>()).toReturnWith('value'));
282-
expectError(expect(jest.fn<() => number>()).toReturnWith('value'));
283-
expectError(expect(123).toReturnWith('value'));
291+
expectType<void>(
292+
expect(jest.fn<() => string>()).toReturnWith(
293+
expect.stringContaining('value'),
294+
),
295+
);
284296
expectError(expect(jest.fn()).toReturnWith());
285297

286298
expectType<void>(expect(jest.fn()).toHaveReturnedWith(123));
287-
expectType<void>(expect(jest.fn<() => number>()).toHaveReturnedWith(123));
288-
expectError(expect(jest.fn<() => string>()).toHaveReturnedWith(123));
289-
expectError(expect(123).toHaveReturnedWith(123));
299+
expectType<void>(
300+
expect(jest.fn<() => string>()).toHaveReturnedWith(
301+
expect.stringContaining('value'),
302+
),
303+
);
290304
expectError(expect(jest.fn()).toHaveReturnedWith());
291305

292306
expectType<void>(expect(jest.fn()).lastReturnedWith('value'));
293-
expectType<void>(expect(jest.fn<() => string>()).lastReturnedWith('value'));
294-
expectError(expect(jest.fn<() => number>()).lastReturnedWith('value'));
295-
expectError(expect(123).lastReturnedWith('value'));
307+
expectType<void>(
308+
expect(jest.fn<() => string>()).lastReturnedWith(
309+
expect.stringContaining('value'),
310+
),
311+
);
296312
expectError(expect(jest.fn()).lastReturnedWith());
297313

298314
expectType<void>(expect(jest.fn()).toHaveLastReturnedWith(123));
299-
expectType<void>(expect(jest.fn<() => number>()).toHaveLastReturnedWith(123));
300-
expectError(expect(jest.fn<() => string>()).toHaveLastReturnedWith(123));
301-
expectError(expect(123).toHaveLastReturnedWith(123));
315+
expectType<void>(
316+
expect(jest.fn<() => string>()).toHaveLastReturnedWith(
317+
expect.stringContaining('value'),
318+
),
319+
);
302320
expectError(expect(jest.fn()).toHaveLastReturnedWith());
303321

304322
expectType<void>(expect(jest.fn()).nthReturnedWith(1, 'value'));
305-
expectType<void>(expect(jest.fn<() => string>()).nthReturnedWith(2, 'value'));
306-
expectError(expect(jest.fn<() => number>()).nthReturnedWith(3, 'value'));
307-
expectError(expect(123).nthReturnedWith(4, 'value'));
308-
expectError(expect(123).nthReturnedWith(5));
323+
expectType<void>(
324+
expect(jest.fn<() => string>()).nthReturnedWith(
325+
2,
326+
expect.stringContaining('value'),
327+
),
328+
);
329+
expectError(expect(123).nthReturnedWith(3));
309330
expectError(expect(jest.fn()).nthReturnedWith());
310331

311-
expectType<void>(expect(jest.fn()).toHaveNthReturnedWith(1, 'value'));
332+
expectType<void>(expect(jest.fn()).nthReturnedWith(1, 'value'));
312333
expectType<void>(
313-
expect(jest.fn<() => string>()).toHaveNthReturnedWith(2, 'value'),
334+
expect(jest.fn<() => string>()).nthReturnedWith(
335+
2,
336+
expect.stringContaining('value'),
337+
),
314338
);
315-
expectError(expect(jest.fn<() => number>()).toHaveNthReturnedWith(3, 'value'));
316-
expectError(expect(123).toHaveNthReturnedWith(4, 'value'));
317-
expectError(expect(123).toHaveNthReturnedWith(5));
339+
expectError(expect(123).toHaveNthReturnedWith(3));
318340
expectError(expect(jest.fn()).toHaveNthReturnedWith());
319341

320342
// snapshot matchers

0 commit comments

Comments
 (0)