Skip to content

Commit

Permalink
Allowed describe and it/test to take in functions again (#12484)
Browse files Browse the repository at this point in the history
  • Loading branch information
JoshuaKGoldberg committed Feb 24, 2022
1 parent ee31422 commit 6b2e901
Show file tree
Hide file tree
Showing 19 changed files with 263 additions and 92 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -4,6 +4,7 @@

- `[babel-jest]` Export `createTransformer` function ([#12399](https://github.com/facebook/jest/pull/12399))
- `[expect]` Expose `AsymmetricMatchers`, `MatcherFunction` and `MatcherFunctionWithState` interfaces ([#12363](https://github.com/facebook/jest/pull/12363), [#12376](https://github.com/facebook/jest/pull/12376))
- `[jest-circus, jest-jasmine2]` Allowed classes and functions as `describe` and `it`/`test` names ([#12484](https://github.com/facebook/jest/pull/12484))
- `[jest-cli, jest-config]` [**BREAKING**] Remove `testURL` config, use `testEnvironmentOptions.url` instead ([#10797](https://github.com/facebook/jest/pull/10797))
- `[jest-config]` [**BREAKING**] Stop shipping `jest-environment-jsdom` by default ([#12354](https://github.com/facebook/jest/pull/12354))
- `[jest-config]` [**BREAKING**] Stop shipping `jest-jasmine2` by default ([#12355](https://github.com/facebook/jest/pull/12355))
Expand Down
17 changes: 15 additions & 2 deletions e2e/__tests__/__snapshots__/globals.test.ts.snap
Expand Up @@ -81,13 +81,26 @@ Time: <<REPLACED>>
Ran all test suites."
`;
exports[`function as descriptor 1`] = `
exports[`function as describe() descriptor 1`] = `
"PASS __tests__/functionAsDescriptor.test.js
Foo
✓ it"
`;
exports[`function as descriptor 2`] = `
exports[`function as describe() descriptor 2`] = `
"Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: <<REPLACED>>
Ran all test suites."
`;
exports[`function as it() descriptor 1`] = `
"PASS __tests__/functionAsDescriptor.test.js
✓ Foo"
`;
exports[`function as it() descriptor 2`] = `
"Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Expand Down
18 changes: 17 additions & 1 deletion e2e/__tests__/globals.test.ts
Expand Up @@ -262,7 +262,7 @@ test('cannot test with no implementation with expand arg', () => {
expect(exitCode).toBe(1);
});

test('function as descriptor', () => {
test('function as describe() descriptor', () => {
const filename = 'functionAsDescriptor.test.js';
const content = `
function Foo() {}
Expand All @@ -279,3 +279,19 @@ test('function as descriptor', () => {
expect(summary).toMatchSnapshot();
expect(exitCode).toBe(0);
});

test('function as it() descriptor', () => {
const filename = 'functionAsDescriptor.test.js';
const content = `
function Foo() {}
it(Foo, () => {});
`;

writeFiles(TEST_DIR, {[filename]: content});
const {stderr, exitCode} = runJest(DIR);

const {summary, rest} = extractSummary(stderr);
expect(rest).toMatchSnapshot();
expect(summary).toMatchSnapshot();
expect(exitCode).toBe(0);
});
Expand Up @@ -33,6 +33,24 @@ run_finish
unhandledErrors: 0"
`;

exports[`function descriptors 1`] = `
"start_describe_definition: describer
add_test: One
finish_describe_definition: describer
run_start
run_describe_start: ROOT_DESCRIBE_BLOCK
run_describe_start: describer
test_start: One
test_fn_start: One
test_fn_success: One
test_done: One
run_describe_finish: describer
run_describe_finish: ROOT_DESCRIBE_BLOCK
run_finish
unhandledErrors: 0"
`;

exports[`simple test 1`] = `
"start_describe_definition: describe
add_hook: beforeEach
Expand Down
10 changes: 10 additions & 0 deletions packages/jest-circus/src/__tests__/baseTest.test.ts
Expand Up @@ -20,6 +20,16 @@ test('simple test', () => {
expect(stdout).toMatchSnapshot();
});

test('function descriptors', () => {
const {stdout} = runTest(`
describe(function describer() {}, () => {
test(class One {}, () => {});
})
`);

expect(stdout).toMatchSnapshot();
});

test('failures', () => {
const {stdout} = runTest(`
describe('describe', () => {
Expand Down
10 changes: 7 additions & 3 deletions packages/jest-circus/src/__tests__/circusItTestError.test.ts
Expand Up @@ -35,11 +35,13 @@ describe('test/it error throwing', () => {
'Missing second argument. It must be a callback function. Perhaps you want to use `test.todo` for a test placeholder.',
);
});
it("it throws an error when first argument isn't a string", () => {
it("it throws an error when first argument isn't valid", () => {
expect(() => {
// @ts-expect-error: Easy, we're testing runtime errors here
circusIt(() => {});
}).toThrowError('Invalid first argument, () => {}. It must be a string.');
}).toThrowError(
'Invalid first argument, () => {}. It must be a named class, named function, number, or string.',
);
});
it('it throws an error when callback function is not a function', () => {
expect(() => {
Expand All @@ -66,7 +68,9 @@ describe('test/it error throwing', () => {
expect(() => {
// @ts-expect-error: Easy, we're testing runtime errors here
circusTest(() => {});
}).toThrowError('Invalid first argument, () => {}. It must be a string.');
}).toThrowError(
'Invalid first argument, () => {}. It must be a named class, named function, number, or string.',
);
});
it('test throws an error when callback function is not a function', () => {
expect(() => {
Expand Down
39 changes: 24 additions & 15 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,13 @@ const _dispatchDescribe = (
asyncError.message = `Invalid second argument, ${blockFn}. It must be a callback function.`;
throw asyncError;
}
try {
blockName = convertDescriptorToString(blockName);
} catch (error) {
asyncError.message = (error as Error).message;
throw asyncError;
}

dispatchSync({
asyncError,
blockName,
Expand Down Expand Up @@ -107,22 +114,22 @@ const afterAll: THook = (fn, timeout) =>

const test: Global.It = (() => {
const test = (
testName: Circus.TestName,
testName: Circus.TestNameLike,
fn: Circus.TestFn,
timeout?: number,
): void => _addTest(testName, undefined, fn, test, timeout);
const skip = (
testName: Circus.TestName,
testName: Circus.TestNameLike,
fn?: Circus.TestFn,
timeout?: number,
): void => _addTest(testName, 'skip', fn, skip, timeout);
const only = (
testName: Circus.TestName,
testName: Circus.TestNameLike,
fn: Circus.TestFn,
timeout?: number,
): void => _addTest(testName, 'only', fn, test.only, timeout);

test.todo = (testName: Circus.TestName, ...rest: Array<any>): void => {
test.todo = (testName: Circus.TestNameLike, ...rest: Array<any>): void => {
if (rest.length > 0 || typeof testName !== 'string') {
throw new ErrorWithStack(
'Todo must be called with only a description.',
Expand All @@ -133,23 +140,25 @@ const test: Global.It = (() => {
};

const _addTest = (
testName: Circus.TestName,
testName: Circus.TestNameLike,
mode: Circus.TestMode,
fn: Circus.TestFn | undefined,
testFn: (
testName: Circus.TestName,
testName: Circus.TestNameLike,
fn: Circus.TestFn,
timeout?: number,
) => void,
timeout?: number,
) => {
const asyncError = new ErrorWithStack(undefined, testFn);

if (typeof testName !== 'string') {
asyncError.message = `Invalid first argument, ${testName}. It must be a string.`;

try {
testName = convertDescriptorToString(testName);
} catch (error) {
asyncError.message = (error as Error).message;
throw asyncError;
}

if (fn === undefined) {
asyncError.message =
'Missing second argument. It must be a callback function. Perhaps you want to use `test.todo` for a test placeholder.';
Expand Down
Expand Up @@ -78,7 +78,7 @@ export const initialize = async ({

globalsObject.test.concurrent = (test => {
const concurrent = (
testName: string,
testName: Global.TestNameLike,
testFn: Global.ConcurrentTestFn,
timeout?: number,
) => {
Expand All @@ -96,7 +96,7 @@ export const initialize = async ({
};

const only = (
testName: string,
testName: Global.TestNameLike,
testFn: Global.ConcurrentTestFn,
timeout?: number,
) => {
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
12 changes: 8 additions & 4 deletions packages/jest-jasmine2/src/__tests__/itTestError.test.ts
Expand Up @@ -14,11 +14,13 @@ describe('test/it error throwing', () => {
'Missing second argument. It must be a callback function. Perhaps you want to use `test.todo` for a test placeholder.',
);
});
it("it throws an error when first argument isn't a string", () => {
it("it throws an error when first argument isn't valid", () => {
expect(() => {
// @ts-expect-error
it(() => {});
}).toThrowError('Invalid first argument, () => {}. It must be a string.');
}).toThrowError(
'Invalid first argument, () => {}. It must be a named class, named function, number, or string.',
);
});
it('it throws an error when callback function is not a function', () => {
expect(() => {
Expand All @@ -35,11 +37,13 @@ describe('test/it error throwing', () => {
'Missing second argument. It must be a callback function. Perhaps you want to use `test.todo` for a test placeholder.',
);
});
test("test throws an error when first argument isn't a string", () => {
test("test throws an error when first argument isn't valid", () => {
expect(() => {
// @ts-expect-error
test(() => {});
}).toThrowError('Invalid first argument, () => {}. It must be a string.');
}).toThrowError(
'Invalid first argument, () => {}. It must be a named class, named function, number, or string.',
);
});
test('test throws an error when callback function is not a function', () => {
expect(() => {
Expand Down

0 comments on commit 6b2e901

Please sign in to comment.