From 41beefadae62cf1b5da693b635ca3373209ca422 Mon Sep 17 00:00:00 2001 From: Dmitrii Abramov Date: Fri, 2 Jun 2017 11:39:19 -0700 Subject: [PATCH 1/2] jest-circus Timeouts --- .../__snapshots__/timeouts-test.js.snap | 13 ---- integration_tests/__tests__/timeouts-test.js | 6 +- packages/jest-circus/src/run.js | 31 +++++---- packages/jest-circus/src/utils.js | 65 +++++++++++-------- 4 files changed, 61 insertions(+), 54 deletions(-) diff --git a/integration_tests/__tests__/__snapshots__/timeouts-test.js.snap b/integration_tests/__tests__/__snapshots__/timeouts-test.js.snap index 164a5fe634e5..13b00317ee7a 100644 --- a/integration_tests/__tests__/__snapshots__/timeouts-test.js.snap +++ b/integration_tests/__tests__/__snapshots__/timeouts-test.js.snap @@ -17,19 +17,6 @@ Ran all test suites. `; exports[`exceeds the timeout 1`] = ` -" FAIL __tests__/a-banana.js - ● banana - - Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL. - - at ../../packages/jest-jasmine2/build/queueRunner.js:53:21 - - ✕ banana - -" -`; - -exports[`exceeds the timeout 2`] = ` "Test Suites: 1 failed, 1 total Tests: 1 failed, 1 total Snapshots: 0 total diff --git a/integration_tests/__tests__/timeouts-test.js b/integration_tests/__tests__/timeouts-test.js index d32a895f44a7..4caa36a5824a 100644 --- a/integration_tests/__tests__/timeouts-test.js +++ b/integration_tests/__tests__/timeouts-test.js @@ -36,9 +36,9 @@ test('exceeds the timeout', () => { const {stderr, status} = runJest(DIR, ['-w=1', '--ci=false']); const {rest, summary} = extractSummary(stderr); - expect(status).toBe(1); - expect(rest).toMatchSnapshot(); + expect(rest).toMatch(/(jasmine\.DEFAULT_TIMEOUT_INTERVAL|Exceeded timeout)/); expect(summary).toMatchSnapshot(); + expect(status).toBe(1); }); test('does not exceed the timeout', () => { @@ -57,7 +57,7 @@ test('does not exceed the timeout', () => { const {stderr, status} = runJest(DIR, ['-w=1', '--ci=false']); const {rest, summary} = extractSummary(stderr); - expect(status).toBe(0); expect(rest).toMatchSnapshot(); expect(summary).toMatchSnapshot(); + expect(status).toBe(0); }); diff --git a/packages/jest-circus/src/run.js b/packages/jest-circus/src/run.js index 0ba206adc5ce..02ef2af6c782 100644 --- a/packages/jest-circus/src/run.js +++ b/packages/jest-circus/src/run.js @@ -54,6 +54,16 @@ const _runTestsForDescribeBlock = async (describeBlock: DescribeBlock) => { const _runTest = async (test: TestEntry): Promise => { const testContext = Object.create(null); + + const isSkipped = + test.mode === 'skip' || + (getState().hasFocusedTests && test.mode !== 'only'); + + if (isSkipped) { + dispatch({name: 'test_skip', test}); + return; + } + const {afterEach, beforeEach} = getEachHooksForTest(test); for (const hook of beforeEach) { @@ -69,27 +79,24 @@ const _runTest = async (test: TestEntry): Promise => { const _callHook = (hook: Hook, testContext?: TestContext): Promise => { dispatch({hook, name: 'hook_start'}); - return callAsyncFn(hook.fn, testContext, {isHook: true}) + const {testTimeout: timeout} = getState(); + return callAsyncFn(hook.fn, testContext, {isHook: true, timeout}) .then(() => dispatch({hook, name: 'hook_success'})) .catch(error => dispatch({error, hook, name: 'hook_failure'})); }; -const _callTest = (test: TestEntry, testContext: TestContext): Promise => { - const isSkipped = - test.mode === 'skip' || - (getState().hasFocusedTests && test.mode !== 'only'); - - if (isSkipped) { - dispatch({name: 'test_skip', test}); - return Promise.resolve(); - } - +const _callTest = async ( + test: TestEntry, + testContext: TestContext, +): Promise => { dispatch({name: 'test_start', test}); + const {testTimeout: timeout} = getState(); + if (!test.fn) { throw Error(`Tests with no 'fn' should have 'mode' set to 'skipped'`); } - return callAsyncFn(test.fn, testContext) + return callAsyncFn(test.fn, testContext, {isHook: false, timeout}) .then(() => dispatch({name: 'test_success', test})) .catch(error => dispatch({error, name: 'test_failure', test})); }; diff --git a/packages/jest-circus/src/utils.js b/packages/jest-circus/src/utils.js index 41f5e0578aa5..21a99b246f14 100644 --- a/packages/jest-circus/src/utils.js +++ b/packages/jest-circus/src/utils.js @@ -110,46 +110,59 @@ const getEachHooksForTest = ( return result; }; +const _makeTimeoutMessage = (timeout, isHook) => { + const message = `Exceeded timeout of ${timeout}ms for a ${isHook ? 'hook' : 'test'}.`; + return new Error(message); +}; + const callAsyncFn = ( fn: AsyncFn, testContext: ?TestContext, - {isHook}: {isHook?: boolean} = {isHook: false}, + { + isHook, + timeout, + test, + }: {isHook?: ?boolean, timeout: number, test?: TestEntry}, ): Promise => { - // If this fn accepts `done` callback we return a promise that fullfills as - // soon as `done` called. - if (fn.length) { - return new Promise((resolve, reject) => { + return new Promise((resolve, reject) => { + setTimeout(() => reject(_makeTimeoutMessage(timeout, isHook)), timeout); + + // If this fn accepts `done` callback we return a promise that fullfills as + // soon as `done` called. + if (fn.length) { const done = (reason?: Error | string): void => reason ? reject(reason) : resolve(); - fn.call(testContext, done); - }); - } + return fn.call(testContext, done); + } - let returnedValue; - try { - returnedValue = fn.call(testContext); - } catch (error) { - return Promise.reject(error); - } + let returnedValue; + try { + returnedValue = fn.call(testContext); + } catch (error) { + return reject(error); + } - // If it's a Promise, return it. - if (returnedValue instanceof Promise) { - return returnedValue; - } + // If it's a Promise, return it. + if (returnedValue instanceof Promise) { + return returnedValue.then(resolve).catch(reject); + } - if (!isHook && returnedValue !== void 0) { - throw new Error( - ` + if (!isHook && returnedValue !== void 0) { + return reject( + new Error( + ` test functions can only return Promise or undefined. Returned value: ${String(returnedValue)} `, - ); - } + ), + ); + } - // Otherwise this test is synchronous, and if it didn't throw it means - // it passed. - return Promise.resolve(); + // Otherwise this test is synchronous, and if it didn't throw it means + // it passed. + return resolve(); + }); }; const getTestDuration = (test: TestEntry): ?number => { From d4587364f8ca0efa2d388f68237ca087ba1d4d6f Mon Sep 17 00:00:00 2001 From: Dmitrii Abramov Date: Thu, 8 Jun 2017 09:22:55 -0700 Subject: [PATCH 2/2] setTestTimeout/setTimeout --- docs/en/JestObjectAPI.md | 8 ++++---- docs/en/Troubleshooting.md | 4 ++-- integration_tests/__tests__/timeouts-test.js | 4 ++-- packages/jest-circus/src/state.js | 1 - packages/jest-circus/src/utils.js | 14 +++++++------- .../jest-cli/src/__tests__/SearchSource-test.js | 2 +- packages/jest-runtime/src/index.js | 4 ++-- testSetupFile.js | 2 +- 8 files changed, 19 insertions(+), 20 deletions(-) diff --git a/docs/en/JestObjectAPI.md b/docs/en/JestObjectAPI.md index 7e793cc31282..d9e0b5161fa1 100644 --- a/docs/en/JestObjectAPI.md +++ b/docs/en/JestObjectAPI.md @@ -27,7 +27,7 @@ The `jest` object is automatically in scope within every test file. The methods - [`jest.runTimersToTime(msToRun)`](#jestruntimerstotimemstorun) - [`jest.runOnlyPendingTimers()`](#jestrunonlypendingtimers) - [`jest.setMock(moduleName, moduleExports)`](#jestsetmockmodulename-moduleexports) - - [`jest.setTestTimeout(timeout)`](#jestsettesttimeouttimeout) + - [`jest.setTimeout(timeout)`](#jestsettimeouttimeout) - [`jest.unmock(moduleName)`](#jestunmockmodulename) - [`jest.useFakeTimers()`](#jestusefaketimers) - [`jest.useRealTimers()`](#jestuserealtimers) @@ -205,16 +205,16 @@ Returns the `jest` object for chaining. *Note It is recommended to use [`jest.mock()`](#jestmockmodulename-factory-options) instead. The `jest.mock` API's second argument is a module factory instead of the expected exported module object.* -### `jest.setTestTimeout(timeout)` +### `jest.setTimeout(timeout)` -Set the default timeout interval for tests in milliseconds. +Set the default timeout interval for tests and before/after hooks in milliseconds. *Note: The default timeout interval is 5 seconds if this method is not called.* Example: ```js -jest.setTestTimeout(1000); // 1 second +jest.setTimeout(1000); // 1 second ``` ### `jest.unmock(moduleName)` diff --git a/docs/en/Troubleshooting.md b/docs/en/Troubleshooting.md index f69a61008918..210c8df6e55f 100644 --- a/docs/en/Troubleshooting.md +++ b/docs/en/Troubleshooting.md @@ -64,10 +64,10 @@ Consider replacing the global promise implementation with your own, for example used Promise libraries to a single one. If your test is long running, you may want to consider to increase the timeout -by calling `jest.setTestTimeout` +by calling `jest.setTimeout` ``` -jest.setTestTimeout(10000); // 10 second timeout +jest.setTimeout(10000); // 10 second timeout ``` ### Watchman Issues diff --git a/integration_tests/__tests__/timeouts-test.js b/integration_tests/__tests__/timeouts-test.js index 4caa36a5824a..e86cf146b592 100644 --- a/integration_tests/__tests__/timeouts-test.js +++ b/integration_tests/__tests__/timeouts-test.js @@ -23,7 +23,7 @@ afterAll(() => cleanup(DIR)); test('exceeds the timeout', () => { writeFiles(DIR, { '__tests__/a-banana.js': ` - jest.setTestTimeout(20); + jest.setTimeout(20); test('banana', () => { return new Promise(resolve => { @@ -44,7 +44,7 @@ test('exceeds the timeout', () => { test('does not exceed the timeout', () => { writeFiles(DIR, { '__tests__/a-banana.js': ` - jest.setTestTimeout(100); + jest.setTimeout(100); test('banana', () => { return new Promise(resolve => { diff --git a/packages/jest-circus/src/state.js b/packages/jest-circus/src/state.js index d3099415ad93..67842f6a00cc 100644 --- a/packages/jest-circus/src/state.js +++ b/packages/jest-circus/src/state.js @@ -10,7 +10,6 @@ import type {Event, State, EventHandler} from '../types'; - const {makeDescribe} = require('./utils'); const eventHandler = require('./eventHandler'); diff --git a/packages/jest-circus/src/utils.js b/packages/jest-circus/src/utils.js index 21a99b246f14..3a1b24241635 100644 --- a/packages/jest-circus/src/utils.js +++ b/packages/jest-circus/src/utils.js @@ -110,19 +110,19 @@ const getEachHooksForTest = ( return result; }; -const _makeTimeoutMessage = (timeout, isHook) => { - const message = `Exceeded timeout of ${timeout}ms for a ${isHook ? 'hook' : 'test'}.`; - return new Error(message); -}; +const _makeTimeoutMessage = (timeout, isHook) => + new Error( + `Exceeded timeout of ${timeout}ms for a ${isHook ? 'hook' : 'test'}.\nUse jest.setTimeout(newTimeout) to increase the timeout value, if this is a long-running test.`, + ); const callAsyncFn = ( fn: AsyncFn, testContext: ?TestContext, { isHook, - timeout, test, - }: {isHook?: ?boolean, timeout: number, test?: TestEntry}, + timeout, + }: {isHook?: ?boolean, test?: TestEntry, timeout: number}, ): Promise => { return new Promise((resolve, reject) => { setTimeout(() => reject(_makeTimeoutMessage(timeout, isHook)), timeout); @@ -145,7 +145,7 @@ const callAsyncFn = ( // If it's a Promise, return it. if (returnedValue instanceof Promise) { - return returnedValue.then(resolve).catch(reject); + return returnedValue.then(resolve, reject); } if (!isHook && returnedValue !== void 0) { diff --git a/packages/jest-cli/src/__tests__/SearchSource-test.js b/packages/jest-cli/src/__tests__/SearchSource-test.js index 80088aad38de..765c1caf1cc5 100644 --- a/packages/jest-cli/src/__tests__/SearchSource-test.js +++ b/packages/jest-cli/src/__tests__/SearchSource-test.js @@ -9,7 +9,7 @@ */ 'use strict'; -jest.setTestTimeout(15000); +jest.setTimeout(15000); const path = require('path'); const skipOnWindows = require('skipOnWindows'); diff --git a/packages/jest-runtime/src/index.js b/packages/jest-runtime/src/index.js index 5a853a641b96..4fe5634c89e4 100644 --- a/packages/jest-runtime/src/index.js +++ b/packages/jest-runtime/src/index.js @@ -715,7 +715,7 @@ class Runtime { const fn = this._moduleMocker.fn.bind(this._moduleMocker); const spyOn = this._moduleMocker.spyOn.bind(this._moduleMocker); - const setTestTimeout = (timeout: number) => { + const setTimeout = (timeout: number) => { this._environment.global.jasmine ? (this._environment.global.jasmine.DEFAULT_TIMEOUT_INTERVAL = timeout) : (this._environment.global[ @@ -758,7 +758,7 @@ class Runtime { setMock: (moduleName: string, mock: Object) => setMockFactory(moduleName, () => mock), - setTestTimeout, + setTimeout, spyOn, unmock, diff --git a/testSetupFile.js b/testSetupFile.js index 625e60464432..6631a9ebd44c 100644 --- a/testSetupFile.js +++ b/testSetupFile.js @@ -10,7 +10,7 @@ const jasmineReporters = require('jasmine-reporters'); // Some of the `jest-runtime` tests are very slow and cause // timeouts on travis -jest.setTestTimeout(70000); +jest.setTimeout(70000); if (global.jasmine && process.env.APPVEYOR_API_URL) { // Running on AppVeyor, add the custom reporter.