Skip to content

Commit

Permalink
fix(@jest/types): infer each types correctly when the table is a tu…
Browse files Browse the repository at this point in the history
…ple or array (#13381)
  • Loading branch information
mrazauskas authored Oct 4, 2022
1 parent 86a810d commit 0555ba3
Show file tree
Hide file tree
Showing 5 changed files with 88 additions and 134 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
### Fixes

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

### Chore & Maintenance

Expand Down
49 changes: 23 additions & 26 deletions packages/jest-circus/src/__tests__/hooksError.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,31 +5,28 @@
* LICENSE file in the root directory of this source tree.
*/

import type {Circus} from '@jest/types';
import circus from '../';

describe.each([
'beforeEach',
'beforeAll',
'afterEach',
'afterAll',
] as Array<Circus.HookType>)('%s hooks error throwing', fn => {
test.each([
['String'],
[1],
[[]],
[{}],
[Symbol('hello')],
[true],
[null],
[undefined],
])(
`${fn} throws an error when %p is provided as a first argument to it`,
el => {
expect(() => {
// @ts-expect-error: Testing runtime errors here
circus[fn](el);
}).toThrow('Invalid first argument. It must be a callback function.');
},
);
});
describe.each(['beforeEach', 'beforeAll', 'afterEach', 'afterAll'] as const)(
'%s hooks error throwing',
fn => {
test.each([
['String'],
[1],
[[]],
[{}],
[Symbol('hello')],
[true],
[null],
[undefined],
])(
`${fn} throws an error when %p is provided as a first argument to it`,
el => {
expect(() => {
// @ts-expect-error: Testing runtime errors here
circus[fn](el);
}).toThrow('Invalid first argument. It must be a callback function.');
},
);
},
);
50 changes: 23 additions & 27 deletions packages/jest-jasmine2/src/__tests__/hooksError.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,30 +5,26 @@
* LICENSE file in the root directory of this source tree.
*/

export type SharedHookType = 'afterAll' | 'beforeAll';
export type HookType = SharedHookType | 'afterEach' | 'beforeEach';

describe.each([
'beforeEach',
'beforeAll',
'afterEach',
'afterAll',
] as Array<HookType>)('%s hooks error throwing', fn => {
test.each([
['String'],
[1],
[[]],
[{}],
[Symbol('hello')],
[true],
[null],
[undefined],
])(
`${fn} throws an error when %p is provided as a first argument to it`,
el => {
expect(() => {
globalThis[fn](el);
}).toThrow('Invalid first argument. It must be a callback function.');
},
);
});
describe.each(['beforeEach', 'beforeAll', 'afterEach', 'afterAll'] as const)(
'%s hooks error throwing',
fn => {
test.each([
['String'],
[1],
[[]],
[{}],
[Symbol('hello')],
[true],
[null],
[undefined],
])(
`${fn} throws an error when %p is provided as a first argument to it`,
el => {
expect(() => {
// @ts-expect-error: Testing runtime errors
globalThis[fn](el);
}).toThrow('Invalid first argument. It must be a callback function.');
},
);
},
);
106 changes: 33 additions & 73 deletions packages/jest-types/__typetests__/each.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {expectError, expectType} from 'tsd-lite';
import {describe, test} from '@jest/globals';

const list = [1, 2, 3];
const tupleList: [number, number, string] = [1, 2, 'three'];
const tupleList = ['one', 'two', 'three'] as const;
const table = [
[1, 2, 'three'],
[3, 4, 'seven'],
Expand All @@ -28,57 +28,41 @@ const objectTable = [
// test.each

expectType<void>(
test.each(list)('some test', (a, b, expected) => {
test.each(list)('some test', a => {
expectType<number>(a);
expectType<number>(b);
expectType<number>(expected);
}),
);
expectType<void>(
test.each(list)(
'some test',
(a, b, expected) => {
expectType<number>(a);
expectType<number>(b);
expectType<number>(expected);
},
1000,
),
test.each(list)('some test', a => {
expectType<number>(a);
}),
);

expectType<void>(
test.each(tupleList)('some test', (a, b, expected) => {
expectType<number>(a);
expectType<number>(b);
expectType<string>(expected);
test.each(tupleList)('some test', b => {
expectType<'one' | 'two' | 'three'>(b);
}),
);
expectType<void>(
test.each(tupleList)(
'some test',
(a, b, expected) => {
expectType<number>(a);
expectType<number>(b);
expectType<string>(expected);
b => {
expectType<'one' | 'two' | 'three'>(b);
},
1000,
),
);

expectType<void>(
test.each([3, 4, 'seven'])('some test', (a, b, expected) => {
expectType<number>(a);
expectType<number>(b);
expectType<string>(expected);
test.each([3, 4, 'seven'])('some test', c => {
expectType<string | number>(c);
}),
);
expectType<void>(
test.each([3, 4, 'seven'])(
'some test',
(a, b, expected) => {
expectType<number>(a);
expectType<number>(b);
expectType<string>(expected);
c => {
expectType<string | number>(c);
},
1000,
),
Expand Down Expand Up @@ -261,57 +245,45 @@ expectType<typeof test.each>(test.skip.each);
// test.concurrent.each

expectType<void>(
test.concurrent.each(list)('some test', async (a, b, expected) => {
test.concurrent.each(list)('some test', async a => {
expectType<number>(a);
expectType<number>(b);
expectType<number>(expected);
}),
);
expectType<void>(
test.concurrent.each(list)(
'some test',
async (a, b, expected) => {
async a => {
expectType<number>(a);
expectType<number>(b);
expectType<number>(expected);
},
1000,
),
);

expectType<void>(
test.concurrent.each(tupleList)('some test', async (a, b, expected) => {
expectType<number>(a);
expectType<number>(b);
expectType<string>(expected);
test.concurrent.each(tupleList)('some test', async b => {
expectType<'one' | 'two' | 'three'>(b);
}),
);
expectType<void>(
test.concurrent.each(tupleList)(
'some test',
async (a, b, expected) => {
expectType<number>(a);
expectType<number>(b);
expectType<string>(expected);
async b => {
expectType<'one' | 'two' | 'three'>(b);
},
1000,
),
);

expectType<void>(
test.concurrent.each([3, 4, 'seven'])('some test', async (a, b, expected) => {
expectType<number>(a);
expectType<number>(b);
expectType<string>(expected);
test.concurrent.each([3, 4, 'seven'])('some test', async c => {
expectType<string | number>(c);
}),
);
expectType<void>(
test.concurrent.each([3, 4, 'seven'])(
'some test',
async (a, b, expected) => {
expectType<number>(a);
expectType<number>(b);
expectType<string>(expected);
async c => {
expectType<string | number>(c);
},
1000,
),
Expand Down Expand Up @@ -448,57 +420,45 @@ expectType<typeof test.concurrent.each>(test.concurrent.skip.each);
// describe.each

expectType<void>(
describe.each(list)('describe each', (a, b, expected) => {
describe.each(list)('describe each', a => {
expectType<number>(a);
expectType<number>(b);
expectType<number>(expected);
}),
);
expectType<void>(
describe.each(list)(
'describe each',
(a, b, expected) => {
a => {
expectType<number>(a);
expectType<number>(b);
expectType<number>(expected);
},
1000,
),
);

expectType<void>(
describe.each(tupleList)('describe each', (a, b, expected) => {
expectType<number>(a);
expectType<number>(b);
expectType<string>(expected);
describe.each(tupleList)('describe each', b => {
expectType<'one' | 'two' | 'three'>(b);
}),
);
expectType<void>(
describe.each(tupleList)(
'describe each',
(a, b, expected) => {
expectType<number>(a);
expectType<number>(b);
expectType<string>(expected);
b => {
expectType<'one' | 'two' | 'three'>(b);
},
1000,
),
);

expectType<void>(
describe.each([3, 4, 'seven'])('describe each', (a, b, expected) => {
expectType<number>(a);
expectType<number>(b);
expectType<string>(expected);
describe.each([3, 4, 'seven'])('describe each', c => {
expectType<string | number>(c);
}),
);
expectType<void>(
describe.each([3, 4, 'seven'])(
'describe each',
(a, b, expected) => {
expectType<number>(a);
expectType<number>(b);
expectType<string>(expected);
c => {
expectType<string | number>(c);
},
1000,
),
Expand Down
16 changes: 8 additions & 8 deletions packages/jest-types/src/Global.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,42 +56,42 @@ export type EachTestFn<EachCallback extends TestCallback> = (
) => ReturnType<EachCallback>;

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

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

<T extends readonly [unknown, ...Array<unknown>]>(table: T): (
name: string | NameLike,
fn: (...args: T) => ReturnType<EachFn>,
timeout?: number,
) => void;

// when the table is an array of arrays
<T extends ReadonlyArray<unknown>>(table: ReadonlyArray<T>): (
name: string | NameLike,
fn: (...args: T) => ReturnType<EachFn>,
timeout?: number,
) => void;

<T extends ReadonlyArray<unknown>>(table: T): (
// when the table is a tuple or array
<T>(table: ReadonlyArray<T>): (
name: string | NameLike,
fn: (...args: T) => ReturnType<EachFn>,
fn: (arg: T) => ReturnType<EachFn>,
timeout?: number,
) => void;

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

// when the table is a template literal with a type argument
<T extends Record<string, unknown>>(
strings: TemplateStringsArray,
...expressions: Array<unknown>
Expand Down

0 comments on commit 0555ba3

Please sign in to comment.