'Error: connect ECONNREFUSED 127.0.0.1:80 if an axios fetch gets initialized outside of a react component react-testing-library/msw

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',
};


Solution 1:[1]

My guess here is that since you're using msw and you're triggering the get request once you import the file, the server might still not be up to catch your request. In that case, I'll try using require or dynamic import to import the component within the specific test and it will work.

Something like this:

  it("should catch request", () => {
    const { App } = require("./App");
    render(<App />);
  });

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Matan Bobi