diff --git a/CHANGELOG.md b/CHANGELOG.md index 120c4e01b9eb..692e7867bc51 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/packages/jest-circus/src/__tests__/hooksError.test.ts b/packages/jest-circus/src/__tests__/hooksError.test.ts index 3e38747b0c6d..a7a08414d43e 100644 --- a/packages/jest-circus/src/__tests__/hooksError.test.ts +++ b/packages/jest-circus/src/__tests__/hooksError.test.ts @@ -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)('%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.'); + }, + ); + }, +); diff --git a/packages/jest-jasmine2/src/__tests__/hooksError.test.ts b/packages/jest-jasmine2/src/__tests__/hooksError.test.ts index 3355b74dda64..35dc072922b6 100644 --- a/packages/jest-jasmine2/src/__tests__/hooksError.test.ts +++ b/packages/jest-jasmine2/src/__tests__/hooksError.test.ts @@ -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)('%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.'); + }, + ); + }, +); diff --git a/packages/jest-types/__typetests__/each.test.ts b/packages/jest-types/__typetests__/each.test.ts index 147153b3b914..3c9212ca5ed4 100644 --- a/packages/jest-types/__typetests__/each.test.ts +++ b/packages/jest-types/__typetests__/each.test.ts @@ -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'], @@ -28,57 +28,41 @@ const objectTable = [ // test.each expectType( - test.each(list)('some test', (a, b, expected) => { + test.each(list)('some test', a => { expectType(a); - expectType(b); - expectType(expected); }), ); expectType( - test.each(list)( - 'some test', - (a, b, expected) => { - expectType(a); - expectType(b); - expectType(expected); - }, - 1000, - ), + test.each(list)('some test', a => { + expectType(a); + }), ); expectType( - test.each(tupleList)('some test', (a, b, expected) => { - expectType(a); - expectType(b); - expectType(expected); + test.each(tupleList)('some test', b => { + expectType<'one' | 'two' | 'three'>(b); }), ); expectType( test.each(tupleList)( 'some test', - (a, b, expected) => { - expectType(a); - expectType(b); - expectType(expected); + b => { + expectType<'one' | 'two' | 'three'>(b); }, 1000, ), ); expectType( - test.each([3, 4, 'seven'])('some test', (a, b, expected) => { - expectType(a); - expectType(b); - expectType(expected); + test.each([3, 4, 'seven'])('some test', c => { + expectType(c); }), ); expectType( test.each([3, 4, 'seven'])( 'some test', - (a, b, expected) => { - expectType(a); - expectType(b); - expectType(expected); + c => { + expectType(c); }, 1000, ), @@ -261,57 +245,45 @@ expectType(test.skip.each); // test.concurrent.each expectType( - test.concurrent.each(list)('some test', async (a, b, expected) => { + test.concurrent.each(list)('some test', async a => { expectType(a); - expectType(b); - expectType(expected); }), ); expectType( test.concurrent.each(list)( 'some test', - async (a, b, expected) => { + async a => { expectType(a); - expectType(b); - expectType(expected); }, 1000, ), ); expectType( - test.concurrent.each(tupleList)('some test', async (a, b, expected) => { - expectType(a); - expectType(b); - expectType(expected); + test.concurrent.each(tupleList)('some test', async b => { + expectType<'one' | 'two' | 'three'>(b); }), ); expectType( test.concurrent.each(tupleList)( 'some test', - async (a, b, expected) => { - expectType(a); - expectType(b); - expectType(expected); + async b => { + expectType<'one' | 'two' | 'three'>(b); }, 1000, ), ); expectType( - test.concurrent.each([3, 4, 'seven'])('some test', async (a, b, expected) => { - expectType(a); - expectType(b); - expectType(expected); + test.concurrent.each([3, 4, 'seven'])('some test', async c => { + expectType(c); }), ); expectType( test.concurrent.each([3, 4, 'seven'])( 'some test', - async (a, b, expected) => { - expectType(a); - expectType(b); - expectType(expected); + async c => { + expectType(c); }, 1000, ), @@ -448,57 +420,45 @@ expectType(test.concurrent.skip.each); // describe.each expectType( - describe.each(list)('describe each', (a, b, expected) => { + describe.each(list)('describe each', a => { expectType(a); - expectType(b); - expectType(expected); }), ); expectType( describe.each(list)( 'describe each', - (a, b, expected) => { + a => { expectType(a); - expectType(b); - expectType(expected); }, 1000, ), ); expectType( - describe.each(tupleList)('describe each', (a, b, expected) => { - expectType(a); - expectType(b); - expectType(expected); + describe.each(tupleList)('describe each', b => { + expectType<'one' | 'two' | 'three'>(b); }), ); expectType( describe.each(tupleList)( 'describe each', - (a, b, expected) => { - expectType(a); - expectType(b); - expectType(expected); + b => { + expectType<'one' | 'two' | 'three'>(b); }, 1000, ), ); expectType( - describe.each([3, 4, 'seven'])('describe each', (a, b, expected) => { - expectType(a); - expectType(b); - expectType(expected); + describe.each([3, 4, 'seven'])('describe each', c => { + expectType(c); }), ); expectType( describe.each([3, 4, 'seven'])( 'describe each', - (a, b, expected) => { - expectType(a); - expectType(b); - expectType(expected); + c => { + expectType(c); }, 1000, ), diff --git a/packages/jest-types/src/Global.ts b/packages/jest-types/src/Global.ts index 0aa451f5ea98..6a1bbecb235a 100644 --- a/packages/jest-types/src/Global.ts +++ b/packages/jest-types/src/Global.ts @@ -56,42 +56,42 @@ export type EachTestFn = ( ) => ReturnType; interface Each { + // when the table is an array of object literals >(table: ReadonlyArray): ( name: string | NameLike, fn: (arg: T) => ReturnType, timeout?: number, ) => void; + // when the table is an array of tuples ]>(table: ReadonlyArray): ( name: string | NameLike, fn: (...args: T) => ReturnType, timeout?: number, ) => void; - ]>(table: T): ( - name: string | NameLike, - fn: (...args: T) => ReturnType, - timeout?: number, - ) => void; - + // when the table is an array of arrays >(table: ReadonlyArray): ( name: string | NameLike, fn: (...args: T) => ReturnType, timeout?: number, ) => void; - >(table: T): ( + // when the table is a tuple or array + (table: ReadonlyArray): ( name: string | NameLike, - fn: (...args: T) => ReturnType, + fn: (arg: T) => ReturnType, timeout?: number, ) => void; + // when the table is a template literal (strings: TemplateStringsArray, ...expressions: Array): ( name: string | NameLike, fn: (arg: Record) => ReturnType, timeout?: number, ) => void; + // when the table is a template literal with a type argument >( strings: TemplateStringsArray, ...expressions: Array