From 78e0893209d266e57feb8b84e64332cc10065348 Mon Sep 17 00:00:00 2001 From: Simen Bekkhus Date: Tue, 2 Oct 2018 11:15:57 +0200 Subject: [PATCH] chore: add integration test for driving promises with fake timers (#7071) --- e2e/__tests__/fake-promises.test.js | 23 ++++ .../asap/__tests__/generator.test.js | 19 +++ e2e/fake-promises/asap/fake-promises.js | 10 ++ e2e/fake-promises/asap/package.json | 9 ++ .../immediate/__tests__/generator.test.js | 19 +++ e2e/fake-promises/immediate/fake-promises.js | 10 ++ e2e/fake-promises/immediate/package.json | 9 ++ package.json | 1 + .../src/__tests__/fake_timers.test.js | 121 +++++++++--------- yarn.lock | 9 +- 10 files changed, 169 insertions(+), 61 deletions(-) create mode 100644 e2e/__tests__/fake-promises.test.js create mode 100644 e2e/fake-promises/asap/__tests__/generator.test.js create mode 100644 e2e/fake-promises/asap/fake-promises.js create mode 100644 e2e/fake-promises/asap/package.json create mode 100644 e2e/fake-promises/immediate/__tests__/generator.test.js create mode 100644 e2e/fake-promises/immediate/fake-promises.js create mode 100644 e2e/fake-promises/immediate/package.json diff --git a/e2e/__tests__/fake-promises.test.js b/e2e/__tests__/fake-promises.test.js new file mode 100644 index 000000000000..b194a6ebdf23 --- /dev/null +++ b/e2e/__tests__/fake-promises.test.js @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2014-present, Facebook, Inc. 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. + * + * @flow + */ +'use strict'; + +const runJest = require('../runJest'); + +describe('Fake promises', () => { + it('should be possible to resolve with fake timers using immediates', () => { + const result = runJest('fake-promises/immediate'); + expect(result.status).toBe(0); + }); + + it('should be possible to resolve with fake timers using asap', () => { + const result = runJest('fake-promises/asap'); + expect(result.status).toBe(0); + }); +}); diff --git a/e2e/fake-promises/asap/__tests__/generator.test.js b/e2e/fake-promises/asap/__tests__/generator.test.js new file mode 100644 index 000000000000..9ba08f248d05 --- /dev/null +++ b/e2e/fake-promises/asap/__tests__/generator.test.js @@ -0,0 +1,19 @@ +/** + * Copyright (c) 2014-present, Facebook, Inc. 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'; + +test('fake promises', () => { + let someValue; + Promise.resolve().then(() => { + someValue = 'foobar'; + }); + + jest.runAllTicks(); + + expect(someValue).toBe('foobar'); +}); diff --git a/e2e/fake-promises/asap/fake-promises.js b/e2e/fake-promises/asap/fake-promises.js new file mode 100644 index 000000000000..a9ccfb696a13 --- /dev/null +++ b/e2e/fake-promises/asap/fake-promises.js @@ -0,0 +1,10 @@ +/** + * Copyright (c) 2014-present, Facebook, Inc. 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'; + +global.Promise = require('promise'); diff --git a/e2e/fake-promises/asap/package.json b/e2e/fake-promises/asap/package.json new file mode 100644 index 000000000000..0f50640514e1 --- /dev/null +++ b/e2e/fake-promises/asap/package.json @@ -0,0 +1,9 @@ +{ + "jest": { + "timers": "fake", + "setupFiles": [ + "/fake-promises" + ], + "testEnvironment": "node" + } +} diff --git a/e2e/fake-promises/immediate/__tests__/generator.test.js b/e2e/fake-promises/immediate/__tests__/generator.test.js new file mode 100644 index 000000000000..706bcc675dbb --- /dev/null +++ b/e2e/fake-promises/immediate/__tests__/generator.test.js @@ -0,0 +1,19 @@ +/** + * Copyright (c) 2014-present, Facebook, Inc. 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'; + +test('fake promises', () => { + let someValue; + Promise.resolve().then(() => { + someValue = 'foobar'; + }); + + jest.runAllImmediates(); + + expect(someValue).toBe('foobar'); +}); diff --git a/e2e/fake-promises/immediate/fake-promises.js b/e2e/fake-promises/immediate/fake-promises.js new file mode 100644 index 000000000000..a8d155852e2d --- /dev/null +++ b/e2e/fake-promises/immediate/fake-promises.js @@ -0,0 +1,10 @@ +/** + * Copyright (c) 2014-present, Facebook, Inc. 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'; + +global.Promise = require('promise/setimmediate'); diff --git a/e2e/fake-promises/immediate/package.json b/e2e/fake-promises/immediate/package.json new file mode 100644 index 000000000000..0f50640514e1 --- /dev/null +++ b/e2e/fake-promises/immediate/package.json @@ -0,0 +1,9 @@ +{ + "jest": { + "timers": "fake", + "setupFiles": [ + "/fake-promises" + ], + "testEnvironment": "node" + } +} diff --git a/package.json b/package.json index 6d55c5309e16..d6ea708d7db8 100644 --- a/package.json +++ b/package.json @@ -59,6 +59,7 @@ "prettier": "^1.13.3", "prettylint": "^1.0.0", "progress": "^2.0.0", + "promise": "^8.0.2", "readable-stream": "^3.0.3", "regenerator-runtime": "^0.11.0", "resolve": "^1.4.0", diff --git a/packages/jest-util/src/__tests__/fake_timers.test.js b/packages/jest-util/src/__tests__/fake_timers.test.js index 14de3805d641..a9d8434532bf 100644 --- a/packages/jest-util/src/__tests__/fake_timers.test.js +++ b/packages/jest-util/src/__tests__/fake_timers.test.js @@ -110,13 +110,13 @@ describe('FakeTimers', () => { global.process.nextTick(mock1); global.process.nextTick(mock2); - expect(mock1.mock.calls.length).toBe(0); - expect(mock2.mock.calls.length).toBe(0); + expect(mock1).toHaveBeenCalledTimes(0); + expect(mock2).toHaveBeenCalledTimes(0); timers.runAllTicks(); - expect(mock1.mock.calls.length).toBe(1); - expect(mock2.mock.calls.length).toBe(1); + expect(mock1).toHaveBeenCalledTimes(1); + expect(mock2).toHaveBeenCalledTimes(1); expect(runOrder).toEqual(['mock1', 'mock2']); }); @@ -132,7 +132,7 @@ describe('FakeTimers', () => { timers.useFakeTimers(); timers.runAllTicks(); - expect(nextTick.mock.calls.length).toBe(0); + expect(nextTick).toHaveBeenCalledTimes(0); }); it('only runs a scheduled callback once', () => { @@ -147,13 +147,13 @@ describe('FakeTimers', () => { const mock1 = jest.fn(); global.process.nextTick(mock1); - expect(mock1.mock.calls.length).toBe(0); + expect(mock1).toHaveBeenCalledTimes(0); timers.runAllTicks(); - expect(mock1.mock.calls.length).toBe(1); + expect(mock1).toHaveBeenCalledTimes(1); timers.runAllTicks(); - expect(mock1.mock.calls.length).toBe(1); + expect(mock1).toHaveBeenCalledTimes(1); }); it('cancels a callback even from native nextTick', () => { @@ -171,13 +171,13 @@ describe('FakeTimers', () => { const mock1 = jest.fn(); global.process.nextTick(mock1); timers.runAllTicks(); - expect(mock1.mock.calls.length).toBe(1); - expect(nativeNextTick.mock.calls.length).toBe(1); + expect(mock1).toHaveBeenCalledTimes(1); + expect(nativeNextTick).toHaveBeenCalledTimes(1); // Now imagine we fast forward to the next real tick. We need to be sure // that native nextTick doesn't try to run the callback again nativeNextTick.mock.calls[0][0](); - expect(mock1.mock.calls.length).toBe(1); + expect(mock1).toHaveBeenCalledTimes(1); }); it('cancels a callback even from native setImmediate', () => { @@ -194,12 +194,12 @@ describe('FakeTimers', () => { const mock1 = jest.fn(); global.setImmediate(mock1); timers.runAllImmediates(); - expect(mock1.mock.calls.length).toBe(1); - expect(nativeSetImmediate.mock.calls.length).toBe(1); + expect(mock1).toHaveBeenCalledTimes(1); + expect(nativeSetImmediate).toHaveBeenCalledTimes(1); // ensure that native setImmediate doesn't try to run the callback again nativeSetImmediate.mock.calls[0][0](); - expect(mock1.mock.calls.length).toBe(1); + expect(mock1).toHaveBeenCalledTimes(1); }); it('doesnt run a tick callback if native nextTick already did', () => { @@ -219,11 +219,11 @@ describe('FakeTimers', () => { // Emulate native nextTick running... nativeNextTick.mock.calls[0][0](); - expect(mock1.mock.calls.length).toBe(1); + expect(mock1).toHaveBeenCalledTimes(1); // Ensure runAllTicks() doesn't run the callback again timers.runAllTicks(); - expect(mock1.mock.calls.length).toBe(1); + expect(mock1).toHaveBeenCalledTimes(1); }); it('doesnt run immediate if native setImmediate already did', () => { @@ -242,11 +242,11 @@ describe('FakeTimers', () => { // Emulate native setImmediate running... nativeSetImmediate.mock.calls[0][0](); - expect(mock1.mock.calls.length).toBe(1); + expect(mock1).toHaveBeenCalledTimes(1); // Ensure runAllTicks() doesn't run the callback again timers.runAllImmediates(); - expect(mock1.mock.calls.length).toBe(1); + expect(mock1).toHaveBeenCalledTimes(1); }); it('native doesnt run immediate if fake already did', () => { @@ -265,12 +265,12 @@ describe('FakeTimers', () => { //run all immediates now timers.runAllImmediates(); - expect(mock1.mock.calls.length).toBe(1); + expect(mock1).toHaveBeenCalledTimes(1); // Emulate native setImmediate running ensuring it doesn't re-run nativeSetImmediate.mock.calls[0][0](); - expect(mock1.mock.calls.length).toBe(1); + expect(mock1).toHaveBeenCalledTimes(1); }); it('throws before allowing infinite recursion', () => { @@ -376,13 +376,13 @@ describe('FakeTimers', () => { const fn = jest.fn(); global.setTimeout(fn, 0); - expect(fn.mock.calls.length).toBe(0); + expect(fn).toHaveBeenCalledTimes(0); timers.runAllTimers(); - expect(fn.mock.calls.length).toBe(1); + expect(fn).toHaveBeenCalledTimes(1); timers.runAllTimers(); - expect(fn.mock.calls.length).toBe(1); + expect(fn).toHaveBeenCalledTimes(1); }); it('runs callbacks with arguments after the interval', () => { @@ -394,7 +394,8 @@ describe('FakeTimers', () => { global.setTimeout(fn, 0, 'mockArg1', 'mockArg2'); timers.runAllTimers(); - expect(fn.mock.calls).toEqual([['mockArg1', 'mockArg2']]); + expect(fn).toHaveBeenCalledTimes(1); + expect(fn).toHaveBeenCalledWith('mockArg1', 'mockArg2'); }); it('doesnt pass the callback to native setTimeout', () => { @@ -412,8 +413,8 @@ describe('FakeTimers', () => { global.setTimeout(mock1, 0); timers.runAllTimers(); - expect(mock1.mock.calls.length).toBe(1); - expect(nativeSetTimeout.mock.calls.length).toBe(0); + expect(mock1).toHaveBeenCalledTimes(1); + expect(nativeSetTimeout).toHaveBeenCalledTimes(0); }); it('throws before allowing infinite recursion', () => { @@ -449,10 +450,10 @@ describe('FakeTimers', () => { global.setTimeout(() => { process.nextTick(fn); }, 0); - expect(fn.mock.calls.length).toBe(0); + expect(fn).toHaveBeenCalledTimes(0); timers.runAllTimers(); - expect(fn.mock.calls.length).toBe(1); + expect(fn).toHaveBeenCalledTimes(1); }); }); @@ -540,7 +541,7 @@ describe('FakeTimers', () => { timers.reset(); timers.runAllTimers(); - expect(mock1.mock.calls.length).toBe(0); + expect(mock1).toHaveBeenCalledTimes(0); }); it('resets all pending setIntervals', () => { @@ -553,7 +554,7 @@ describe('FakeTimers', () => { timers.reset(); timers.runAllTimers(); - expect(mock1.mock.calls.length).toBe(0); + expect(mock1).toHaveBeenCalledTimes(0); }); it('resets all pending ticks callbacks & immediates', () => { @@ -573,7 +574,7 @@ describe('FakeTimers', () => { timers.reset(); timers.runAllTicks(); timers.runAllImmediates(); - expect(mock1.mock.calls.length).toBe(0); + expect(mock1).toHaveBeenCalledTimes(0); }); it('resets current advanceTimersByTime time cursor', () => { @@ -589,7 +590,7 @@ describe('FakeTimers', () => { global.setTimeout(mock1, 100); timers.advanceTimersByTime(50); - expect(mock1.mock.calls.length).toBe(0); + expect(mock1).toHaveBeenCalledTimes(0); }); }); @@ -685,29 +686,29 @@ describe('FakeTimers', () => { timers.runWithRealTimers(() => { global.clearInterval(); }); - expect(nativeClearInterval.mock.calls.length).toBe(1); - expect(global.clearInterval.mock.calls.length).toBe(0); + expect(nativeClearInterval).toHaveBeenCalledTimes(1); + expect(global.clearInterval).toHaveBeenCalledTimes(0); // clearTimeout() timers.runWithRealTimers(() => { global.clearTimeout(); }); - expect(nativeClearTimeout.mock.calls.length).toBe(1); - expect(global.clearTimeout.mock.calls.length).toBe(0); + expect(nativeClearTimeout).toHaveBeenCalledTimes(1); + expect(global.clearTimeout).toHaveBeenCalledTimes(0); // setInterval() timers.runWithRealTimers(() => { global.setInterval(); }); - expect(nativeSetInterval.mock.calls.length).toBe(1); - expect(global.setInterval.mock.calls.length).toBe(0); + expect(nativeSetInterval).toHaveBeenCalledTimes(1); + expect(global.setInterval).toHaveBeenCalledTimes(0); // setTimeout() timers.runWithRealTimers(() => { global.setTimeout(); }); - expect(nativeSetTimeout.mock.calls.length).toBe(1); - expect(global.setTimeout.mock.calls.length).toBe(0); + expect(nativeSetTimeout).toHaveBeenCalledTimes(1); + expect(global.setTimeout).toHaveBeenCalledTimes(0); }); it('resets mock timers after executing callback', () => { @@ -730,45 +731,45 @@ describe('FakeTimers', () => { timers.runWithRealTimers(() => { global.clearInterval(); }); - expect(nativeClearInterval.mock.calls.length).toBe(1); - expect(global.clearInterval.mock.calls.length).toBe(0); + expect(nativeClearInterval).toHaveBeenCalledTimes(1); + expect(global.clearInterval).toHaveBeenCalledTimes(0); global.clearInterval(); - expect(nativeClearInterval.mock.calls.length).toBe(1); - expect(global.clearInterval.mock.calls.length).toBe(1); + expect(nativeClearInterval).toHaveBeenCalledTimes(1); + expect(global.clearInterval).toHaveBeenCalledTimes(1); // clearTimeout() timers.runWithRealTimers(() => { global.clearTimeout(); }); - expect(nativeClearTimeout.mock.calls.length).toBe(1); - expect(global.clearTimeout.mock.calls.length).toBe(0); + expect(nativeClearTimeout).toHaveBeenCalledTimes(1); + expect(global.clearTimeout).toHaveBeenCalledTimes(0); global.clearTimeout(); - expect(nativeClearTimeout.mock.calls.length).toBe(1); - expect(global.clearTimeout.mock.calls.length).toBe(1); + expect(nativeClearTimeout).toHaveBeenCalledTimes(1); + expect(global.clearTimeout).toHaveBeenCalledTimes(1); // setInterval() timers.runWithRealTimers(() => { global.setInterval(); }); - expect(nativeSetInterval.mock.calls.length).toBe(1); - expect(global.setInterval.mock.calls.length).toBe(0); + expect(nativeSetInterval).toHaveBeenCalledTimes(1); + expect(global.setInterval).toHaveBeenCalledTimes(0); global.setInterval(); - expect(nativeSetInterval.mock.calls.length).toBe(1); - expect(global.setInterval.mock.calls.length).toBe(1); + expect(nativeSetInterval).toHaveBeenCalledTimes(1); + expect(global.setInterval).toHaveBeenCalledTimes(1); // setTimeout() timers.runWithRealTimers(() => { global.setTimeout(); }); - expect(nativeSetTimeout.mock.calls.length).toBe(1); - expect(global.setTimeout.mock.calls.length).toBe(0); + expect(nativeSetTimeout).toHaveBeenCalledTimes(1); + expect(global.setTimeout).toHaveBeenCalledTimes(0); global.setTimeout(); - expect(nativeSetTimeout.mock.calls.length).toBe(1); - expect(global.setTimeout.mock.calls.length).toBe(1); + expect(nativeSetTimeout).toHaveBeenCalledTimes(1); + expect(global.setTimeout).toHaveBeenCalledTimes(1); }); it('resets mock timer functions even if callback throws', () => { @@ -786,12 +787,12 @@ describe('FakeTimers', () => { throw new Error('test'); }); }).toThrow(new Error('test')); - expect(nativeSetTimeout.mock.calls.length).toBe(1); - expect(global.setTimeout.mock.calls.length).toBe(0); + expect(nativeSetTimeout).toHaveBeenCalledTimes(1); + expect(global.setTimeout).toHaveBeenCalledTimes(0); global.setTimeout(); - expect(nativeSetTimeout.mock.calls.length).toBe(1); - expect(global.setTimeout.mock.calls.length).toBe(1); + expect(nativeSetTimeout).toHaveBeenCalledTimes(1); + expect(global.setTimeout).toHaveBeenCalledTimes(1); }); }); diff --git a/yarn.lock b/yarn.lock index 3a6e330530d6..d02d14fca5e3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1633,7 +1633,7 @@ art@^0.10.0: resolved "https://registry.yarnpkg.com/art/-/art-0.10.3.tgz#b01d84a968ccce6208df55a733838c96caeeaea2" integrity sha512-HXwbdofRTiJT6qZX/FnchtldzJjS3vkLJxQilc3Xj+ma2MXjY4UAyQ0ls1XZYVnDvVIBiFZbC6QsvtW86TD6tQ== -asap@^2.0.0, asap@~2.0.3: +asap@^2.0.0, asap@~2.0.3, asap@~2.0.6: version "2.0.6" resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" integrity sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY= @@ -10779,6 +10779,13 @@ promise@^7.1.1: dependencies: asap "~2.0.3" +promise@^8.0.2: + version "8.0.2" + resolved "https://registry.yarnpkg.com/promise/-/promise-8.0.2.tgz#9dcd0672192c589477d56891271bdc27547ae9f0" + integrity sha512-EIyzM39FpVOMbqgzEHhxdrEhtOSDOtjMZQ0M6iVfCE+kWNgCkAyOdnuCWqfmflylftfadU6FkiMgHZA2kUzwRw== + dependencies: + asap "~2.0.6" + prompts@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/prompts/-/prompts-1.1.0.tgz#8a8b33030943e8355e06f81bebc436f7aa669d42"