Skip to content

Browser mode: cannot overwrite request handler when MSW is initialized in setup file #6690

@foxaltus

Description

@foxaltus

Describe the bug

I have a HelloWorld.tsx component that displays a random joke using the https://api.chucknorris.io/jokes/random API (sorry about that), which I'm mocking using MSW:

// src/mocks/handlers.ts
import { http, HttpResponse } from "msw";

export const handlers = [
  http.get("https://api.chucknorris.io/jokes/random", () => {
    return HttpResponse.json({
      icon_url: "https://api.chucknorris.io/img/avatar/chuck-norris.png",
      id: "hbCl1mPLQHuKuZGij--jZA",
      url: "https://api.chucknorris.io/jokes/hbCl1mPLQHuKuZGij--jZA",
      value: "Chuck Norris can win connect four in three move",
    });
  }),
];

using the MSW worker:

// src/mock/browser.ts
import { setupWorker } from "msw/browser";
import { handlers } from "./handlers";

export const worker = setupWorker(...handlers);

MSW is initialized in vitest-setup.ts:

import { cleanup } from "@testing-library/react";
import { worker } from "./mocks/browser";

// from https://mswjs.io/docs/getting-started/integrate/node#setup
// Establish API mocking before all tests.
beforeAll(async () => {
  await worker.start({ onUnhandledRequest: "error" });
});

// Reset any request handlers that we may add during the tests,
// so they don't affect other tests.
afterEach(() => {
  worker.resetHandlers();
  cleanup();
});

// Clean up after the tests are finished.
afterAll(() => {
  worker.stop();
});

🐛 When I run the tests, the test cases that use default handlers pass, but the ones that override them fail, eg:

// HelloWorld.test.tsx

// PASS
test("tells a joke", async () => {
  const { findByText } = render(<HelloWorld name="Chuck" />);
  const element = await findByText(/Chuck Norris can win connect four/);
  expect(element).toBeInTheDocument();
});

// FAIL
test("tells another joke", async () => {
  worker.use(
    http.get("https://api.chucknorris.io/jokes/random", () =>
      HttpResponse.json({
        icon_url: "https://api.chucknorris.io/img/avatar/chuck-norris.png",
        id: "ihYDJ5NcT4mgj1vN5taKVQ",
        url: "https://api.chucknorris.io/jokes/ihYDJ5NcT4mgj1vN5taKVQ",
        value: "Chuck Norris can milk a bucket with a cow.",
      })
    )
  );
  const { findByText } = render(<HelloWorld name="Chuck" />);
  const element = await findByText(/Chuck Norris can milk a bucket/);
  expect(element).toBeInTheDocument();
});

The text from the response is not found (the one from the default mock is here though), which seems to indicate that the override is not working.

However, if I move the initialization from the setup file to the test file itself, then all tests pass 🤔

Refs:

Reproduction

The issue can be reproduced at https://github.com/foxaltus/vitest-browser-mode-msw.
The workaround can be seen here: https://github.com/foxaltus/vitest-browser-mode-msw/compare/workaround

Use pnpm run test script.

System Info

System:
    OS: Windows 11 10.0.26100
    CPU: (8) x64 11th Gen Intel(R) Core(TM) i7-1165G7 @ 2.80GHz
    Memory: 8.42 GB / 31.73 GB
  Binaries:
    Node: 18.20.2 - C:\Program Files\nodejs\node.EXE
    Yarn: 1.22.19 - ~\AppData\Roaming\npm\yarn.CMD
    npm: 10.5.0 - C:\Program Files\nodejs\npm.CMD
    pnpm: 9.9.0 - ~\AppData\Local\pnpm\pnpm.EXE
  Browsers:
    Edge: Chromium (129.0.2792.79)
    Internet Explorer: 11.0.26100.1882
  npmPackages:
    @vitejs/plugin-react: ^4.3.1 => 4.3.1 
    @vitest/browser: ^2.1.1 => 2.1.1
    @vitest/coverage-v8: ^2.1.1 => 2.1.1
    vite: ^5.4.8 => 5.4.8
    vitest: ^2.1.1 => 2.1.1

Used Package Manager

pnpm

Validations

Metadata

Metadata

Assignees

No one assigned

    Labels

    feat: browserIssues and PRs related to the browser runnerp3-minor-bugAn edge case that only affects very specific usage (priority)

    Type

    No type

    Projects

    Status

    Approved

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions