We have a function in our React project to fetch a list of stores. If the fetch takes longer than 10 seconds we abort the request and show an error.
const controller = new AbortController();
const getTimeout = setTimeout(() => controller.abort(), 10000);
const fetchStores = storeId => (
ourFetchStoresFunction(`http://my-api/${storeId}`, {
headers: { 'x-block': 'local-stores' },
signal: controller.signal
})
.then((results) => {
clearTimeout(getTimeout);
return results
})
.catch((err) => { throw err; })
);
Here is the basic test for the fetchStores function:
it('fetchStores should return a stores array', () => {
storesAPI.fetchStores(MOCK_STORES)
.then((stores) => {
expect(Array.isArray(stores)).toBe(true);
})
.catch();
});
How do I mock this timeout in Jest?
using setTimeout in the .then block while calling that method did not work. Additionally, I would rather NOT have to wait 10 seconds during the test. I looked up jest.useFakeTimers but got nowhere.
I could test global timers, read here: jestjs.io/docs/timer-mocks You can use jest spyOn function. For example:
let timeoutSpy; beforeEach(() => { timeoutSpy = jest.spyOn(global, 'setTimeout'); }); afterEach(() => { jest.restoreAllMocks(); })
Then in your test, you can expect(tymepoutSpy).toHaveBeenCalledTimes(1); Something like this should work, worked in my case.
In your case, you can mock about controller too, again using jest.spyOn, could be something like this:
let abortSpy;
In the same beforeEach you can set it:
abortSpy = jest.spyOn(AbortController.prototype, 'abort');
And I suppose ourFetchStoresFunction function is similar to fetch?
And finally, you can mock fetch function, so it takes lots f time to load, it can be done in this way:
> global.fetch = jest.fn(() => Promise.resolve({ // set some time })
> );