Skip to content

Commit 0555ba3

Browse files
authored
fix(@jest/types): infer each types correctly when the table is a tuple or array (#13381)
1 parent 86a810d commit 0555ba3

File tree

5 files changed

+88
-134
lines changed

5 files changed

+88
-134
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
### Fixes
1010

1111
- `[babel-plugin-jest-hoist]` Ignore `TSTypeQuery` when checking for hoisted references ([#13367](https://github.com/facebook/jest/pull/13367))
12+
- `[@jest/types]` Infer type of `each` table correctly when the table is a tuple or array ([#13381](https://github.com/facebook/jest/pull/13381))
1213

1314
### Chore & Maintenance
1415

packages/jest-circus/src/__tests__/hooksError.test.ts

Lines changed: 23 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -5,31 +5,28 @@
55
* LICENSE file in the root directory of this source tree.
66
*/
77

8-
import type {Circus} from '@jest/types';
98
import circus from '../';
109

11-
describe.each([
12-
'beforeEach',
13-
'beforeAll',
14-
'afterEach',
15-
'afterAll',
16-
] as Array<Circus.HookType>)('%s hooks error throwing', fn => {
17-
test.each([
18-
['String'],
19-
[1],
20-
[[]],
21-
[{}],
22-
[Symbol('hello')],
23-
[true],
24-
[null],
25-
[undefined],
26-
])(
27-
`${fn} throws an error when %p is provided as a first argument to it`,
28-
el => {
29-
expect(() => {
30-
// @ts-expect-error: Testing runtime errors here
31-
circus[fn](el);
32-
}).toThrow('Invalid first argument. It must be a callback function.');
33-
},
34-
);
35-
});
10+
describe.each(['beforeEach', 'beforeAll', 'afterEach', 'afterAll'] as const)(
11+
'%s hooks error throwing',
12+
fn => {
13+
test.each([
14+
['String'],
15+
[1],
16+
[[]],
17+
[{}],
18+
[Symbol('hello')],
19+
[true],
20+
[null],
21+
[undefined],
22+
])(
23+
`${fn} throws an error when %p is provided as a first argument to it`,
24+
el => {
25+
expect(() => {
26+
// @ts-expect-error: Testing runtime errors here
27+
circus[fn](el);
28+
}).toThrow('Invalid first argument. It must be a callback function.');
29+
},
30+
);
31+
},
32+
);

packages/jest-jasmine2/src/__tests__/hooksError.test.ts

Lines changed: 23 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -5,30 +5,26 @@
55
* LICENSE file in the root directory of this source tree.
66
*/
77

8-
export type SharedHookType = 'afterAll' | 'beforeAll';
9-
export type HookType = SharedHookType | 'afterEach' | 'beforeEach';
10-
11-
describe.each([
12-
'beforeEach',
13-
'beforeAll',
14-
'afterEach',
15-
'afterAll',
16-
] as Array<HookType>)('%s hooks error throwing', fn => {
17-
test.each([
18-
['String'],
19-
[1],
20-
[[]],
21-
[{}],
22-
[Symbol('hello')],
23-
[true],
24-
[null],
25-
[undefined],
26-
])(
27-
`${fn} throws an error when %p is provided as a first argument to it`,
28-
el => {
29-
expect(() => {
30-
globalThis[fn](el);
31-
}).toThrow('Invalid first argument. It must be a callback function.');
32-
},
33-
);
34-
});
8+
describe.each(['beforeEach', 'beforeAll', 'afterEach', 'afterAll'] as const)(
9+
'%s hooks error throwing',
10+
fn => {
11+
test.each([
12+
['String'],
13+
[1],
14+
[[]],
15+
[{}],
16+
[Symbol('hello')],
17+
[true],
18+
[null],
19+
[undefined],
20+
])(
21+
`${fn} throws an error when %p is provided as a first argument to it`,
22+
el => {
23+
expect(() => {
24+
// @ts-expect-error: Testing runtime errors
25+
globalThis[fn](el);
26+
}).toThrow('Invalid first argument. It must be a callback function.');
27+
},
28+
);
29+
},
30+
);

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

Lines changed: 33 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import {expectError, expectType} from 'tsd-lite';
99
import {describe, test} from '@jest/globals';
1010

1111
const list = [1, 2, 3];
12-
const tupleList: [number, number, string] = [1, 2, 'three'];
12+
const tupleList = ['one', 'two', 'three'] as const;
1313
const table = [
1414
[1, 2, 'three'],
1515
[3, 4, 'seven'],
@@ -28,57 +28,41 @@ const objectTable = [
2828
// test.each
2929

3030
expectType<void>(
31-
test.each(list)('some test', (a, b, expected) => {
31+
test.each(list)('some test', a => {
3232
expectType<number>(a);
33-
expectType<number>(b);
34-
expectType<number>(expected);
3533
}),
3634
);
3735
expectType<void>(
38-
test.each(list)(
39-
'some test',
40-
(a, b, expected) => {
41-
expectType<number>(a);
42-
expectType<number>(b);
43-
expectType<number>(expected);
44-
},
45-
1000,
46-
),
36+
test.each(list)('some test', a => {
37+
expectType<number>(a);
38+
}),
4739
);
4840

4941
expectType<void>(
50-
test.each(tupleList)('some test', (a, b, expected) => {
51-
expectType<number>(a);
52-
expectType<number>(b);
53-
expectType<string>(expected);
42+
test.each(tupleList)('some test', b => {
43+
expectType<'one' | 'two' | 'three'>(b);
5444
}),
5545
);
5646
expectType<void>(
5747
test.each(tupleList)(
5848
'some test',
59-
(a, b, expected) => {
60-
expectType<number>(a);
61-
expectType<number>(b);
62-
expectType<string>(expected);
49+
b => {
50+
expectType<'one' | 'two' | 'three'>(b);
6351
},
6452
1000,
6553
),
6654
);
6755

6856
expectType<void>(
69-
test.each([3, 4, 'seven'])('some test', (a, b, expected) => {
70-
expectType<number>(a);
71-
expectType<number>(b);
72-
expectType<string>(expected);
57+
test.each([3, 4, 'seven'])('some test', c => {
58+
expectType<string | number>(c);
7359
}),
7460
);
7561
expectType<void>(
7662
test.each([3, 4, 'seven'])(
7763
'some test',
78-
(a, b, expected) => {
79-
expectType<number>(a);
80-
expectType<number>(b);
81-
expectType<string>(expected);
64+
c => {
65+
expectType<string | number>(c);
8266
},
8367
1000,
8468
),
@@ -261,57 +245,45 @@ expectType<typeof test.each>(test.skip.each);
261245
// test.concurrent.each
262246

263247
expectType<void>(
264-
test.concurrent.each(list)('some test', async (a, b, expected) => {
248+
test.concurrent.each(list)('some test', async a => {
265249
expectType<number>(a);
266-
expectType<number>(b);
267-
expectType<number>(expected);
268250
}),
269251
);
270252
expectType<void>(
271253
test.concurrent.each(list)(
272254
'some test',
273-
async (a, b, expected) => {
255+
async a => {
274256
expectType<number>(a);
275-
expectType<number>(b);
276-
expectType<number>(expected);
277257
},
278258
1000,
279259
),
280260
);
281261

282262
expectType<void>(
283-
test.concurrent.each(tupleList)('some test', async (a, b, expected) => {
284-
expectType<number>(a);
285-
expectType<number>(b);
286-
expectType<string>(expected);
263+
test.concurrent.each(tupleList)('some test', async b => {
264+
expectType<'one' | 'two' | 'three'>(b);
287265
}),
288266
);
289267
expectType<void>(
290268
test.concurrent.each(tupleList)(
291269
'some test',
292-
async (a, b, expected) => {
293-
expectType<number>(a);
294-
expectType<number>(b);
295-
expectType<string>(expected);
270+
async b => {
271+
expectType<'one' | 'two' | 'three'>(b);
296272
},
297273
1000,
298274
),
299275
);
300276

301277
expectType<void>(
302-
test.concurrent.each([3, 4, 'seven'])('some test', async (a, b, expected) => {
303-
expectType<number>(a);
304-
expectType<number>(b);
305-
expectType<string>(expected);
278+
test.concurrent.each([3, 4, 'seven'])('some test', async c => {
279+
expectType<string | number>(c);
306280
}),
307281
);
308282
expectType<void>(
309283
test.concurrent.each([3, 4, 'seven'])(
310284
'some test',
311-
async (a, b, expected) => {
312-
expectType<number>(a);
313-
expectType<number>(b);
314-
expectType<string>(expected);
285+
async c => {
286+
expectType<string | number>(c);
315287
},
316288
1000,
317289
),
@@ -448,57 +420,45 @@ expectType<typeof test.concurrent.each>(test.concurrent.skip.each);
448420
// describe.each
449421

450422
expectType<void>(
451-
describe.each(list)('describe each', (a, b, expected) => {
423+
describe.each(list)('describe each', a => {
452424
expectType<number>(a);
453-
expectType<number>(b);
454-
expectType<number>(expected);
455425
}),
456426
);
457427
expectType<void>(
458428
describe.each(list)(
459429
'describe each',
460-
(a, b, expected) => {
430+
a => {
461431
expectType<number>(a);
462-
expectType<number>(b);
463-
expectType<number>(expected);
464432
},
465433
1000,
466434
),
467435
);
468436

469437
expectType<void>(
470-
describe.each(tupleList)('describe each', (a, b, expected) => {
471-
expectType<number>(a);
472-
expectType<number>(b);
473-
expectType<string>(expected);
438+
describe.each(tupleList)('describe each', b => {
439+
expectType<'one' | 'two' | 'three'>(b);
474440
}),
475441
);
476442
expectType<void>(
477443
describe.each(tupleList)(
478444
'describe each',
479-
(a, b, expected) => {
480-
expectType<number>(a);
481-
expectType<number>(b);
482-
expectType<string>(expected);
445+
b => {
446+
expectType<'one' | 'two' | 'three'>(b);
483447
},
484448
1000,
485449
),
486450
);
487451

488452
expectType<void>(
489-
describe.each([3, 4, 'seven'])('describe each', (a, b, expected) => {
490-
expectType<number>(a);
491-
expectType<number>(b);
492-
expectType<string>(expected);
453+
describe.each([3, 4, 'seven'])('describe each', c => {
454+
expectType<string | number>(c);
493455
}),
494456
);
495457
expectType<void>(
496458
describe.each([3, 4, 'seven'])(
497459
'describe each',
498-
(a, b, expected) => {
499-
expectType<number>(a);
500-
expectType<number>(b);
501-
expectType<string>(expected);
460+
c => {
461+
expectType<string | number>(c);
502462
},
503463
1000,
504464
),

packages/jest-types/src/Global.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -56,42 +56,42 @@ export type EachTestFn<EachCallback extends TestCallback> = (
5656
) => ReturnType<EachCallback>;
5757

5858
interface Each<EachFn extends TestFn | BlockFn> {
59+
// when the table is an array of object literals
5960
<T extends Record<string, unknown>>(table: ReadonlyArray<T>): (
6061
name: string | NameLike,
6162
fn: (arg: T) => ReturnType<EachFn>,
6263
timeout?: number,
6364
) => void;
6465

66+
// when the table is an array of tuples
6567
<T extends readonly [unknown, ...Array<unknown>]>(table: ReadonlyArray<T>): (
6668
name: string | NameLike,
6769
fn: (...args: T) => ReturnType<EachFn>,
6870
timeout?: number,
6971
) => void;
7072

71-
<T extends readonly [unknown, ...Array<unknown>]>(table: T): (
72-
name: string | NameLike,
73-
fn: (...args: T) => ReturnType<EachFn>,
74-
timeout?: number,
75-
) => void;
76-
73+
// when the table is an array of arrays
7774
<T extends ReadonlyArray<unknown>>(table: ReadonlyArray<T>): (
7875
name: string | NameLike,
7976
fn: (...args: T) => ReturnType<EachFn>,
8077
timeout?: number,
8178
) => void;
8279

83-
<T extends ReadonlyArray<unknown>>(table: T): (
80+
// when the table is a tuple or array
81+
<T>(table: ReadonlyArray<T>): (
8482
name: string | NameLike,
85-
fn: (...args: T) => ReturnType<EachFn>,
83+
fn: (arg: T) => ReturnType<EachFn>,
8684
timeout?: number,
8785
) => void;
8886

87+
// when the table is a template literal
8988
<T = unknown>(strings: TemplateStringsArray, ...expressions: Array<T>): (
9089
name: string | NameLike,
9190
fn: (arg: Record<string, T>) => ReturnType<EachFn>,
9291
timeout?: number,
9392
) => void;
9493

94+
// when the table is a template literal with a type argument
9595
<T extends Record<string, unknown>>(
9696
strings: TemplateStringsArray,
9797
...expressions: Array<unknown>

0 commit comments

Comments
 (0)