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
setTimeout
andsetInterval
had 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 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 = [];
});
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
setInterval
is 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
expect
will 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