Skip to content

noctcore-code-quality/no-real-network-in-unit-tests

Unit tests must not perform real network I/O.

Recommended preset: error · Autofix: no · Suggestions: no · Type information: not needed

A unit test that calls fetch or axios for real depends on a server, a port, DNS and the network being up. It is slow, flaky and order-dependent, and it hides the fact that the code under test has no seam for a test double. Mock the client, or move the test to an integration suite where real I/O is the point.

In a unit test file (a path ending in one of testFileSuffixes, and not containing any integrationMarkers):

  • a call to a networkCallees global: fetch(...), globalThis.fetch(...), window.fetch(...);
  • a call to an httpClients client or its request methods: axios(...), axios.get(...), axios.post(...), and put / patch / delete / head / options / request.
Incorrect · src/api/client.test.ts
it('loads the profile', async () => {
const res = await fetch('https://api.example.com/me');
expect(res.status).toBe(200);
});
Correct · src/api/client.test.ts
it('loads the profile', async () => {
vi.stubGlobal('fetch', vi.fn().mockResolvedValue(new Response('{"id":1}')));
expect(await loadProfile()).toEqual({ id: 1 });
});

A test that needs the real server moves to an integration suite:

Correct · src/api/client.integration.test.ts
it('loads the profile', async () => {
const res = await fetch('https://api.example.com/me');
expect(res.status).toBe(200);
});
  • a locally declared double (const fetch = vi.fn()); an imported fetch is still reported;
  • a global the file stubs (vi.stubGlobal('fetch', ...), jest.spyOn(globalThis, 'fetch'), globalThis.fetch = vi.fn());
  • a client whose module the file mocks (vi.mock('axios'), jest.mock('node-fetch'));
  • a method that only shares a name (repository.fetch(1), store.get('k'));
  • files that are not unit tests, or whose path contains an integrationMarkers entry.

The rule sees calls in the test file only, not network calls made by the code under test. A request intercepted by a setup-file mock server (for example MSW) is still reported when the test file itself calls fetch; add that file’s suffix to integrationMarkers or disable the rule for it.

Option Type Default Meaning
testFileSuffixes string[] .test / .spec with .ts, .tsx, .js, .jsx A file is a unit test when its path ends with one of these.
integrationMarkers string[] .integration.test., .integration.spec., .e2e.test., .e2e.spec., .e2e-spec., /integration/, /e2e/ A test file whose path, relative to the ESLint working directory, contains one of these is skipped.
networkCallees string[] ["fetch"] Global functions that perform network I/O.
httpClients string[] ["axios"] HTTP clients whose direct call or request methods perform network I/O.
'noctcore-code-quality/no-real-network-in-unit-tests': ['error', {
integrationMarkers: ['.integration.', '/e2e/', '.live.'],
httpClients: ['axios', 'ky'],
}]

If your unit tests deliberately run against a local server started in-process, name those files with an integration marker instead of turning the rule off.

Based on a rule from tsforge (MIT). See THIRD_PARTY_NOTICES.md.