Skip to content
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

test_runner: introduces a new MockTimers API #47775

Merged

Conversation

ErickWendel
Copy link
Member

@ErickWendel ErickWendel commented Apr 28, 2023

This PR introduces a new FakeTimers API for the native Node.js test runner.

I'm opening it for review as I've implemented all features for this initial version (it's still missing docs but I think we can start moving forward while I write them)

Backlog

  • - accept a list of "Which timers/things do I mock?"
  • - add an experimental warning
  • - tests
  • - 100% code coverage
  • - docs
  • - be part of the mock module
  • - works with globals
  • - works with require("timers/promises")
  • - works with require("timers")
  • - have a .reset function to clear the state
  • - have a .releaseAllTimers function to trigger all functions
  • - .reset calls itself after an .it test

API:

  • - globals
    • - setTimeout
    • - clearTimeout
    • - setInterval
    • - clearInterval
  • - timers
    • - setTimeout
    • - clearTimeout
    • - setInterval
    • - clearInterval
  • - timers/promises
    • - setTimeout
    • - setInterval

For the next version:

  • - Date.now
  • - performance.now
  • - scheduler.wait
  • - queueMicrotask/process.nextTick
  • - add tests for edge cases

MockTimers Design API

MockTimers.enable(['setInterval', 'setTimeout' ]) // enable fake timers
MockTimers.reset()  // clean up to the original state
MockTimers.tick(100) // advance in time by 100ms
MockTimers.runAll() // release all timers

Usage example:

import assert from 'node:assert';
import { test } from 'node:test';

test('mocks setTimeout to be executed synchronously without having to actually wait for it', (context) => {
  const fn = context.mock.fn();
  context.mock.timers.enable(['setTimeout']);
  const nineSecs = 9000;
  setTimeout(fn, nineSecs);

  const threeSeconds = 3000;
  context.mock.timers.tick(threeSeconds);
  context.mock.timers.tick(threeSeconds);
  context.mock.timers.tick(threeSeconds);

  assert.strictEqual(fn.mock.callCount(), 1);
});

Signed-off-by: Erick Wendel <erick.workspace@gmail.com>
@nodejs-github-bot
Copy link
Collaborator

nodejs-github-bot commented Apr 28, 2023

Review requested:

  • @nodejs/test_runner

@ErickWendel ErickWendel self-assigned this Apr 28, 2023
@nodejs-github-bot nodejs-github-bot added lib / src Issues and PRs related to general changes in the lib or src directory. needs-ci PRs that need a full CI run. labels Apr 28, 2023
@benjamingr
Copy link
Member

benjamingr commented Apr 30, 2023

Hey message me (wherever) I am a maintainer of sinon/jest's fake timers and would be happy to give feedback. I'll also leave some on this PR

@benjamingr
Copy link
Member

I'm wondering what the right layer for this is:

  • We can do it with the approach you picked (and userland libraries like sinon use) which is overriding setTimeout/setInterval etc.
  • We can override it one level deeper at the Timeout class and instead of calling binding.scheduleTimer keep the linked list / priority queue machinery and only mock out interoperating with libuv.
  • We can override one level deeper at timers.cc (e.g. override RunTimers / ScheduleTimer on node's v8 env)

It is worth mentioning that places that need fake time/timers like HTTP server date headers does new Date() so presumably that'd either have to work or be adjusted to something that does.

@benjamingr
Copy link
Member

Also cc some sinon folks @SimenB @fatso83 @mroderick

Also note you can use our tests (super simple) https://github.com/sinonjs/fake-timers/blob/main/test/fake-timers-test.js

@ErickWendel
Copy link
Member Author

That's great @benjamingr gonna check it out soon! I loved the concerns and suggestions surely it's helpful and will help making this feature a complete solution!

@tniessen
Copy link
Member

tniessen commented May 1, 2023

We can do it with the approach you picked (and userland libraries like sinon use) which is overriding setTimeout/setInterval etc.

In that case, I am wondering if there is any advantage of having it in core, besides convenience.

If we commit to something like this at the lower levels that you mention, and not just through some monkey-patching in the test runner, we should evaluate spec-compliance and various side-effects. Timers are notoriously tricky in Node.js.

Copy link
Contributor

@cjihrig cjihrig left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few comments:

  • I don't think this should be a separate API inside of the test runner, but rather a component of the existing mock functionality.
  • I don't think this should change the code of any parts of core other than the test runner.

lib/internal/test_runner/test.js Outdated Show resolved Hide resolved
@benjamingr
Copy link
Member

@tniessen

In that case, I am wondering if there is any advantage of having it in core, besides convenience.

Other than convenience, the motivation in several cases is that Node dates/timers use primordials which makes it impossible to mock things like http date headers impossible in userland without hacks.

@ErickWendel ErickWendel force-pushed the test_runner/introduce-fake-timers branch from 7a71461 to 278893a Compare May 1, 2023 17:02
Signed-off-by: Erick Wendel <erick.workspace@gmail.com>
@ErickWendel ErickWendel force-pushed the test_runner/introduce-fake-timers branch from 278893a to ac0fab3 Compare May 1, 2023 17:08
@ljharb
Copy link
Member

ljharb commented May 1, 2023

@benjamingr wouldn't that defeat the purpose of primordials tho? there shouldn't be a way for later-run code to compromise first-run code.

Signed-off-by: Erick Wendel <erick.workspace@gmail.com>
@ErickWendel ErickWendel force-pushed the test_runner/introduce-fake-timers branch from ed3a873 to 3670374 Compare May 1, 2023 18:33
Signed-off-by: Erick Wendel <erick.workspace@gmail.com>
@ErickWendel ErickWendel force-pushed the test_runner/introduce-fake-timers branch from 3670374 to 71ffd10 Compare May 1, 2023 18:33
Signed-off-by: Erick Wendel <erick.workspace@gmail.com>
@ErickWendel ErickWendel force-pushed the test_runner/introduce-fake-timers branch from 407644b to a0f8afd Compare May 1, 2023 18:43
Signed-off-by: Erick Wendel <erick.workspace@gmail.com>
RafaelGSS added a commit to RafaelGSS/node that referenced this pull request Jul 4, 2023
Notable changes:

crypto:
  * update root certificates to NSS 3.90 (Node.js GitHub Bot) nodejs#48416
doc:
  * add vmoroz to collaborators (Vladimir Morozov) nodejs#48527
  * add kvakil to collaborators (Keyhan Vakil) nodejs#48449
fs, stream:
  * initial `Symbol.dispose` and `Symbol.asyncDispose` support (Moshe Atlow) nodejs#48518
test_runner:
  * (SEMVER-MINOR) add initial draft for fakeTimers (Erick Wendel) nodejs#47775
tls:
  * (SEMVER-MINOR) add ALPNCallback server option for dynamic ALPN negotiation (Tim Perry) nodejs#45190

PR-URL: nodejs#48643
RafaelGSS added a commit that referenced this pull request Jul 5, 2023
Notable changes:

crypto:
  * update root certificates to NSS 3.90 (Node.js GitHub Bot) #48416
doc:
  * add vmoroz to collaborators (Vladimir Morozov) #48527
  * add kvakil to collaborators (Keyhan Vakil) #48449
fs, stream:
  * initial `Symbol.dispose` and `Symbol.asyncDispose` support (Moshe Atlow) #48518
test_runner:
  * (SEMVER-MINOR) add initial draft for fakeTimers (Erick Wendel) #47775
tls:
  * (SEMVER-MINOR) add ALPNCallback server option for dynamic ALPN negotiation (Tim Perry) #45190

PR-URL: #48643
Ceres6 pushed a commit to Ceres6/node that referenced this pull request Aug 14, 2023
Signed-off-by: Erick Wendel <erick.workspace@gmail.com>
PR-URL: nodejs#47775
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
Reviewed-By: Moshe Atlow <moshe@atlow.co.il>
Ceres6 pushed a commit to Ceres6/node that referenced this pull request Aug 14, 2023
Notable changes:

crypto:
  * update root certificates to NSS 3.90 (Node.js GitHub Bot) nodejs#48416
doc:
  * add vmoroz to collaborators (Vladimir Morozov) nodejs#48527
  * add kvakil to collaborators (Keyhan Vakil) nodejs#48449
fs, stream:
  * initial `Symbol.dispose` and `Symbol.asyncDispose` support (Moshe Atlow) nodejs#48518
test_runner:
  * (SEMVER-MINOR) add initial draft for fakeTimers (Erick Wendel) nodejs#47775
tls:
  * (SEMVER-MINOR) add ALPNCallback server option for dynamic ALPN negotiation (Tim Perry) nodejs#45190

PR-URL: nodejs#48643
Ceres6 pushed a commit to Ceres6/node that referenced this pull request Aug 14, 2023
Signed-off-by: Erick Wendel <erick.workspace@gmail.com>
PR-URL: nodejs#47775
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
Reviewed-By: Moshe Atlow <moshe@atlow.co.il>
Ceres6 pushed a commit to Ceres6/node that referenced this pull request Aug 14, 2023
Notable changes:

crypto:
  * update root certificates to NSS 3.90 (Node.js GitHub Bot) nodejs#48416
doc:
  * add vmoroz to collaborators (Vladimir Morozov) nodejs#48527
  * add kvakil to collaborators (Keyhan Vakil) nodejs#48449
fs, stream:
  * initial `Symbol.dispose` and `Symbol.asyncDispose` support (Moshe Atlow) nodejs#48518
test_runner:
  * (SEMVER-MINOR) add initial draft for fakeTimers (Erick Wendel) nodejs#47775
tls:
  * (SEMVER-MINOR) add ALPNCallback server option for dynamic ALPN negotiation (Tim Perry) nodejs#45190

PR-URL: nodejs#48643
@ruyadorno
Copy link
Member

This commit has a broken test when cherry-picked into v18.x-staging. It's going to need manual backporting in case we want it in v18.

@ruyadorno ruyadorno added the backport-requested-v18.x PRs awaiting manual backport to the v18.x-staging branch. label Sep 10, 2023
atlowChemi pushed a commit to atlowChemi/node that referenced this pull request Sep 12, 2023
Signed-off-by: Erick Wendel <erick.workspace@gmail.com>
PR-URL: nodejs#47775
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
Reviewed-By: Moshe Atlow <moshe@atlow.co.il>
atlowChemi pushed a commit to atlowChemi/node that referenced this pull request Sep 14, 2023
Signed-off-by: Erick Wendel <erick.workspace@gmail.com>
PR-URL: nodejs#47775
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
Reviewed-By: Moshe Atlow <moshe@atlow.co.il>
atlowChemi pushed a commit to atlowChemi/node that referenced this pull request Sep 18, 2023
Signed-off-by: Erick Wendel <erick.workspace@gmail.com>
PR-URL: nodejs#47775
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
Reviewed-By: Moshe Atlow <moshe@atlow.co.il>
@ruyadorno ruyadorno added backport-open-v18.x Indicate that the PR has an open backport. and removed backport-requested-v18.x PRs awaiting manual backport to the v18.x-staging branch. labels Sep 18, 2023
targos pushed a commit that referenced this pull request Oct 28, 2023
Signed-off-by: Erick Wendel <erick.workspace@gmail.com>
PR-URL: #47775
Backport-PR-URL: #49618
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
Reviewed-By: Moshe Atlow <moshe@atlow.co.il>
@targos targos added backported-to-v18.x PRs backported to the v18.x-staging branch. and removed backport-open-v18.x Indicate that the PR has an open backport. labels Oct 28, 2023
targos pushed a commit that referenced this pull request Oct 28, 2023
Signed-off-by: Erick Wendel <erick.workspace@gmail.com>
PR-URL: #47775
Backport-PR-URL: #49618
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
Reviewed-By: Moshe Atlow <moshe@atlow.co.il>
targos added a commit that referenced this pull request Nov 27, 2023
Notable changes:

deps:
  * (SEMVER-MINOR) update uvwasi to 0.0.19 (Node.js GitHub Bot) #49908
  * (SEMVER-MINOR) upgrade npm to 10.0.0 (npm team) #49423
doc:
  * add new TSC members (Michael Dawson) #48841
  * move and rename loaders section (Geoffrey Booth) #49261
esm:
  * use import attributes instead of import assertions (Antoine du Hamel) #50140
  * --experimental-default-type flag to flip module defaults (Geoffrey Booth) #49869
  * unflag import.meta.resolve (Guy Bedford) #49028
  * move hook execution to separate thread (Jacob Smith) #44710
  * leverage loaders when resolving subsequent loaders (Maël Nison) #43772
lib:
  * (SEMVER-MINOR) add api to detect whether source-maps are enabled (翠 / green) #46391
  * (SEMVER-MINOR) add tracing channel to diagnostics_channel (Stephen Belanger) #44943
src:
  * (SEMVER-MINOR) add cjs_module_lexer_version base64_version (Jithil P Ponnan) #45629
stream:
  * use bitmap in readable state (Benjamin Gruenbaum) #49745
test_runner:
  * (SEMVER-MINOR) accept `testOnly` in `run` (Moshe Atlow) #49753
  * (SEMVER-MINOR) add junit reporter (Moshe Atlow) #49614
  * (SEMVER-MINOR) expose location of tests (Colin Ihrig) #48975
  * (SEMVER-MINOR) add shards support (Raz Luvaton) #48639
  * (SEMVER-MINOR) add initial draft for fakeTimers (Erick Wendel) #47775
test_runner, cli:
  * (SEMVER-MINOR) add --test-concurrency flag (Colin Ihrig) #49996
tls:
  * (SEMVER-MINOR) add ALPNCallback server option for dynamic ALPN negotiation (Tim Perry) #45190
vm:
  * (SEMVER-MINOR) use import attributes instead of import assertions (Antoine du Hamel) #50141
wasi:
  * (SEMVER-MINOR) updates required for latest uvwasi version (Michael Dawson) #49908

PR-URL: TODO
targos added a commit that referenced this pull request Nov 28, 2023
Notable changes:

deps:
  * (SEMVER-MINOR) update uvwasi to 0.0.19 (Node.js GitHub Bot) #49908
  * (SEMVER-MINOR) upgrade npm to 10.2.3 (npm team) #50531
doc:
  * move and rename loaders section (Geoffrey Booth) #49261
esm:
  * use import attributes instead of import assertions (Antoine du Hamel) #50140
  * --experimental-default-type flag to flip module defaults (Geoffrey Booth) #49869
  * unflag import.meta.resolve (Guy Bedford) #49028
  * move hook execution to separate thread (Jacob Smith) #44710
  * leverage loaders when resolving subsequent loaders (Maël Nison) #43772
lib:
  * (SEMVER-MINOR) add api to detect whether source-maps are enabled (翠 / green) #46391
  * (SEMVER-MINOR) add tracing channel to diagnostics_channel (Stephen Belanger) #44943
src:
  * (SEMVER-MINOR) add cjs_module_lexer_version base64_version (Jithil P Ponnan) #45629
stream:
  * use bitmap in readable state (Benjamin Gruenbaum) #49745
test_runner:
  * (SEMVER-MINOR) accept `testOnly` in `run` (Moshe Atlow) #49753
  * (SEMVER-MINOR) add junit reporter (Moshe Atlow) #49614
  * (SEMVER-MINOR) expose location of tests (Colin Ihrig) #48975
  * (SEMVER-MINOR) add shards support (Raz Luvaton) #48639
  * (SEMVER-MINOR) add initial draft for fakeTimers (Erick Wendel) #47775
test_runner, cli:
  * (SEMVER-MINOR) add --test-concurrency flag (Colin Ihrig) #49996
tls:
  * (SEMVER-MINOR) add ALPNCallback server option for dynamic ALPN negotiation (Tim Perry) #45190
vm:
  * (SEMVER-MINOR) use import attributes instead of import assertions (Antoine du Hamel) #50141

PR-URL: #50953
targos added a commit that referenced this pull request Nov 29, 2023
Notable changes:

deps:
  * (SEMVER-MINOR) update uvwasi to 0.0.19 (Node.js GitHub Bot) #49908
  * (SEMVER-MINOR) upgrade npm to 10.2.3 (npm team) #50531
doc:
  * move and rename loaders section (Geoffrey Booth) #49261
esm:
  * use import attributes instead of import assertions (Antoine du Hamel) #50140
  * --experimental-default-type flag to flip module defaults (Geoffrey Booth) #49869
  * unflag import.meta.resolve (Guy Bedford) #49028
  * move hook execution to separate thread (Jacob Smith) #44710
  * leverage loaders when resolving subsequent loaders (Maël Nison) #43772
lib:
  * (SEMVER-MINOR) add api to detect whether source-maps are enabled (翠 / green) #46391
  * (SEMVER-MINOR) add tracing channel to diagnostics_channel (Stephen Belanger) #44943
src:
  * (SEMVER-MINOR) add cjs_module_lexer_version base64_version (Jithil P Ponnan) #45629
stream:
  * use bitmap in readable state (Benjamin Gruenbaum) #49745
test_runner:
  * (SEMVER-MINOR) accept `testOnly` in `run` (Moshe Atlow) #49753
  * (SEMVER-MINOR) add junit reporter (Moshe Atlow) #49614
  * (SEMVER-MINOR) expose location of tests (Colin Ihrig) #48975
  * (SEMVER-MINOR) add shards support (Raz Luvaton) #48639
  * (SEMVER-MINOR) add initial draft for fakeTimers (Erick Wendel) #47775
test_runner, cli:
  * (SEMVER-MINOR) add --test-concurrency flag (Colin Ihrig) #49996
tls:
  * (SEMVER-MINOR) add ALPNCallback server option for dynamic ALPN negotiation (Tim Perry) #45190
vm:
  * (SEMVER-MINOR) use import attributes instead of import assertions (Antoine du Hamel) #50141

PR-URL: #50953
sercher added a commit to sercher/graaljs that referenced this pull request Apr 25, 2024
Signed-off-by: Erick Wendel <erick.workspace@gmail.com>
PR-URL: nodejs/node#47775
Backport-PR-URL: nodejs/node#49618
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
Reviewed-By: Moshe Atlow <moshe@atlow.co.il>
sercher added a commit to sercher/graaljs that referenced this pull request Apr 25, 2024
Notable changes:

deps:
  * (SEMVER-MINOR) update uvwasi to 0.0.19 (Node.js GitHub Bot) nodejs/node#49908
  * (SEMVER-MINOR) upgrade npm to 10.2.3 (npm team) nodejs/node#50531
doc:
  * move and rename loaders section (Geoffrey Booth) nodejs/node#49261
esm:
  * use import attributes instead of import assertions (Antoine du Hamel) nodejs/node#50140
  * --experimental-default-type flag to flip module defaults (Geoffrey Booth) nodejs/node#49869
  * unflag import.meta.resolve (Guy Bedford) nodejs/node#49028
  * move hook execution to separate thread (Jacob Smith) nodejs/node#44710
  * leverage loaders when resolving subsequent loaders (Maël Nison) nodejs/node#43772
lib:
  * (SEMVER-MINOR) add api to detect whether source-maps are enabled (翠 / green) nodejs/node#46391
  * (SEMVER-MINOR) add tracing channel to diagnostics_channel (Stephen Belanger) nodejs/node#44943
src:
  * (SEMVER-MINOR) add cjs_module_lexer_version base64_version (Jithil P Ponnan) nodejs/node#45629
stream:
  * use bitmap in readable state (Benjamin Gruenbaum) nodejs/node#49745
test_runner:
  * (SEMVER-MINOR) accept `testOnly` in `run` (Moshe Atlow) nodejs/node#49753
  * (SEMVER-MINOR) add junit reporter (Moshe Atlow) nodejs/node#49614
  * (SEMVER-MINOR) expose location of tests (Colin Ihrig) nodejs/node#48975
  * (SEMVER-MINOR) add shards support (Raz Luvaton) nodejs/node#48639
  * (SEMVER-MINOR) add initial draft for fakeTimers (Erick Wendel) nodejs/node#47775
test_runner, cli:
  * (SEMVER-MINOR) add --test-concurrency flag (Colin Ihrig) nodejs/node#49996
tls:
  * (SEMVER-MINOR) add ALPNCallback server option for dynamic ALPN negotiation (Tim Perry) nodejs/node#45190
vm:
  * (SEMVER-MINOR) use import attributes instead of import assertions (Antoine du Hamel) nodejs/node#50141

PR-URL: nodejs/node#50953
sercher added a commit to sercher/graaljs that referenced this pull request Apr 25, 2024
Signed-off-by: Erick Wendel <erick.workspace@gmail.com>
PR-URL: nodejs/node#47775
Backport-PR-URL: nodejs/node#49618
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
Reviewed-By: Moshe Atlow <moshe@atlow.co.il>
sercher added a commit to sercher/graaljs that referenced this pull request Apr 25, 2024
Notable changes:

deps:
  * (SEMVER-MINOR) update uvwasi to 0.0.19 (Node.js GitHub Bot) nodejs/node#49908
  * (SEMVER-MINOR) upgrade npm to 10.2.3 (npm team) nodejs/node#50531
doc:
  * move and rename loaders section (Geoffrey Booth) nodejs/node#49261
esm:
  * use import attributes instead of import assertions (Antoine du Hamel) nodejs/node#50140
  * --experimental-default-type flag to flip module defaults (Geoffrey Booth) nodejs/node#49869
  * unflag import.meta.resolve (Guy Bedford) nodejs/node#49028
  * move hook execution to separate thread (Jacob Smith) nodejs/node#44710
  * leverage loaders when resolving subsequent loaders (Maël Nison) nodejs/node#43772
lib:
  * (SEMVER-MINOR) add api to detect whether source-maps are enabled (翠 / green) nodejs/node#46391
  * (SEMVER-MINOR) add tracing channel to diagnostics_channel (Stephen Belanger) nodejs/node#44943
src:
  * (SEMVER-MINOR) add cjs_module_lexer_version base64_version (Jithil P Ponnan) nodejs/node#45629
stream:
  * use bitmap in readable state (Benjamin Gruenbaum) nodejs/node#49745
test_runner:
  * (SEMVER-MINOR) accept `testOnly` in `run` (Moshe Atlow) nodejs/node#49753
  * (SEMVER-MINOR) add junit reporter (Moshe Atlow) nodejs/node#49614
  * (SEMVER-MINOR) expose location of tests (Colin Ihrig) nodejs/node#48975
  * (SEMVER-MINOR) add shards support (Raz Luvaton) nodejs/node#48639
  * (SEMVER-MINOR) add initial draft for fakeTimers (Erick Wendel) nodejs/node#47775
test_runner, cli:
  * (SEMVER-MINOR) add --test-concurrency flag (Colin Ihrig) nodejs/node#49996
tls:
  * (SEMVER-MINOR) add ALPNCallback server option for dynamic ALPN negotiation (Tim Perry) nodejs/node#45190
vm:
  * (SEMVER-MINOR) use import attributes instead of import assertions (Antoine du Hamel) nodejs/node#50141

PR-URL: nodejs/node#50953
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backported-to-v18.x PRs backported to the v18.x-staging branch. commit-queue-squash Add this label to instruct the Commit Queue to squash all the PR commits into the first one. experimental Issues and PRs related to experimental features. lib / src Issues and PRs related to general changes in the lib or src directory. needs-ci PRs that need a full CI run. notable-change PRs with changes that should be highlighted in changelogs. semver-minor PRs that contain new features and should be released in the next minor version. test_runner Issues and PRs related to the test runner subsystem.
Projects
None yet
Development

Successfully merging this pull request may close these issues.