I'm getting the ECONNREFUSED error and it looks like my msw server isn't catching my get request when I start a get outside of a React component (which shaves some time off of the response).
When axios.get is uses inside of the useEffect everything works as normal and the msw picks up the request with no errors. Is there a special way to setup react-testing-library with msw so that I can initialize an axios.get() outside of react components and then have the component pick up the promise once it's loaded.
Thanks, get tool, but I just couldn't find how to get this working.
const signinPromise = axios.get(`signin?ajax=true`);
const Index = () => {
useEffect(() => {
(async () => {
try {
const response = await signinPromise;
// ... do something with data etc
} catch (err) {
} finally {
}
})();
}, []);
return <>{/* content here */}</>;
};
test that's failing
import { screen } from '@testing-library/dom';
import { render, waitFor } from 'jestTestUtils';
import Index from './Index';
test('Signed in -> 404 page renders when given a bad route.', async () => {
render(<Index />, { route: '/imabadroute' });
await waitFor(() => expect(screen.getByRole('heading', { name: /chloë: add 404 page here to show nothing is at this route/i })));
});
My setup is as follows:
server-handlers.ts
/**
* these are the happy path responses for endpoints that we want to exist for tests so the pages load properly during tests
*/
import { rest } from 'msw';
import { getActivities, getAlertTypes, getDashboard, getSearch, getTab, getUserAccounts } from './data';
export const handlers = [
rest.get('/signin', (req, res, ctx) => {
return res(ctx.status(200), ctx.json(getUserAccounts({ amount: 2, overrides: [{ disabled: false }, { disabled: false }] })));
}),
rest.post('/signin', (req, res, ctx) => {
return res(ctx.status(200), ctx.json(getUserAccounts({ amount: 2, overrides: [{ disabled: false }, { disabled: false }] })));
}),
rest.get(`/accounts/:accountId/tweet_event/types`, (req, res, ctx) => {
return res(ctx.status(200), ctx.json(getAlertTypes()));
}),
rest.get(`/accounts/:accountId/event_dashboard`, (req, res, ctx) => {
return res(ctx.status(200), ctx.json(getDashboard({ tabAmount: 1 })));
}),
rest.get(`/accounts/:accountId/event_dashboard/searches/:searchId`, (req, res, ctx) => {
return res(ctx.status(200), ctx.json(getTab()));
}),
rest.get(`/accounts/:accountId/event_dashboard/searches/:searchId/search`, (req, res, ctx) => {
return res(ctx.status(200), ctx.json(getSearch()));
}),
rest.get(`/accounts/:accountId/event_dashboard/searches/:searchId/activities`, (req, res, ctx) => {
return res(ctx.status(200), ctx.json(getActivities({ amount: 2 })));
}),
];
server.ts
/** this is just building a server with all the end points setup in server-handlers */
import { rest } from 'msw';
import { setupServer } from 'msw/node';
import { handlers } from './server-handlers';
const server = setupServer(...handlers);
export { server, rest };
server-env.ts
/** our mock api is setup before each test, so the happy path is available to all tests */
import { server } from './server';
beforeAll(() => server.listen());
afterEach(() => server.resetHandlers());
afterAll(() => server.close());
jestTestUtils.tsx
import { CssBaseline, ThemeProvider } from '@mui/material';
import '@testing-library/jest-dom/extend-expect';
import { render, RenderOptions } from '@testing-library/react';
import { ReactElement } from 'react';
import { BrowserRouter } from 'react-router-dom';
import theme from '../theme';
interface RenderOptionsWithRoute extends RenderOptions {
route: string;
}
interface Props {
children: JSX.Element;
}
const AllTheProviders = ({ children }: Props) => (
<ThemeProvider theme={theme}>
<CssBaseline />
<BrowserRouter>{children}</BrowserRouter>
</ThemeProvider>
);
const customRender = (ui: ReactElement, options?: Omit<RenderOptionsWithRoute, 'wrapper'>) => {
window.history.pushState({}, 'Test page', options?.route || '/');
return render(ui, { wrapper: AllTheProviders, ...options });
};
export * from '@testing-library/react';
export { customRender as render };
jest.config.ts
export default {
// Automatically clear mock calls, instances and results before every test
clearMocks: true,
// An array of glob patterns indicating a set of files for which coverage information should be collected
collectCoverageFrom: ['./src/routes/**', './src/router/**', './src/utils/**'],
// The directory where Jest should output its coverage files
coverageDirectory: 'coverage',
// An array of directory names to be searched recursively up from the requiring module's location
moduleDirectories: [
/** gives an absolute path to the root directory so jestTestUtils can be imported by an absolute path */
'node_modules',
'src/testing',
],
/**
* A map from regular expressions to module names or to arrays of module names that allow to stub out resources with a single module
*
* mirrors the resolve.alias object in webpack.config.js so the tests can import the same as in the code
*/
moduleNameMapper: {
'^@mui/styled-engine$': '@mui/styled-engine-sc',
'^routes(.*)$': '<rootDir>/src/routes/$1',
'^router(.*)$': '<rootDir>/src/router/$1',
'^stores(.*)$': '<rootDir>/src/stores/$1',
'^utils(.*)$': '<rootDir>/src/utils/$1',
// svgr support
'\\.svg': '<rootDir>/src/testing/__mocks__/svg.ts',
},
// A list of paths to modules that run some code to configure or set up the testing framework before each test
setupFilesAfterEnv: ['<rootDir>/src/testing/__mocks__/setup-env.ts'],
// The test environment that will be used for testing
testEnvironment: 'jest-environment-jsdom',
};