Open 9still opened 4 years ago
I think something similar can be achieved by doing the following:
afterEach(() => {
if (jest.isMockFunction(setTimeout)) {
jest.runOnlyPendingTimers();
jest.useRealTimers();
}
});
Thanks for the suggestion @cschwebk ! That seems like a very clean workaround, but it'd be awesome if it was officially supported/documented, since strictly speaking without that, it's not guaranteed that enabling fake timers will make setTimeout
an actual mock function and could thus break at any time if the underlying implementation changes.
It's worth noting that these methods aren't actually correct. If you use jest.spyOn(global, "setTimeout")
, the checks above will still be true despite the fact that timers aren't actually using the fake implementations. So simply checking if setTimeout
is mocked isn't enough to definitively determine.
I was not able to find any way to differentiate between a spy and a mock so I'm not sure how it'd be possible to determine this reliably, even in a hacky way.
If only there was a property/method exposed by Jest which could help us! 😉
This seems not to work with jest 28.1.0 - jest.isMockFunction(setTimeout)
will always return false
, regardless of using real or fake timers.
As a temporary and hacky workaround that is almost certain to break, checking the setTimeout.name
property seems to be an indication of whether the timers are mocked, but this will be extremely brittle long term. When the timers are mocked, setTimeout.name === "setTimeout"
, and when using real timers, setTimeout.name === undefined
.
I can't explain why this is the case (maybe some setup from jest-environment-jsdom?), as setTimeout.name === "setTimeout"
in browsers as well as node, but it seems to work for the time being.
To maybe provide some reasoning for why this feature is useful, it can be used with the react-testing-library user-event companion library. Setup of this is something like:
userEvent.setup();
But when using mocked timers, you must provide an advanceTimers
function to hook into jest
userEvent.setup({ advanceTimers: jest.advanceTimersByTime });
To simplify this, it is often put in a setup wrapper, so should be able to dynamically set the correct advanceTimers
function based on whether or not the running test context has mocked time.
I can confirm that jest.isMockFunction(setTimeout)
doesn't work in Jest 29 either, always returns false
even if fake timers enabled :( I ended up doing the following.
if (typeof jest !== 'undefined' && setTimeout.clock != null && typeof setTimeout.clock.Date === 'function') {
// ...
}
Can you please consider deprecating useFakeTimers()
?
This issue is stale because it has been open for 1 year with no activity. Remove stale label or comment or this will be closed in 30 days.
Not stale
jest@29.7.0
use @sinonjs/fake-timers
internally to fake timers, they detect fake timers by checking global.Date.isFake
, i guess it safe for now to do the same, to check for fake timers.
declare global {
interface DateConstructor {
/* Jest uses @sinonjs/fake-timers, that add this flag */
isFake: boolean;
}
}
const hasFakeTimers = global.Date.isFake === true;
This issue is stale because it has been open for 1 year with no activity. Remove stale label or comment or this will be closed in 30 days.
Bump. Please deprecate useFakeTimers()
.
🚀 Feature Proposal
Provide a method (e.g.
jest.usingFakeTimers()
) that returnstrue
ifjest.useFakeTimers
was previously invoked. Alternatively, a property or a config object could be exposed with the same information.Motivation
It is often convenient to have a global cleanup routine for tests that does things like always reverting to real timers, etc. It would be awesome if we could flush timers (e.g.
jest.runOnlyPendingTimers()
) in this cleanup routine as well, but to do that, one would need to find out if fake timers are actually being used.There are already examples of libraries resorting to introspection of the
setTimeout
implementation to try to deduce this for similar purposes.@kentcdodds had to do the following https://github.com/testing-library/react-testing-library/pull/720/files recently
Would be awesome if
jest
exposed an official method to check the above, so that tooling wouldn't break if the underlying implementation were to change.Example
Pitch
Why does this feature belong in the Jest core platform?
Since
jest.useFakeTimers
is a part of the core platform, it seems reasonable to be able to find out whether that call had previously been invoked. The core platform is the only place that would be able to provide this information.