Vitest Browser Mode

Integrate Mock Service Worker with Vitest Browser Mode.

Vitest Browser Mode is a fantastic tool for testing your UI components in the actual browser. There are a few things to consider when integrating MSW with the Browser Mode:

  • As the name suggests, your Browser Mode tests run in the actual browser. This means you will be using the Browser integration of MSW (i.e. setupWorker());
  • You cannot reuse the app-level integration (e.g. in your main.tsx) because you don’t normally render your entire component tree during component testing. You can still rely on that integration for local development with MSW though;
  • Vitest actually ships with MSW built-in, however, as of the time writing this, you cannot directly access the worker instance created by Vitest. This may change in the future.

Example

We recommend integrating MSW with Vitest Browser Mode by extending the test context.

// test-extend.ts
import { test as testBase } from 'vitest'
import { worker } from './mocks/browser.js'
 
export const test = testBase.extend({
  worker: [
    async ({}, use) => {
      // Start the worker before the test.
      await worker.start()
 
      // Expose the worker object on the test's context.
      await use(worker)
 
      // Stop the worker after the test is done.
      worker.stop()
    },
    {
      auto: true,
    },
  ],
})

Initial request handlers

Any test() now runs against the initial, happy-path request handlers (like those in handlers.ts) without explicitly referencing MSW. Leverage this for cleaner test suites and predictable baseline behavior.

import { test } from './test-extend'
import { Dashboard } from './components/dashboard.js'
 
test('renders the dashboard', () => {
  // Uses only the happy-path request handlers.
  render(<Dashboard />)
 
  // Your actions and assertions...
})

Overriding request handlers

You can override request handlers by accessing the worker object of your test’s context and calling .use(), providing it with the request handlers that should take priority:

import { http, HttpResponse } from 'msw'
import { test } from './test-extend'
import { Dashboard } from './components/dashboard.js'
 
test('displays a notification if fetching the dashboard failed', async ({
  worker,
}) => {
  // Prepend overrides to the happy-path handlers
  // on the `worker` object from the test's context.
  worker.use(
    http.post('/dashboard', () => {
      return new HttpResponse(null, { status: 500 })
    }),
  )
 
  render(<Dashboard />)
 
  // Your actions and assertions...
})