Emily discussing React test debugging on her laptop, with graphics illustrating API call mocks and error messages.

Embark on a journey through the intricacies of React testing with Emily's latest TWIL installment, where she tackles the elusive Debugging Network Errors in Tests. Discover how to effectively mock API calls and decipher those vexing network errors that often surface during automated test runs. Her insights offer a way to transform temporal bugs from intermittent CI failures into reproducible local issues, ensuring smoother development and more reliable software.

Debugging Network Errors in Tests

A key piece to testing in React is mocking out our API calls.

As part of our testing philosophy, we mock at the lowest level possible (e.g. mock an API response that loads data into the store and/or component instead of mocking a piece of data/props/state or the store itself).

Occasionally, we miss one of these mocks and it results in an error that looks something like this:

FAIL  app/containers/ClientPage/tests/ClientPage.test.js

  - ClientPage › renders and matches snapshot
 
    Network Error
      at createError (node_modules/axios/lib/core/createError.js:16:15)
      at XMLHttpRequest.handleError (node_modules/axios/lib/adapters/xhr.js:69:14)
      at XMLHttpRequest.<anonymous> (node_modules/jsdom/lib/jsdom/living/helpers/create-event-accessor.js:33:32)
      at innerInvokeEventListeners (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:316:27)
      at invokeEventListeners (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:267:3)
      at XMLHttpRequestEventTargetImpl._dispatch (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:214:9)
      at fireAnEvent (node_modules/jsdom/lib/jsdom/living/helpers/events.js:17:36)
      at requestErrorSteps (node_modules/jsdom/lib/jsdom/living/xhr-utils.js:121:3)
      at Object.dispatchError (node_modules/jsdom/lib/jsdom/living/xhr-utils.js:51:3)
      at Request.<anonymous> (node_modules/jsdom/lib/jsdom/living/xmlhttprequest.js:675:20)
      at Request.onRequestError (node_modules/request/request.js:877:8)

The trick here is that the Network Error is likely NOT coming from the ClientPage test. The network call was probably made in a previous test and just happened to time out while this test was running.

This type of bug also seems to pop up more frequently on CI or while updating snapshots locally (probably because these run a bit slower than when running the plain tests locally and the requests don't even have a chance to time out). This also means that this is a temporal bug - sometimes CI will pass and sometimes it won't!

Replicating the Error Locally

The easiest way that I've found to replicate this locally is to bump the timeout in the Axios instance down to something that will cause all API calls to time out almost immediately.

Your project probably has something like this, bump down that timeout:

// Default config options
const DEFAULT_OPTIONS = {
  baseURL: process.env.API_BASE_URL,
  headers: {
    'Content-Type': 'application/json',
  },
  timeout: 0.1, // Usually set to 15000, in ms
}

// Create instance
const instance = axios.create(DEFAULT_OPTIONS)

Bam! Now you can tell which test the error is actually coming from and see ALL errors deterministically:

Summary of all failing tests
 FAIL  app/containers/AgentPage/tests/AgentPage.test.js
AgentPage › does not log errors in console

    timeout of 0.1ms exceeded

      at createError (node_modules/axios/lib/core/createError.js:16:15)
      at XMLHttpRequest.handleTimeout (node_modules/axios/lib/adapters/xhr.js:77:14)
      at XMLHttpRequest.<anonymous> (node_modules/jsdom/lib/jsdom/living/helpers/create-event-accessor.js:33:32)
      at innerInvokeEventListeners (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:316:27)
      at invokeEventListeners (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:267:3)
      at XMLHttpRequestEventTargetImpl._dispatch (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:214:9)
      at fireAnEvent (node_modules/jsdom/lib/jsdom/living/helpers/events.js:17:36)
      at Timeout.properties.timeoutFn [as _onTimeout] (node_modules/jsdom/lib/jsdom/living/xmlhttprequest.js:729:15)

 FAIL  app/containers/ClientPage/tests/ClientPage.test.js
ClientPage › does not log errors in console

    timeout of 0.1ms exceeded

      at createError (node_modules/axios/lib/core/createError.js:16:15)
      at XMLHttpRequest.handleTimeout (node_modules/axios/lib/adapters/xhr.js:77:14)
      at XMLHttpRequest.<anonymous> (node_modules/jsdom/lib/jsdom/living/helpers/create-event-accessor.js:33:32)
      at innerInvokeEventListeners (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:316:27)
      at invokeEventListeners (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:267:3)
      at XMLHttpRequestEventTargetImpl._dispatch (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:214:9)
      at fireAnEvent (node_modules/jsdom/lib/jsdom/living/helpers/events.js:17:36)
      at Timeout.properties.timeoutFn [as _onTimeout] (node_modules/jsdom/lib/jsdom/living/xmlhttprequest.js:729:15)

 FAIL  app/components/ProfileSidebar/ProfileSidebar.test.js
ProfileSidebar › does not log errors in console

    timeout of 0.1ms exceeded

      at createError (node_modules/axios/lib/core/createError.js:16:15)
      at XMLHttpRequest.handleTimeout (node_modules/axios/lib/adapters/xhr.js:77:14)
      at XMLHttpRequest.<anonymous> (node_modules/jsdom/lib/jsdom/living/helpers/create-event-accessor.js:33:32)
      at innerInvokeEventListeners (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:316:27)
      at invokeEventListeners (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:267:3)
      at XMLHttpRequestEventTargetImpl._dispatch (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:214:9)
      at fireAnEvent (node_modules/jsdom/lib/jsdom/living/helpers/events.js:17:36)
      at Timeout.properties.timeoutFn [as _onTimeout] (node_modules/jsdom/lib/jsdom/living/xmlhttprequest.js:729:15)

Now go mock that service!

  • React
Emily Morehouse's profile picture
Emily Morehouse

Cofounder, Director of Engineering

Related Posts

MCP (Model Context Protocol) logo — a stylized white interlinked letter mark — centered on an abstract background of flowing purple and orange gradient waves, representing AI connectivity and data integration.
November 25, 2025 • Frank Valcarcel

Anthropic’s Model Context Protocol: The Standard for AI Tool Integration

A year after launch, Anthropic’s Model Context Protocol has become the universal standard for connecting AI agents to enterprise tools. Backed by OpenAI, Google, Microsoft, and the Linux Foundation. Here’s what developers need to know.

Git Flow branching diagram showing colorful merge lines with feature branches, hotfix workflows, and release commits on dark purple background for release-it plugin automation
April 28, 2025 • Frank Valcarcel

Git Flow Releases with ­­release-it

Learn how to build a custom release-it plugin that automates your entire Git Flow workflow: version bumps, branch merges, multi-branch pushes, and GitHub releases with a single command.

Let's work together

Tell us about your project and how Cuttlesoft can help. Schedule a consultation with one of our experts today.

Contact Us