-
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
NodeJS "timers" module is not mocked #466
Comments
PR welcome :) |
@benjamingr You are bit more into the Node internals than me, so I just vaguely remember this or something related (HTTP Headers in |
The timers should be pretty easily stubbable unlike HTTP headers - just |
Thanks for the quick responses 🙏
I've had a quick glance at the fake-timers repo before opening this issue... but I wouldn't know where to put the code or how to make sure it's only done for NodeJS. Also I'm a senior Python developer, not so much JS/TS 😅
That's what I thought too and why I'm not sure whether a fix would belong here or there...
Indeed they are and that's exactly my current workaround:
export function myUseFakeTimers() {
jest.useFakeTimers();
timers.setTimeout = setTimeout;
timers.clearTimeout = clearTimeout;
timers.setInterval = setInterval;
timers.clearInterval = clearInterval;
timers.setImmediate = setImmediate;
timers.clearImmediate = clearImmediate;
}
export function myUseRealTimers() {
jest.useRealTimers();
timers.setTimeout = setTimeout;
timers.clearTimeout = clearTimeout;
timers.setInterval = setInterval;
timers.clearInterval = clearInterval;
timers.setImmediate = setImmediate;
timers.clearImmediate = clearImmediate;
} |
@swenzel-arc You already have code that works, so that is great. Now what about the interface ... We need to be able to selectively disable or enable the stubbing. I guess it makes sense to enable it as the default? And how should we deal with only stubbing selected timers? I think a reasonable assumption is that if you only want to stub out two specific timers from fakeTimers.install({ toFake: ['setTimeout', 'clearTimeout', 'nodeTimers']}); You would then basically add a section here to specifically deal with the Node timers lib.
let nodeTimersModule;
try { nodeTimersModule = require('timers') }
catch(err) { // not recent Node version }
....
if (toFake.nodeTimers && nodeTimersModule) {
installNodeTimers()
} Conditional requires is not possible (AFAIK) when using ESM, as linking takes place before running the code, so I guess this would prevent us from easily going the ESM in the future? If we did, I think it would require clients to use something that captured calls to Word of warning: instead of having an explicit section for dealing with Node timers, one could think (as I did) that we could just use the library's ability to target a specific object with its |
A loader (not fun) or using top level await with dynamic import (easy and also works) |
AFAIK, we cannot start using promise based code without changing the API. If we were to do dynamic imports (great idea, btw), we would probably have to change all the exports to resolve to promises: export install(config:Config|null): Promise<Clock>
export withGlobal(config:Config|null): Promise<Clock>
etc Otherwise we would not know if the call to let asyncFunction = async () => {
async function main() {
var value = await Promise.resolve("Hey there");
console.log("inside: " + value);
return value;
}
var text = await main();
console.log("outside: " + text);
};
console.log("pre");
asyncFunction();
console.log("post"); will print
Either that, or expose a promise one could wait for: |
It appears to be a bit harder than I thought... especially the |
Or actually, nevermind... I think I'll just handle the "timers" module separately. Similar to how I solved it in the workaround. |
That's fine. We can still keep this issue around as we might want this still |
Should this be closed or kept open for timers/promises? |
Ah, good catch. I'll create a new one, referencing this. |
Thanks guys 🙏 As it turns out, this doesn't solve my initial problem, though. Jest is using a custom global object but I made it so that the timers module isn't touched unless the patched object is the "default" global object. So upon |
the referenced issue is # #469 btw |
@SimenB is there anything we can do better in this regard for jest? |
Sniffing out |
In case anyone want's to check it out: Is there another way to access the "currently active global object"? Maybe we could compare the |
What did you expect to happen?
NodeJS's timers module to be mocked upon
FakeTimers.install()
.What actually happens
It's not mocked.
How to reproduce
I was testing some code that is working with socket.io and was wondering why my sockets kept closing with ping time outs. Turns out engine.io is using
timers.*
instead of the corresponding global functions.TBH I'm not quite sure if a fix belongs into this library or into jest's
useFakeTimers
function. However, the README here says it'd mock all "native" timers whenFakeTimers.install
is called without arguments, so it should maybe also include NodeJS's core module timers.The text was updated successfully, but these errors were encountered: