-
-
Notifications
You must be signed in to change notification settings - Fork 34k
test_runner: introduces a new MockTimers API #47775
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
nodejs-github-bot
merged 57 commits into
nodejs:main
from
ErickWendel:test_runner/introduce-fake-timers
Jun 22, 2023
Merged
Changes from 1 commit
Commits
Show all changes
57 commits
Select commit
Hold shift + click to select a range
568ad96
test_runner: add initial draft for fakeTimers
ErickWendel ac0fab3
test_runner: move fakerTimers to mock module
ErickWendel e54a162
test_runner: change fakeTimers prop name
ErickWendel 71ffd10
test_runner: implement PriorityQueue for timers
ErickWendel a0f8afd
test_runner: add @ljharb suggestion
ErickWendel 0f55f65
test_runner: add @benjamingr suggestion
ErickWendel e34a426
test_runner: add fake setTimeout initial impl
ErickWendel df35174
test_runner: add @molow suggestion
ErickWendel e5af52f
test_runner: fix a test
ErickWendel a22321f
test_runner: rename from fakeTimers to mockTimers
ErickWendel 21be0bc
test_runner: add experimental warning
ErickWendel 102a830
test_runner: fix tests
ErickWendel 1d30e47
test_runner: add @ljharb suggestion
ErickWendel 0cb4e7c
test_runner: fix possible truthy evaluation on tick by @ljharb
ErickWendel a53aedc
test_runner: add tests for clearTimeout
ErickWendel 1a2cf34
test_runner: add tests for setInterval modules
ErickWendel db2a79f
test_runner: add tests for clearInterval modules
ErickWendel f200467
test_runner: add impl for timers.promises.setInterval function
ErickWendel cc652fe
test_runner: fix setInterval algorithm
ErickWendel 942f504
test_runner: add abortController support for promises.setTimeout and …
ErickWendel bb75287
test_runner: add test cases for abortController and remove listeners …
ErickWendel b0baf00
test_runner: change import order
ErickWendel 92bf115
test_runner: add ArrayPrototypeAt instead of [].at
ErickWendel 1fe731e
test_runner: return safe asyncIterator
ErickWendel 08f27ba
test_runner: make promises.setInterval update time during iterations
ErickWendel 3e39782
test_runner: add __proto__ null while returning the object
ErickWendel a563ce9
test_runner: make promises.setInterval work with abortControllers
ErickWendel 17381f1
test_runner: rm unsafe array iteration and comments
ErickWendel 3677482
test_runner: avoid avoid code repetition
ErickWendel 1825426
test_runner: (rollback) avoid avoid code repetition
ErickWendel abc7c96
test_runner: rm unecessarly PromiseRejection
ErickWendel 87b0d36
test_runner: add timers.reset on test postRun
ErickWendel a001e65
test_runner: add config for choosing timers to use, error handling an…
ErickWendel d168614
test_runner: implement releaseAllTimers function
ErickWendel 1e09a22
test_runner: reach 100% code coverage
ErickWendel 89b489b
test_runner: rename function to runAll
ErickWendel 2b64a4a
fix flaky test
ErickWendel a9ed28d
add abort once flag
ErickWendel b383a1c
check that timeout will only be called when reaches the specified tim…
ErickWendel ba725f4
fix lint problems
ErickWendel 1bcbe65
test_runner: add initial doc
ErickWendel 7c65e64
test_runner: fix heading
ErickWendel aaf7070
test_runner: fix text
ErickWendel ac9f5b6
test_runner: fix links
ErickWendel 13fab2b
test_runner: add docs for timers.tick
ErickWendel 296f5b0
test_runner: add docs for timers.runAll
ErickWendel a75ddb4
doc rm empty spaces
ErickWendel 1bee321
Update test/parallel/test-runner-mock-timers.js
ErickWendel bc8fea7
Update lib/internal/test_runner/mock/mock_timers.js
ErickWendel 1bfd7b8
format test.md
ErickWendel d2c9a1a
add 1ms to tick to fix flakyness
ErickWendel 93950f5
test_runner: add 50ms to .tick so setInterval will not be flaky
ErickWendel 49e8eba
test_runner: revert last commit
ErickWendel 4d3a45c
founde the bug 🐛
MoLow 12772d1
Apply suggestions from code review
ErickWendel 5c9e425
apply suggestions from review
ErickWendel 0424bf5
add info about support for destructuring from modules
ErickWendel File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,110 @@ | ||
| 'use strict'; | ||
|
|
||
| const { | ||
| DateNow, | ||
| SafeMap, | ||
| Symbol, | ||
| globalThis, | ||
| } = primordials; | ||
|
|
||
| class Timers { | ||
| constructor() { | ||
| this.timers = new SafeMap(); | ||
|
|
||
| this.setTimeout = this.#createTimer.bind(this, false); | ||
| this.clearTimeout = this.#clearTimer.bind(this); | ||
| this.setInterval = this.#createTimer.bind(this, true); | ||
| this.clearInterval = this.#clearTimer.bind(this); | ||
| } | ||
|
|
||
| #createTimer(isInterval, callback, delay, ...args) { | ||
| const timerId = Symbol('kTimerId'); | ||
| const timer = { | ||
| id: timerId, | ||
| callback, | ||
| time: DateNow() + delay, | ||
ErickWendel marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| interval: isInterval, | ||
| args, | ||
| }; | ||
| this.timers.set(timerId, timer); | ||
| return timerId; | ||
| } | ||
|
|
||
| #clearTimer(timerId) { | ||
| this.timers.delete(timerId); | ||
| } | ||
|
|
||
| } | ||
|
|
||
| let realSetTimeout; | ||
| let realClearTimeout; | ||
| let realSetInterval; | ||
| let realClearInterval; | ||
|
|
||
| class FakeTimers { | ||
| constructor() { | ||
| this.fakeTimers = {}; | ||
| this.isEnabled = false; | ||
| this.now = DateNow(); | ||
| } | ||
|
|
||
| tick(time = 0) { | ||
|
|
||
| // if (!this.isEnabled) { | ||
| // throw new Error('you should enable fakeTimers first by calling the .enable function'); | ||
| // } | ||
|
|
||
| this.now += time; | ||
| const timers = this.fakeTimers.timers; | ||
|
|
||
| for (const timer of timers.values()) { | ||
ErickWendel marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| if (!(this.now >= timer.time)) continue; | ||
|
|
||
| timer.callback(...timer.args); | ||
| if (timer.interval) { | ||
| timer.time = this.now + (timer.time - this.now) % timer.args[0]; | ||
| continue; | ||
| } | ||
|
|
||
| timers.delete(timer.id); | ||
| } | ||
| } | ||
|
|
||
| enable() { | ||
| // if (this.isEnabled) { | ||
| // throw new Error('fakeTimers is already enabled!'); | ||
| // } | ||
| this.now = DateNow(); | ||
| this.isEnabled = true; | ||
| this.fakeTimers = new Timers(); | ||
|
|
||
| realSetTimeout = globalThis.setTimeout; | ||
| realClearTimeout = globalThis.clearTimeout; | ||
| realSetInterval = globalThis.setInterval; | ||
| realClearInterval = globalThis.clearInterval; | ||
|
|
||
| globalThis.setTimeout = this.fakeTimers.setTimeout; | ||
ErickWendel marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| globalThis.clearTimeout = this.fakeTimers.clearTimeout; | ||
| globalThis.setInterval = this.fakeTimers.setInterval; | ||
| globalThis.clearInterval = this.fakeTimers.clearInterval; | ||
|
|
||
| } | ||
|
|
||
| reset() { | ||
| this.isEnabled = false; | ||
| this.fakeTimers = {}; | ||
|
|
||
| // Restore the real timer functions | ||
| globalThis.setTimeout = realSetTimeout; | ||
| globalThis.clearTimeout = realClearTimeout; | ||
| globalThis.setInterval = realSetInterval; | ||
| globalThis.clearInterval = realClearInterval; | ||
| } | ||
|
|
||
| releaseAllTimers() { | ||
|
|
||
| } | ||
| } | ||
|
|
||
| module.exports = { FakeTimers }; | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,46 @@ | ||
| 'use strict'; | ||
| const common = require('../common'); | ||
| process.env.NODE_TEST_KNOWN_GLOBALS = 0; | ||
|
|
||
| const assert = require('node:assert'); | ||
| const { fakeTimers, it, mock, afterEach, describe } = require('node:test'); | ||
| describe('Faketimers Test Suite', () => { | ||
|
|
||
| describe('setTimeout Suite', () => { | ||
| afterEach(() => fakeTimers.reset()); | ||
|
|
||
| it('should advance in time and trigger timers when calling the .tick function', (t) => { | ||
| fakeTimers.enable(); | ||
|
|
||
| const fn = mock.fn(() => {}); | ||
|
|
||
| global.setTimeout(fn, 4000); | ||
|
|
||
| fakeTimers.tick(4000); | ||
| assert.ok(fn.mock.callCount()); | ||
| }); | ||
|
|
||
| it('should advance in time and trigger timers when calling the .tick function multiple times', (t) => { | ||
| fakeTimers.enable(); | ||
| const fn = mock.fn(); | ||
|
|
||
| global.setTimeout(fn, 2000); | ||
|
|
||
| fakeTimers.tick(1000); | ||
| fakeTimers.tick(1000); | ||
|
|
||
| assert.strictEqual(fn.mock.callCount(), 1); | ||
| }); | ||
|
|
||
| it('should keep setTimeout working if fakeTimers are disabled', (t, done) => { | ||
| const now = Date.now(); | ||
| const timeout = 2; | ||
| const expected = () => now - timeout; | ||
| global.setTimeout(common.mustCall(() => { | ||
| assert.strictEqual(now - timeout, expected()); | ||
| done(); | ||
| }), timeout); | ||
| }); | ||
|
|
||
| }); | ||
| }); |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.