48

I need to test JavaScript code that relies on setTimeout in order to perform periodic tasks. How can I from my Mocha tests simulate the passing of time so that setTimeout callbacks gets called?

I am basically asking for functionality similar to Jasmine's Mock Clock, which allows you to advance JavaScript time by a number of ticks.

aknuds1
  • 65,625
  • 67
  • 195
  • 317

1 Answers1

68

I found out that Sinon.JS has support for manipulating the JavaScript clock, via sinon.useFakeTimers, as described in its Fake Timers documentation. This is perfect since I already use Sinon for mocking purposes, and I guess it makes sense that Mocha itself doesn't support this as it's more in the domain of a mocking library.

Here's an example employing Mocha/Chai/Sinon:

var clock;
beforeEach(function () {
     clock = sinon.useFakeTimers();
 });

afterEach(function () {
    clock.restore();
});

it("should time out after 500 ms", function() {
    var timedOut = false;
    setTimeout(function () {
        timedOut = true;
    }, 500);

    timedOut.should.be.false;
    clock.tick(510);
    timedOut.should.be.true;
});
ozanmuyes
  • 721
  • 12
  • 26
aknuds1
  • 65,625
  • 67
  • 195
  • 317
  • why the beforeEach and afterEach? – R01010010 Nov 18 '14 at 12:57
  • 1
    @Rimbuaj In order to install the simulated clock before each test and remove it afterwards? – aknuds1 Nov 18 '14 at 20:07
  • 1
    but there's only a test... that's why i ask – R01010010 Nov 25 '14 at 03:52
  • 8
    It's a good practice to get into. Whenever you need to do setup/teardown for a test, it's smart to use before/after pairs so you don't forget one or the other. – Danny Andrews Jul 20 '15 at 21:38
  • 4
    @R01010010 if you didn't have clock.restore() in an after each and anything inside the test threw, setTimeout and other time based functions would stay overridden. By using an after each, you ensure that they always get restored to the defaults. – Will Munn Oct 17 '15 at 16:46
  • @aknuds1 can you help me out with this https://stackoverflow.com/questions/50646921/sinonjs-advance-clock-to-59-minutes-and-wait-for-1-minute-actually – Valay Jun 01 '18 at 16:09
  • If you're using a [sinon sandbox](https://sinonjs.org/releases/v9.0.2/sandbox/), you'll probably have to enable `useFakeTimers`: `const sandbox = sinon.createSandbox({useFakeTimers: true})` – kenecaswell Jul 31 '20 at 23:16