-
Notifications
You must be signed in to change notification settings - Fork 108
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
fix: fake all supported timers by default #323
Conversation
@@ -1262,10 +1262,7 @@ function withGlobal(_global) { | |||
clock.methods = config.toFake || []; | |||
|
|||
if (clock.methods.length === 0) { | |||
// do not fake nextTick by default - GitHub#126 | |||
clock.methods = keys(timers).filter(function(key) { | |||
return key !== "nextTick" && key !== "queueMicrotask"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
seems docs were lying 🤷 queueMicrotask
was also not mocked by default
Codecov Report
@@ Coverage Diff @@
## master #323 +/- ##
==========================================
- Coverage 92.75% 92.71% -0.04%
==========================================
Files 1 1
Lines 552 549 -3
==========================================
- Hits 512 509 -3
Misses 40 40
Flags with carried forward coverage won't be shown. Click here to find out more.
Continue to review full report at Codecov.
|
src/fake-timers-src.js
Outdated
return key !== "nextTick" && key !== "queueMicrotask"; | ||
}); | ||
} | ||
clock.methods = config.toFake || keys(timers); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
another technically breaking change I guess - if people passed toFake: []
before, we faked everything. Seems like a bug fix to me to respect it, but maybe not 😀 If not, should just revert the last commit
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah I think this and the other one should be a major version if we land them.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can open a separate PR for it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can open a separate PR for it?
Yes
So here's the thing: promise libraries and other libraries use nextTick and microticks for scheduling so this is a pretty big breaking change. In principle I agree that we should mock this by default. |
test/fake-timers-test.js
Outdated
@@ -4504,19 +4504,6 @@ describe("FakeTimers", function() { | |||
assert(called); | |||
clock.uninstall(); | |||
}); | |||
|
|||
it("does not install by default - GitHub#126", function(done) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it be possible to change this test to assert nextTick is mocked if the behavior changes?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
changed the test above, I think that's fine?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
changed the test above, I think that's fine?
Yes, this is fine. It's implicitly true, as the code won't work unless nextTick
is synchronous.
Good point, should probably call it out in the readme.
👍 |
@benjamingr added a section to the readme, feedback appreciated 😀 |
@SimenB I am +1 on this change in principle but I know it will break pretty much every fake-timers install "in the wild" that uses the current API. |
Should work if people use the builtin My main issue is that to enable "fake everything" I have to enumerate all timers from the outside, which is not obvious I think. Maybe we could rather add a |
It doesn't break the built in promises but mostly because we don't mock its timings at the moment (we probably should with async_hooks). In practice this means that it's a lot harder than it has to to test promises with fake-timers (I recall a lot of discussions about this + async versions of timers somewhere?) I don't mind seeing what breaks with mocking nextTick on some large codebases I maintain - though I assume I know the answer is "every place that relies on nextTick executing and doesn't .tick or runMicrotasks before that :] |
As a data point, in a work project where I migrated to use Jest's fake timers now that Jest ships with Lolex it broke |
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions. |
Stale bot?! |
This makes my head hurt and you guys know best anyhow. Not sure why it has stalled, though? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To me, this looks good. @SimenB anything you want addressed (apart from the conflicts)?
B,B,B,B,bump? It's not super problematic to release a major version, as long as you also document how to deal with the fallout. Like using node-fetch as an example case, show what needs to be done to fix the test cases. @SimenB |
src/fake-timers-src.js
Outdated
return key !== "nextTick" && key !== "queueMicrotask"; | ||
}); | ||
} | ||
clock.methods = config.toFake || keys(timers); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can open a separate PR for it?
Yes
test/fake-timers-test.js
Outdated
@@ -4504,19 +4504,6 @@ describe("FakeTimers", function() { | |||
assert(called); | |||
clock.uninstall(); | |||
}); | |||
|
|||
it("does not install by default - GitHub#126", function(done) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
changed the test above, I think that's fine?
Yes, this is fine. It's implicitly true, as the code won't work unless nextTick
is synchronous.
This needs a rebase to resolve the conflicts. @SimenB do you have time to take this across the finish line? If not, would you be ok with someone else doing it? |
I want to finish this (and do #490) and release a new breaking major. Soonish
There's been 4 years. I guess the number of places that rely on non-native Promises are a lot fewer and further between. Maybe it's not that bad? I think we would just need to add something to the changelog. |
Since I closed #490 and I haven't heard anything in months, I think I'll just pick this up and release a new breaking major. |
21d726f
to
83c1381
Compare
Weird how much you can get done in a weekend without kids 😄 |
I think this needs to be reverted (even though I merged it myself in the end). Even in 2024, the new behavior of faking all timers seems to trip people up over and over again, ref sinonjs/sinon#2620 (comment), and so it makes for poor developer experience. I'd rather just change the docs to say "fakes most timers by default, but you can also choose to stub all or a subset, if you so please" and then expose some constants they could use ( fakeTimers.install({toFake: fakeTimers.ALL_TIMERS}) I think a library should aim to cover the common cases by default, allowing for the more exotic ones by config. |
Purpose (TL;DR) - mandatory
It's very weird to me that this method is excluded from default mocking. I've read #126 and to me the solution seems to be for users to specify a
toFake
themselves, not force other people to specify "yes, when I say fake timers I do mean all timers".Note that this should be considered a breaking change.
Whenever we start supporting some new timer, it should by default not be mocked, but I think when we later make a new major release it should be mocked by default again.