Skip to content

Commit

Permalink
feat(circus): expose expect.deadline()
Browse files Browse the repository at this point in the history
c.f. jestjs#10895, jestjs#10905

Expose the test's timeout back to the the test, so it can make
decisions based on this, if it wants. Some proposed uses are
included in the above issue, but the implementation has got
rather big, and none of the rest absolutely have to be core.

This part does.
  • Loading branch information
FauxFaux committed Jan 4, 2021
1 parent 7430a78 commit e1da938
Show file tree
Hide file tree
Showing 11 changed files with 77 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -4,6 +4,7 @@

- `[jest-circus]` [**BREAKING**] Fail tests when multiple `done()` calls are made ([#10624](https://github.com/facebook/jest/pull/10624))
- `[jest-circus, jest-jasmine2]` [**BREAKING**] Fail the test instead of just warning when describe returns a value ([#10947](https://github.com/facebook/jest/pull/10947))
- `[jest-circus]` Expose the test's timeout as `expect.deadline()` ([#10993](https://github.com/facebook/jest/pull/10993))
- `[jest-config]` [**BREAKING**] Default to Node testing environment instead of browser (JSDOM) ([#9874](https://github.com/facebook/jest/pull/9874))
- `[jest-config]` [**BREAKING**] Use `jest-circus` as default test runner ([#10686](https://github.com/facebook/jest/pull/10686))
- `[jest-config, jest-runtime]` Support ESM for files other than `.js` and `.mjs` ([#10823](https://github.com/facebook/jest/pull/10823))
Expand Down
15 changes: 15 additions & 0 deletions e2e/__tests__/deadlines.ts
@@ -0,0 +1,15 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import {skipSuiteOnJasmine} from '@jest/test-utils';
import runJest from '../runJest';

skipSuiteOnJasmine();

it('self checks the deadlines are within bounds', () => {
const result = runJest('deadlines', ['timings.js']);
expect(result.exitCode).toBe(0);
});
28 changes: 28 additions & 0 deletions e2e/deadlines/__tests__/timings.js
@@ -0,0 +1,28 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

'use strict';

const fileStarted = Date.now();

describe('describe', () => {
jest.setTimeout(789);

it('is present for global timeout', () => {
const testStarted = Date.now();
const deadline = expect.deadline();
expect(deadline).toBeGreaterThanOrEqual(testStarted);
expect(deadline).toBeLessThanOrEqual(testStarted + 789);
});

it('explicit override', () => {
const testStarted = Date.now();
const deadline = expect.deadline();
expect(deadline).toBeGreaterThanOrEqual(testStarted);
expect(deadline).toBeLessThanOrEqual(testStarted + 456);
}, 456);
});
1 change: 1 addition & 0 deletions e2e/deadlines/package.json
@@ -0,0 +1 @@
{}
3 changes: 3 additions & 0 deletions packages/expect/src/index.ts
Expand Up @@ -412,6 +412,9 @@ setMatchers(spyMatchers, true, expect as Expect);
setMatchers(toThrowMatchers, true, expect as Expect);

expect.addSnapshotSerializer = () => void 0;
expect.deadline = () => {
throw new Error('deadline must be implemented by the runtime');
};
expect.assertions = assertions;
expect.hasAssertions = hasAssertions;
expect.getState = getState;
Expand Down
3 changes: 3 additions & 0 deletions packages/expect/src/types.ts
Expand Up @@ -75,6 +75,9 @@ export type Expect = {
hasAssertions(): void;
setState(state: Partial<MatcherState>): void;

// TODO: this is added by test runners, not `expect` itself
deadline(): number;

any(expectedObject: any): AsymmetricMatcher;
anything(): AsymmetricMatcher;
arrayContaining(sample: Array<unknown>): AsymmetricMatcher;
Expand Down
16 changes: 16 additions & 0 deletions packages/jest-circus/src/deadlineTimeout.ts
@@ -0,0 +1,16 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

import {getState} from './state';

export function deadline(): number {
const deadline = getState()?.currentlyRunningChildDeadline;
if (deadline === null) {
throw new Error('bug! no deadline available');
}
return deadline;
}
Expand Up @@ -14,6 +14,7 @@ import {
toThrowErrorMatchingInlineSnapshot,
toThrowErrorMatchingSnapshot,
} from 'jest-snapshot';
import {deadline} from '../deadlineTimeout';

export type Expect = typeof expect;

Expand All @@ -27,6 +28,7 @@ export default (config: Pick<Config.GlobalConfig, 'expand'>): Expect => {
});

expect.addSnapshotSerializer = addSerializer;
expect.deadline = deadline;

return expect;
};
6 changes: 6 additions & 0 deletions packages/jest-circus/src/run.ts
Expand Up @@ -150,6 +150,7 @@ const _callCircusHook = async ({
}): Promise<void> => {
await dispatch({hook, name: 'hook_start'});
const timeout = hook.timeout || getState().testTimeout;
_updateDeadline(timeout);

try {
await callAsyncCircusFn(hook, testContext, {
Expand All @@ -168,6 +169,7 @@ const _callCircusTest = async (
): Promise<void> => {
await dispatch({name: 'test_fn_start', test});
const timeout = test.timeout || getState().testTimeout;
_updateDeadline(timeout);
invariant(test.fn, `Tests with no 'fn' should have 'mode' set to 'skipped'`);

if (test.errors.length) {
Expand All @@ -185,4 +187,8 @@ const _callCircusTest = async (
}
};

const _updateDeadline = (timeout: number): void => {
getState().currentlyRunningChildDeadline = Date.now() + timeout - 20;
};

export default run;
1 change: 1 addition & 0 deletions packages/jest-circus/src/state.ts
Expand Up @@ -21,6 +21,7 @@ export const ROOT_DESCRIBE_BLOCK_NAME = 'ROOT_DESCRIBE_BLOCK';
const ROOT_DESCRIBE_BLOCK = makeDescribe(ROOT_DESCRIBE_BLOCK_NAME);
const INITIAL_STATE: Circus.State = {
currentDescribeBlock: ROOT_DESCRIBE_BLOCK,
currentlyRunningChildDeadline: null,
currentlyRunningTest: null,
expand: undefined,
hasFocusedTests: false,
Expand Down
1 change: 1 addition & 0 deletions packages/jest-types/src/Circus.ts
Expand Up @@ -200,6 +200,7 @@ export type GlobalErrorHandlers = {
export type State = {
currentDescribeBlock: DescribeBlock;
currentlyRunningTest?: TestEntry | null; // including when hooks are being executed
currentlyRunningChildDeadline: number | null;
expand?: boolean; // expand error messages
hasFocusedTests: boolean; // that are defined using test.only
hasStarted: boolean; // whether the rootDescribeBlock has started running
Expand Down

0 comments on commit e1da938

Please sign in to comment.