From 0f11a85f704561b98d87b8039855c925b422766d Mon Sep 17 00:00:00 2001 From: Valentin Ignatev Date: Fri, 16 Nov 2018 11:54:18 +0300 Subject: [PATCH] feat: use real Date.now to avoid using potentially mocked one (#12) * (#12) use real Date.now to avoid using potentially mocked one * (#12) make tsc happy with Date on Window interface and Date jest mock --- src/index.ts | 21 +++++++++---- src/withFakeTimers.spec.ts | 61 ++++++++++++++++++++++++++++++++++++-- 2 files changed, 75 insertions(+), 7 deletions(-) diff --git a/src/index.ts b/src/index.ts index 5501d15..d0f3a2a 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,6 +1,17 @@ -// Used to avoid using Jest's fake timers. -// See https://github.com/TheBrainFamily/wait-for-expect/issues/4 for more info -const { setTimeout } = typeof window !== "undefined" ? window : global; +// Augment Window interface with the Date declaratoin, +// because typescript does not expose it for now. +// Check https://github.com/Microsoft/TypeScript/issues/19816 for more info +declare global { + /* eslint-disable-next-line no-undef */ + interface Window { + Date: typeof Date; + } +} +// Used to avoid using Jest's fake timers and Date.now mocks +// See https://github.com/TheBrainFamily/wait-for-expect/issues/4 and +// https://github.com/TheBrainFamily/wait-for-expect/issues/12 for more info +const { setTimeout, Date: { now } } = + typeof window !== "undefined" ? window : global; /** * Waits for the expectation to pass and returns a Promise @@ -15,10 +26,10 @@ const waitForExpect = function waitForExpect( timeout = 4500, interval = 50 ) { - const startTime = Date.now(); + const startTime = now(); return new Promise((resolve, reject) => { const rejectOrRerun = (error: Error) => { - if (Date.now() - startTime >= timeout) { + if (now() - startTime >= timeout) { reject(error); return; } diff --git a/src/withFakeTimers.spec.ts b/src/withFakeTimers.spec.ts index 16f0dab..d80f41b 100644 --- a/src/withFakeTimers.spec.ts +++ b/src/withFakeTimers.spec.ts @@ -2,10 +2,15 @@ import "./toBeInRangeMatcher"; import waitForExpect from "./index"; -// this is a copy of "it waits for expectation to pass" modified to use jestFakeTimers -// This breakes when we remove the const { setTimeout } = typeof window !== "undefined" ? window : global; +// this is a copy of "it waits for expectation to pass" modified to use jestFakeTimers and two ways of Date.now mocking +// This breakes when we remove the const { setTimeout, Date: { now } } = typeof window !== "undefined" ? window : global; // line from the index.ts +beforeEach(() => { + jest.restoreAllMocks(); + jest.useRealTimers(); +}); + test("it works even if the timers are overwritten by jest", async () => { jest.useFakeTimers(); let numberToChange = 10; @@ -22,3 +27,55 @@ test("it works even if the timers are overwritten by jest", async () => { expect(numberToChange).toEqual(100); }); }); + +// Date.now might be mocked with two main ways: +// via mocking whole Date, or by mocking just Date.now +// hence two test cases covered both ways +test("it works even if the Date was mocked", async () => { + /* eslint-disable no-global-assign */ + // @ts-ignore: Cannot reassign to const Date + Date = jest.fn(() => ({ + now() { + return 1482363367071; + } + })); + /* eslint-enable */ + let numberToChange = 10; + + setTimeout(() => { + numberToChange = 100; + }, 100); + let expectFailingMessage; + try { + await waitForExpect(() => { + expect(numberToChange).toEqual(101); + }, 1000); + } catch (e) { + expectFailingMessage = e.message; + } + expect(expectFailingMessage).toMatch("Expected value to equal:"); + expect(expectFailingMessage).toMatch("101"); + expect(expectFailingMessage).toMatch("Received:"); + expect(expectFailingMessage).toMatch("100"); +}); + +test("it works even if the Date.now was mocked", async () => { + Date.now = jest.fn(() => 1482363367071); + let numberToChange = 10; + + setTimeout(() => { + numberToChange = 100; + }, 100); + let expectFailingMessage; + try { + await waitForExpect(() => { + expect(numberToChange).toEqual(101); + }, 1000); + } catch (e) { + expectFailingMessage = e.message; + } + expect(expectFailingMessage).toMatch("Expected value to equal:"); + expect(expectFailingMessage).toMatch("101"); + expect(expectFailingMessage).toMatch("Received:"); + expect(expectFailingMessage).toMatch("100"); +});