← Back to archive

Repo of the Day

deshiknaves/cypress-msw-interceptor

Published: Nov 14, 2024

Open repository ↗

A networking layer for Cypress using MSW - This would replace cy.intercept and allow MSW to be used to mocks network requests in e2e tests, unit tests, and in the browser (hopefully all using the same code as to avoid lots of duplication that is currently done)

Summary

cypress-msw-interceptor is a Cypress plugin that adapts the Mock Service Worker (MSW) API to work inside Cypress tests. It starts an MSW service worker as part of the Cypress runner so fetch requests from the application under test can be intercepted, with MSW itself not needing to be a runtime dependency of the app.

What it is useful for

  • Mocking HTTP responses in Cypress tests using MSW's response resolver syntax ((req, res, ctx) => res(ctx.json(...))).
  • Waiting on a specific request to complete (including with ctx.delay) before asserting UI state, instead of aliasing with cy.route.
  • Reading fields off the real response object inside cy.waitForRequest and using them in subsequent assertions.
  • Counting how many times a request fired via cy.getRequestCalls('@alias').
  • Mocking GraphQL queries and mutations by operation name, with cy.interceptQuery / cy.interceptMutation and the matching waitFor* / get*Calls helpers.
  • Running the same test in two modes: a fully mocked integration test by default, and an end-to-end test when an env flag (e.g. CYPRESS_E2E) is set, by conditionally passing the resolver.

How engineers can use it

Install alongside MSW as dev dependencies:

npm install cypress-msw-interceptor msw --save-dev

Add the import to cypress/support/index.js:

import 'cypress-msw-interceptor'

Initialize MSW in the app per the MSW browser integration guide, and set Cypress's baseUrl to the same origin as the app so the service worker registers. MSW worker start options can be customized with setMswWorkerOptions({ quiet: true, onUnhandledRequest: 'bypass' }).

Mock a request and wait on it:

cy.interceptRequest(
  'GET',
  'https://jsonplaceholder.typicode.com/todos/1',
  (req, res, ctx) => res(ctx.json({ id: 1, title: 'Lord of the rings' })),
  'todos',
)
cy.visit('/')
cy.waitForRequest('@todos').then(({ response }) => {
  cy.findByText(new RegExp(response.body.title, 'i')).should('be.visible')
})

For GraphQL, the equivalent helpers target the operation name, e.g. cy.interceptQuery('CoursesQuery', resolver, 'courses') followed by cy.waitForQuery('@courses'). Redefining a handler with the same alias updates the mock, and omitting the resolver while keeping the alias lets the request hit the real network but still be tracked and waited on.

Documented limitations: the MSW service worker file must live in the app's public folder (a constraint the README attributes to the Cypress plugin API), and Cypress's baseUrl must match the app's origin for the worker to register correctly.