fake-timers: NodeJS "timers" module is not mocked

  • FakeTimers version : v10.1.0
  • Environment : Node.js v18.12.1
  • Other libraries you are using: jest v29.5.0

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

let timers = require("timers");
let FakeTimers = require("@sinonjs/fake-timers");

let clock;

beforeEach(() => {
    clock = FakeTimers.install();
});

it("doesn't work", () => {
    let timerDone = false;
    timers.setTimeout(()=>{timerDone=true;}, 1000);
    clock.tick(1001);
    expect(timerDone).toBe(true);
});

afterEach(() => {
    clock.uninstall();
});

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 when FakeTimers.install is called without arguments, so it should maybe also include NodeJS’s core module timers.

About this issue

  • Original URL
  • State: closed
  • Created a year ago
  • Comments: 17 (17 by maintainers)

Most upvoted comments

Sniffing out require should work fine in Jest as that should work the same as Node, but that won’t work for import declarations or expressions. I think that would need to hook into the module mocking directly. I haven’t looked into it, tho

the referenced issue is # #469 btw

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 jest.useFakeTimers the timers module stays the same.
Despite that, I still think it’s not a good idea to have fake-timers change the timers module for every call to “install” as this might lead to unexpected behavior if multiple objects are being patched and reverted.

Ah, good catch. I’ll create a new one, referencing this.

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 timers, which seems like a big nuisance. Unless you have some clever tricks to avoid this issue, @benjamingr?

A loader (not fun) or using top level await with dynamic import (easy and also works)