Recently at a client, a question came up about unit testing functionality that used setTimeout and setInterval.

The issue in this particular case was that there were several additional locations where

setTimeoutandsetIntervalhad been implemented … and the complete codebase needs to run before testing. Because all code runs, there are “bleed over” cases where**_other _**code is interfering with the tests.

The Pattern

The pattern discussed would allow for both sets of functionality to be wrapped in such a way that they can be removed, as needed. This functionality allowed the IDs to be stored in a way that they could be removed as the tests iterated.

This pattern is a patch using a pattern I am somewhat uncomfortable with as a tester, but given the amount of code already in place, this seemed like a reasonable option.

var timeoutIds = [];
var intervalIds = [];

var windowSetTimeout = window.setTimeout;
var windowSetInterval = window.setInterval;

window.setTimeout = function testSetTimeout() {
  var id = windowSetTimeout.apply(this, arguments)
  timeoutIds.push(id);
  return id;
};

window.setInterval = function testSetInterval() {
  var id = windowSetInterval.apply(this, arguments)
  intervalIds.push(id);
  return id;
};

afterEach(function() {
  timeoutIds.forEach(window.clearTimeout);
  intervalIds.forEach(window.clearInterval);
  timeoutIds = [];
  intervalIds = [];
});

setTimeout

Now, having shown this pattern, I found a few other options that, while they seemed more reasonable, did not fit well with this established codebase.

The following examples were primarily derived from How to test a function which has a setTimeout with jasmine?

Part of the issue I see with these examples is that

setIntervalis not covered.

Given a function with a timeout inside:

var testableVariable = false;
function testableCode() {
  setTimeout(function() {
    testableVariable = true;
  }, 10);
}

Use done as a means to tell the test that the

expectwill be checked Asynchronously, allowing enough time to expire for the setTimeout in the code above to run …

it('expects testableVariable to become true', function(done) {
  testableCode();

  setTimeout(function() {
    expect(testableVariable).toEqual(true);
    done();
  }, 20);
});

Additionally, the timer behavior could be mocked - this method allows jasmine to step the time forward.

#javascript #web-development #asynchronous #jasmine #unit-testing #testing #software-development #coding

Unit Testing Functionality: Testing setTimeout and setInterval
1.40 GEEK