question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. ItĀ collects links to all the places you might be looking at while hunting down a tough bug.

And, if youā€™re still stuck at the end, weā€™re happy to hop on a call to see how we can help out.

doc : jest fake timers : expect on setTimeout not working

See original GitHub issue

šŸ› Bug Report

In https://jestjs.io/fr/docs/timer-mocks, we can see that we can assert that setTimeout has been called once : expect(setTimeout).toHaveBeenCalledTimes(1);

However, if you do this in a test, jest will complain :

expect(received).toHaveBeenCalledTimes(expected)

Matcher error: received value must be a mock or spy function

Received has type:  function
Received has value: [Function setTimeout]

  216 |     //TODO: test refresh works
> 217 |     expect(setTimeout).toHaveBeenCalledTimes(1);
      |                        ^
  218 |   });
  219 | });
  220 |

  at Object.<anonymous> (xxx.spec.ts:217:24)

I think the documentation should be fixed to explain how we can do ā€¦

Issue Analytics

  • State:open
  • Created 2 years ago
  • Comments:13 (6 by maintainers)

github_iconTop GitHub Comments

4reactions
kleinfreundcommented, Aug 15, 2021

How is one supposed to solve this issue?

My tests start to fail as described in the inital report (i.e. I get a ā€œreceived value must be a mock or spy functionā€ error when invoking expect(setTimeout).not.toHaveBeenCalled() in a test).

Adding jest.spyOn(window, 'setTimeout') inexplicably produces a ā€œReferenceError: setTimeout is not definedā€ error:

node:internal/process/promises:246
          triggerUncaughtException(err, true /* fromPromise */);
          ^

[UnhandledPromiseRejection: This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). The promise rejected with the reason "ReferenceError: setTimeout is not defined".] {
  code: 'ERR_UNHANDLED_REJECTION'
}

Iā€™m using testEnvironment: 'jsdom'. The function window.setTimeout does exist in the test, so I donā€™t really understand how it can appear as not defined to the test runner.

3reactions
sigveiocommented, Aug 16, 2021

Why wouldnā€™t I be able to spy on a global function? I understand how this could lead to testing internals of an implementation that might not contribute to a proper unit test, but thatā€™s a decision a developer should be able to make rather than having the testing framework force this decision upon them.

I went by all the reports about it not working and thought that perhaps it was sacrificed for the fact that relying on an external library greatly simplifies things for Jest.

But actually, I was partially wrong and should have tested it more thoroughly.

After you have enabled the fake timers you can spy on the global:

jest.spyOn(global, 'setTimeout');

That said; I do still stand by my comment on it most often being more favourable not to do so.

Side note: Specifically what Iā€™d like to still be able to do is assess whether certain calls happened in an expected order. I donā€™t much care about the exact processor time that elapses but rather the information that events A, B, and C happened before event D.

When you use the modern fake timers, ā€œprocessor timeā€ should not play into the millisecond timing of when a given task can be expected to run though, because time is entirely faked. So with for example jest.advanceTimersByTime() you do have a lot of power.

I would also think that tasks under fake timers would run in the natural order they are scheduled in. So if you want to ignore the exact timingā€¦ and only care about the orderā€¦ then perhaps you can use jest.runAllTimers() to fast forward in time and exhaust all the queues, and then toHaveBeenNthCalledWith() to verify them?

Read more comments on GitHub >

github_iconTop Results From Across the Web

Timer Mocks - Jest
In the following example we enable fake timers by calling jest. useFakeTimers() . This is replacing the original implementation of setTimeout()Ā ...
Read more >
Mocking setTimeout with Jest. | Medium - Marek Rozmus
The first one is setting up fake timers and the second one restores the original JS behaviour. Example 1 ā€” setTimeout calls some...
Read more >
Jest: Timer and Promise don't work well. (setTimeout and ...
Timer Mocks work by replacing functions like setTimeout() with mocks when jest.useFakeTimers() is called. These mocks record the argumentsĀ ...
Read more >
Unit Testing Beginners Guide - Part 2 - Spying and fake timers
Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL. What does actually means is that Jest had expect us toĀ ......
Read more >
Using Fake Timers | Testing Library
In some cases, when your code uses timers ( setTimeout , setInterval , clearTimeout , clearInterval ), your tests may become unpredictable, slowĀ ......
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found