Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allowed describe and it/test to take in functions again #12484

Merged
merged 18 commits into from Feb 24, 2022
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
13 changes: 7 additions & 6 deletions packages/jest-circus/src/index.ts
Expand Up @@ -7,24 +7,24 @@

import type {Circus, Global} from '@jest/types';
import {bind as bindEach} from 'jest-each';
import {ErrorWithStack, isPromise} from 'jest-util';
import {ErrorWithStack, convertDescriptorToString, isPromise} from 'jest-util';
import {dispatchSync} from './state';

export {setState, getState, resetState} from './state';
export {default as run} from './run';

type THook = (fn: Circus.HookFn, timeout?: number) => void;
type DescribeFn = (
blockName: Circus.BlockName,
blockName: Circus.BlockNameLike,
blockFn: Circus.BlockFn,
) => void;

const describe = (() => {
const describe = (blockName: Circus.BlockName, blockFn: Circus.BlockFn) =>
const describe = (blockName: Circus.BlockNameLike, blockFn: Circus.BlockFn) =>
_dispatchDescribe(blockFn, blockName, describe);
const only = (blockName: Circus.BlockName, blockFn: Circus.BlockFn) =>
const only = (blockName: Circus.BlockNameLike, blockFn: Circus.BlockFn) =>
_dispatchDescribe(blockFn, blockName, only, 'only');
const skip = (blockName: Circus.BlockName, blockFn: Circus.BlockFn) =>
const skip = (blockName: Circus.BlockNameLike, blockFn: Circus.BlockFn) =>
_dispatchDescribe(blockFn, blockName, skip, 'skip');

describe.each = bindEach(describe, false);
Expand All @@ -40,7 +40,7 @@ const describe = (() => {

const _dispatchDescribe = (
blockFn: Circus.BlockFn,
blockName: Circus.BlockName,
blockName: Circus.BlockNameLike,
describeFn: DescribeFn,
mode?: Circus.BlockMode,
) => {
Expand All @@ -54,6 +54,7 @@ const _dispatchDescribe = (
asyncError.message = `Invalid second argument, ${blockFn}. It must be a callback function.`;
throw asyncError;
}
blockName = convertDescriptorToString(blockName);
JoshuaKGoldberg marked this conversation as resolved.
Show resolved Hide resolved
dispatchSync({
asyncError,
blockName,
Expand Down
5 changes: 3 additions & 2 deletions packages/jest-each/src/bind.ts
Expand Up @@ -7,7 +7,7 @@
*/

import type {Global} from '@jest/types';
import {ErrorWithStack} from 'jest-util';
import {ErrorWithStack, convertDescriptorToString} from 'jest-util';
import convertArrayTable from './table/array';
import convertTemplateTable from './table/template';
import {
Expand Down Expand Up @@ -37,10 +37,11 @@ export default function bind<EachCallback extends Global.TestCallback>(
...taggedTemplateData: Global.TemplateData
) =>
function eachBind(
title: string,
title: Global.BlockNameLike,
test: Global.EachTestFn<EachCallback>,
timeout?: number,
): void {
title = convertDescriptorToString(title);
try {
const tests = isArrayTable(taggedTemplateData)
? buildArrayTests(title, table)
Expand Down
26 changes: 26 additions & 0 deletions packages/jest-types/__typetests__/globals.test.ts
Expand Up @@ -58,6 +58,7 @@ expectType<void>(beforeEach(fn, timeout));
expectType<void>(beforeEach(asyncFn, timeout));
expectType<void>(beforeEach(genFn, timeout));

expectType<void>(test(testName, fn));
expectType<void>(test(testName, fn));
expectType<void>(test(testName, asyncFn));
expectType<void>(test(testName, doneFn));
Expand Down Expand Up @@ -247,27 +248,52 @@ expectType<void>(
`(testName, asyncFn, timeout),
);

expectType<void>(describe(testName, fn));
expectType<void>(describe(123, fn));
expectType<void>(describe(() => {}, fn));
expectType<void>(describe(function named() {}, fn));
expectType<void>(describe(class {}, fn));
expectType<void>(describe(class Named {}, fn));

expectType<void>(describe.each(list)(testName, fn));
expectType<void>(describe.each(list)(testName, fn, timeout));
expectType<void>(describe.each(table)(testName, fn));
expectType<void>(describe.each(table)(testName, fn, timeout));
expectType<void>(describe.each(readonlyTable)(testName, fn));
expectType<void>(describe.each(readonlyTable)(testName, fn, timeout));

expectType<void>(describe.each(list)(testName, fn));
expectType<void>(describe.each(list)(123, fn));
expectType<void>(describe.each(list)(() => {}, fn));
expectType<void>(describe.each(list)(function named() {}, fn));
expectType<void>(describe.each(list)(class Named {}, fn));

expectType<void>(describe.only.each(list)(testName, fn));
expectType<void>(describe.only.each(list)(testName, fn, timeout));
expectType<void>(describe.only.each(table)(testName, fn));
expectType<void>(describe.only.each(table)(testName, fn, timeout));
expectType<void>(describe.only.each(readonlyTable)(testName, fn));
expectType<void>(describe.only.each(readonlyTable)(testName, fn, timeout));

expectType<void>(describe.only.each(list)(testName, fn));
expectType<void>(describe.only.each(list)(123, fn));
expectType<void>(describe.only.each(list)(() => {}, fn));
expectType<void>(describe.only.each(list)(function named() {}, fn));
expectType<void>(describe.only.each(list)(class Named {}, fn));

expectType<void>(describe.skip.each(list)(testName, fn));
expectType<void>(describe.skip.each(list)(testName, fn, timeout));
expectType<void>(describe.skip.each(table)(testName, fn));
expectType<void>(describe.skip.each(table)(testName, fn, timeout));
expectType<void>(describe.skip.each(readonlyTable)(testName, fn));
expectType<void>(describe.skip.each(readonlyTable)(testName, fn, timeout));

expectType<void>(describe.skip.each(list)(testName, fn));
expectType<void>(describe.skip.each(list)(123, fn));
expectType<void>(describe.skip.each(list)(() => {}, fn));
expectType<void>(describe.skip.each(list)(function named() {}, fn));
expectType<void>(describe.skip.each(list)(class Named {}, fn));

expectType<void>(
describe.each`
a | b | expected
Expand Down
1 change: 1 addition & 0 deletions packages/jest-types/src/Circus.ts
Expand Up @@ -12,6 +12,7 @@ type Process = NodeJS.Process;
export type DoneFn = Global.DoneFn;
export type BlockFn = Global.BlockFn;
export type BlockName = Global.BlockName;
export type BlockNameLike = Global.BlockNameLike;
export type BlockMode = void | 'skip' | 'only' | 'todo';
export type TestMode = BlockMode;
export type TestName = Global.TestName;
Expand Down
21 changes: 11 additions & 10 deletions packages/jest-types/src/Global.ts
Expand Up @@ -27,6 +27,9 @@ export type GeneratorReturningTestFn = (
this: TestContext | undefined,
) => TestReturnValueGenerator;

// eslint-disable-next-line @typescript-eslint/ban-types
export type NameLike = number | Function;

export type TestName = string;
export type TestFn =
| PromiseReturningTestFn
Expand All @@ -35,6 +38,8 @@ export type TestFn =
export type ConcurrentTestFn = () => TestReturnValuePromise;
export type BlockFn = () => void;
export type BlockName = string;
export type BlockNameLike = BlockName | NameLike;

export type HookFn = TestFn;

export type Col = unknown;
Expand All @@ -51,15 +56,11 @@ export type EachTestFn<EachCallback extends TestCallback> = (
...args: ReadonlyArray<any>
) => ReturnType<EachCallback>;

type Each<EachCallback extends TestCallback> =
type Each<EachCallback extends TestCallback, Name> =
| ((
table: EachTable,
...taggedTemplateData: TemplateData
) => (
name: BlockName | TestName,
test: EachTestFn<EachCallback>,
timeout?: number,
) => void)
) => (name: Name, test: EachTestFn<EachCallback>, timeout?: number) => void)
| (() => () => void);

export interface HookBase {
Expand All @@ -68,7 +69,7 @@ export interface HookBase {

export interface ItBase {
(testName: TestName, fn: TestFn, timeout?: number): void;
each: Each<TestFn>;
each: Each<TestFn, TestName>;
}

export interface It extends ItBase {
Expand All @@ -79,7 +80,7 @@ export interface It extends ItBase {

export interface ItConcurrentBase {
(testName: TestName, testFn: ConcurrentTestFn, timeout?: number): void;
each: Each<ConcurrentTestFn>;
each: Each<ConcurrentTestFn, TestName>;
}

export interface ItConcurrentExtended extends ItConcurrentBase {
Expand All @@ -92,8 +93,8 @@ export interface ItConcurrent extends It {
}

export interface DescribeBase {
(blockName: BlockName, blockFn: BlockFn): void;
each: Each<BlockFn>;
(blockName: BlockNameLike, blockFn: BlockFn): void;
each: Each<BlockFn, BlockNameLike | TestName>;
}

export interface Describe extends DescribeBase {
Expand Down
39 changes: 13 additions & 26 deletions packages/jest-util/src/convertDescriptorToString.ts
Expand Up @@ -5,35 +5,22 @@
* LICENSE file in the root directory of this source tree.
*/

/* eslint-disable local/ban-types-eventually */
import type {Global} from '@jest/types';

// See: https://github.com/facebook/jest/pull/5154
export default function convertDescriptorToString<
T extends number | string | Function | undefined,
>(descriptor: T): T | string {
if (
typeof descriptor === 'string' ||
typeof descriptor === 'number' ||
descriptor === undefined
) {
return descriptor;
}
export default function convertDescriptorToString(
descriptor: Global.BlockNameLike | undefined,
): string {
switch (typeof descriptor) {
case 'function':
return descriptor.name;

if (typeof descriptor !== 'function') {
throw new Error('describe expects a class, function, number, or string.');
}
case 'number':
case 'undefined':
return `${descriptor}`;

if (descriptor.name !== undefined) {
return descriptor.name;
case 'string':
return descriptor;
}

// Fallback for old browsers, pardon Flow
const stringified = descriptor.toString();
const typeDescriptorMatch = stringified.match(/class|function/);
const indexOfNameSpace =
// @ts-expect-error: typeDescriptorMatch exists
typeDescriptorMatch.index + typeDescriptorMatch[0].length;
const indexOfNameAfterSpace = stringified.search(/\(|\{/);
const name = stringified.substring(indexOfNameSpace, indexOfNameAfterSpace);
return name.trim();
throw new Error('describe expects a class, function, number, or string.');
JoshuaKGoldberg marked this conversation as resolved.
Show resolved Hide resolved
}