简体   繁体   中英

AbortController not working in React test (Jest)

We have a function in our React project to fetch a list of stores. If the fetch takes longer than 3 seconds (set low for testing purposes) we abort the request and show an error.

const controller = new AbortController();
const getTimeout = setTimeout(() => controller.abort(), 3000);

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; })
);

I am trying to trigger the Abort error from Jest. I am using Mock Service Worker to intercept fetch requests and mock a delayed response:

import * as StoresAPI from '../Stores-api';
import { rest } from 'msw';
import { setupServer } from 'msw/node';

const server = setupServer(rest.get(`http://my-api/*`, (req, res, ctx) => {
    console.log('TEST');
    return res(
        ctx.delay(5000),
        ctx.status(200),
        ctx.json({ stores: ['hi']})
    )
}));

beforeAll(() => server.listen());
afterAll(() => server.close());
afterEach(() => server.resetHandlers());

it('fetchStores should return a stores array', async () => {
    await StoresAPI.fetchStores(MOCK_STORES)
    .then((stores) => {
        expect(Array.isArray(stores)).toBe(true);
     })
    .catch();
});

When I run this, the delay works, it takes 5000 seconds for the mocked response to fire and the test to pass. But...The test passes and it seems abortController is never called. WHy is this happening? And is there a better way to test this (ideally without using MSW or other library)?

Your test is running synchronously; Jest runs all the code, which includes firing off a Promise but not awaiting it, and then finishes. After the test finishes, the Promise returns, but no one is waiting for it.

The code in the .then block is never even reached by Jest, since it is not awaited.

You can use async code inside Jest tests. I suspect this may give your more mileage:

// mock a quick response for this test
it('returns stores', async () => {
  const stores = await StoresAPI.fetchStores(MOCK_STORES)
  expect(stores).toEqual([/* returned array */])
})

// mock a long response for this test
it('times out', async () => {
  await expect(() => StoresAPI.fetchStores(MOCK_STORES)).rejects.toThrow();
})

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM