-
-
Notifications
You must be signed in to change notification settings - Fork 6.5k
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
Use Lolex to implement fake timers #5171
Conversation
I think we can start with not-purging FakeTimers and a temporary new environment and break it some time later. |
You mean instead of using the @cpojer have you had a chance to look through the FB code base for usage of the different functions? |
I checked, we don't use |
Cool, so sinonjs/fake-timers#146 and sinonjs/fake-timers#147 should be enough for us, then? That's awesome |
We can try running this PR, once it's fully iterated, on the FB codebase to uncover more issues. |
But it is also the only way to advance code based on Promises in tests (scheduled with setImmediate, as mentioned in #5165 by @cpojer) without triggering other timers. |
Are we planning to ship this or shall we close this PR for now? |
There has been some movement in Lolex, I need to test if it's enough. Will look into it this weekend 🙂 |
I've rebased this and added the two potential changes in Lolex to help support our use case. From my testing now, it's not enough, so I reported back on one of the PRs over there (sinonjs/fake-timers#157). |
I've rebased now, and tested with sinonjs/fake-timers#164 merged. It's pretty close (I sent sinonjs/fake-timers#165 for a quick fix of one issue found) and works really well, but I'm having a few issues:
|
Another key difference is that the timer function are no longer jest mocks when faked - people will have to do Spying on them ourselves means we have to sniff out which ones exist, which it's sorta nice we don't have to now. E.g. if we had been using Lolex before, |
Figured out issue nr 3 above, it's the infinites recursion not making it bail. Might be same issue as number 2. EDIT: Nope, not related, but asked a question in their issue tracker: sinonjs/fake-timers#147 (comment) |
Dug into number 2 above, and I think the thing there is that the recursion check is only for EDIT: sinonjs/fake-timers#166 |
Regarding this comment sinonjs/fake-timers#166 (comment), is it web only or Node acts in the same way? |
My PRs to Lolex has been merged and released, so I updated this PR. Getting quite close now 🙂 |
@cpojer would it be possible to get an example of how you use fake timers to drive promises at FB? Would be great to add it as an integration test or something |
cc @mjesun @rubennorte who can give more comments and/or run this diff on FB infra. |
50c6b15
to
7b0d0e2
Compare
Codecov Report
@@ Coverage Diff @@
## master #5171 +/- ##
==========================================
+ Coverage 62.19% 66.02% +3.82%
==========================================
Files 266 240 -26
Lines 10701 9141 -1560
Branches 2603 6 -2597
==========================================
- Hits 6656 6035 -621
+ Misses 3459 3103 -356
+ Partials 586 3 -583
Continue to review full report at Codecov.
|
Hello, are there any updates / plans on this issue? |
@AlexLomm it's still being tested internally at FB. Let's be patient, there's no need to rush things ;) |
@thymikee No rush, just being curious :). Thanks for such a quick reply and keep up the amazing work! :) |
How do we stand with this one? Any feedback from internal testing? cc @rubennorte @rickhanlonii @aaronabramov |
c202e0d
to
e13e60c
Compare
Non-breaking alternative: #7776 |
CI is very unhappy due to sinonjs/fake-timers#232 |
Hi there 👋 Any chance of seeing this hitting release stage? |
This is too breaking for FB as they rely on the broken semantics of the current implementation. So the current plan is to land a Lolex implementation in Jest 26 which will be the default if fake timers are used, and make the current implementation opt-in by saying I don't want to land Lolex as opt-in first to avoid juggling extra options |
This pull request has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs. |
Summary
Fixes #5165.
This PR switches out Jest's custom fake timers implementation with Lolex. This greatly simplifies things on our side (as we just need to proxy their API through the Jest object), while bringing many features:
Date
requestAnimationFrame
and soonrequestIdleCallback
(ImplementrequestIdleCallback
sinonjs/fake-timers#218)performance.now
queueMicrotask
: add support for queueMicrotask sinonjs/fake-timers#217Note that this might mean that previously working tests now will fail because more timers are faked. We can consider allowing
jest.useFakeTimers
to get passed an array matching Lolex'stoFake
if people want to specify what to mock and what not to. See https://github.com/sinonjs/lolex/blob/master/Readme.md#var-clock--lolexinstallconfigIt brings some behavioral (aka breaking) changes as well:
runAllPendingTimers
in Jest currently do not trigger new timers scheduled while running to the last scheduled one. Lolex does (which matches what would happen in real code). Fixes calling runAllTimers after using Lodash's _.debounce results in an infinite recursion error #3465runAllImmediates
is removed. There is no way that real code could trigger an immediate without triggering other timers. Users can approximate this by doingjest.advanceTimersByTime(0)
, but that will also trigger timers.Other breaking changes:
setImmediate
orprocess.nextTick
was scheduled using the real APIs in addition to the fake one, and Jest made sure that they only fired once (by keeping track). This has been removed - if you're faking time, then you're faking timejest.spyOn(global, 'setTimeout')
themselves.0
ms will be coerced to1
, see Scheduling timers duringtick
with timeout of0
forcing timeout of1
sinonjs/fake-timers#166runWithRealTimers
removed - it was undocumented and unused at FBTest plan
Green CI. No new tests are added as they'd be testing Lolex and not our own code. I've removed old tests that either didn't make sense or were testing features we've removed.