Jest: bug: `resetAllMocks` messes up `runAllTimers` when using `useFakeTimers`

Created on 23 Jan 2018  路  8Comments  路  Source: facebook/jest

Do you want to request a _feature_ or report a _bug_?
Bug

What is the current behavior?
When using useFakeTimers, running resetAllMocks messes up runAllTimers in the second test (it does not advance the timer) and the test times out (fails).

If the current behavior is a bug, please provide the steps to reproduce and
either a repl.it demo through https://repl.it/languages/jest or a minimal
repository on GitHub that we can yarn install and yarn test.

https://repl.it/repls/CarelessNormalAssassinbug

What is the expected behavior?
resetAllMocks should indeed reset the calls instances of the setTimeout mock, but runAllTimers should still work as expected and complete the setTimeout

Please provide your exact Jest configuration and mention your Jest, node,
yarn/npm version and operating system.

Jest v22.1.4
Node v9.3.0
Yarn v1.3.2
Mac OS X 10.12.6

Bug Confirmed Help Wanted

Most helpful comment

I was not aware that we made setTimeout and friends into spies - I'm not sure how that will work once we start using Lolex (#5165).

So for now I'd say we should document the current behaviour. Thoughts @cpojer @thymikee?

All 8 comments

In your code you've called the jest.useFakeTimers on a beforeAll.

If you replace that with beforeEach and your afterAll with afterEach, it works (https://repl.it/@Rafazelramalho/CarelessNormalAssassinbug)

Do you really require it to be beforeAll and afterAll?

Yes, the current workaround is to useFakeTimers on beforeEach, but that's not the expected behavior.

If I understand correctly, useFakeTimers mocks setTimeout and the like with Jest mock functions, so they're supposed to act like all other jest.fn() and jest.spyOn() mocks.
In that sense, running resetAllMocks should reset the calls tracking of the mocks, but keep the actual mock intact.

So, the expected behavior would be to run useFakeTimers only once and reset the mocks after each test. In which case runAllTimers should have worked in my setup.

This is also based on what we see in the docs:
https://facebook.github.io/jest/docs/en/timer-mocks.html

If the docs would have noted to run it on beforeEach, I wouldn't have a problem with that.
But since I followed the examples and that led me to broken code, I consider it a bug.

@SimenB would you suggest updating the docs or looking into this particular issue?

I was not aware that we made setTimeout and friends into spies - I'm not sure how that will work once we start using Lolex (#5165).

So for now I'd say we should document the current behaviour. Thoughts @cpojer @thymikee?

@SimenB haven't thought about that either. Would be quite a breaking change with Lolex.

FWIW I've set up the Lolex branch to spy on the methods, so no longer breaking in that regard

My current thinking is that we should remove the mocks from the timing functions when using fake timers. Easy enough for people to do jest.spyOn(global, 'setTimeout') if they want.

it鈥檚 a surprise to me that jest. useFakeTimers could be clear by jest.resetAllMocks, no document for it and I spent one hour to figure out the root cause. If this is the rule, could you update related documents as well?

Was this page helpful?
0 / 5 - 0 ratings