From 0d433009a27efcf34f8b073ea69063d98bcca8d4 Mon Sep 17 00:00:00 2001 From: Dmitrii Abramov Date: Fri, 9 Jun 2017 02:15:16 -0700 Subject: [PATCH] fix bug when setTimeout is mocked (#3769) --- packages/jest-circus/src/utils.js | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/packages/jest-circus/src/utils.js b/packages/jest-circus/src/utils.js index 3a1b24241635..5e92612c3070 100644 --- a/packages/jest-circus/src/utils.js +++ b/packages/jest-circus/src/utils.js @@ -115,6 +115,10 @@ const _makeTimeoutMessage = (timeout, isHook) => `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.`, ); +// Global values can be overwritten by mocks or tests. We'll capture +// the original values in the variables before we require any files. +const {setTimeout, clearTimeout} = global; + const callAsyncFn = ( fn: AsyncFn, testContext: ?TestContext, @@ -124,8 +128,13 @@ const callAsyncFn = ( timeout, }: {isHook?: ?boolean, test?: TestEntry, timeout: number}, ): Promise => { + let timeoutID; + return new Promise((resolve, reject) => { - setTimeout(() => reject(_makeTimeoutMessage(timeout, isHook)), timeout); + timeoutID = setTimeout( + () => reject(_makeTimeoutMessage(timeout, isHook)), + timeout, + ); // If this fn accepts `done` callback we return a promise that fullfills as // soon as `done` called. @@ -162,7 +171,18 @@ const callAsyncFn = ( // Otherwise this test is synchronous, and if it didn't throw it means // it passed. return resolve(); - }); + }) + .then(() => { + // If timeout is not cleared/unrefed the node process won't exit until + // it's resolved. + timeoutID.unref && timeoutID.unref(); + clearTimeout(timeoutID); + }) + .catch(error => { + timeoutID.unref && timeoutID.unref(); + clearTimeout(timeoutID); + throw error; + }); }; const getTestDuration = (test: TestEntry): ?number => {