Timer functions like setTimeout are commonly used in JavaScript to schedule tasks to run after some delay. When writing unit tests to test this kind of functionality, it isn’t ideal to wait for real time to pass especially if the delays are hours long. Jest allows us to use “fake timers” to instantly run timers to completion, or even advance time by a specified amount.
What We Are Testing
In this example, we’ll be testing a method in a Vue component. However this method of mocking timers using Jest should be applicable to other frameworks as well.
In this Vue component, we have one method that creates an alert after 5 seconds. We’ll be writing a test case to test that this method does create the alert by mocking the timer to artificially advance it by 5 seconds.
<template>
<div>
<button @click="delayedAlert">Delayed alert</button>
</div>
</template>
<script>
export default {
name: "TimeoutExample",
methods: {
delayedAlert: function() {
setTimeout(() => {
alert("Hello!");
}, 5000);
}
}
};
</script>
Writing the Test
The first thing we need to do in our test is to let Jest know we need to use fake timers. This is done using the jest.useFakeTimers()
method. Doing this will automagically replace setTimeout
with mock functions.
To test that our callbacks are called after the timeout, you can use jest.runAllTimers
to immediately run the callback methods.
Another option is to specify an amount of time to advance the timers by. This can be done using jest.advanceTimersByTime()
as shown in the example below. Here, I’m advancing time by 5 seconds instantly which will trigger the alert callback.
import { shallowMount } from "@vue/test-utils";
import TimeoutExample from "@/components/TimeoutExample.vue";
describe("TimeoutExample.vue", () => {
it("alerts after 5 seconds", () => {
// Tell jest to use fake timers
jest.useFakeTimers();
// Spy on the window.alert() function
const spy = jest.spyOn(window, 'alert').mockImplementation(() => { });
// Mount the TimeoutExample component
const wrapper = shallowMount(TimeoutExample);
// Call the method we are testing
wrapper.vm.delayedAlert();
// Advance timers by 5 seconds
jest.advanceTimersByTime(5000);
// Check that alert has been called
expect(spy).toBeCalledWith('Hello!');
});
});
Learn more about Timer Mocks and Jest here: https://jestjs.io/docs/en/timer-mocks