MSW Playwright Binding

repository·main·Indexed 42 days ago

https://github.com/mswjs/playwright

A Mock Service Worker (MSW) binding for Playwright version 0.6.7 that enables API mocking in end-to-end tests. It provides the `defineNetworkFixture` utility to intercept HTTP and WebSocket requests using MSW handlers via `page.route()`, avoiding cross-process messaging complexities.

Tokens
2.3K
Snippets
6
Records
10
Agent score
53%

What's inside MSW

  1. Configure the network fixture in Playwright

    main

    To use @msw/playwright, you should extend the Playwright test object with a network fixture. This is done using defineNetworkFixture.

    Recommended setup pattern:

    1. Define a handlers fixture containing your base MSW handlers.
    2. Define a network fixture that uses defineNetworkFixture to wrap the Playwright context and handlers.
    3. Call network.enable() before the test runs and network.disable() after it completes.
    4. Set { auto: true } on the fixture so it is automatically initialized for every test.
    // playwright.setup.ts
    import { test as testBase } from '@playwright/test'
    import { type AnyHandler } from 'msw'
    import { defineNetworkFixture, type NetworkFixture } from '@msw/playwright'
    import { handlers } from '../mocks/handlers.js'
    
    interface Fixtures {
      handlers: Array<AnyHandler>
      network: NetworkFixture
    }
    
    const test = testBase.extend<Fixtures>({
      // Initial list of the network handlers.
      handlers: [handlers, { option: true }],
    
      // A fixture you use to control the network in your tests.
      network: [
        async ({ context, handlers }, use) => {
          const network = defineNetworkFixture({
            context,
            handlers,
          })
    
          await network.enable()
          await use(network)
          await network.disable()
        },
        { auto: true },
      ],
    })
  2. Limitations of @msw/playwright

    main

    WebSocket URL Resolution

    Because context.routeWebSocket() does not provide information about which specific page triggered a WebSocket connection, relative WebSocket URLs used in ws.link(url) will resolve against the latest page created within the browser context.

  3. Mock APIs using the network fixture

    main

    Once the network fixture is configured, you can use network.use() within your tests to override or add new MSW handlers. This works similarly to the standard MSW worker.use() API but avoids the cross-process messaging issues typically found in Playwright by leveraging page.route() under the hood.

    import { http, HttpResponse } from 'msw'
    import { test } from './playwright.setup.js'
    
    test('displays the user dashboard', async ({ network, page }) => {
      // Access the network fixture and use it as the `setupWorker()` API.
      network.use(
        http.get('/user', () => {
          return HttpResponse.json({
            id: 'abc-123',
            firstName: 'John',
            lastName: 'Maverick',
          })
        }),
      )
    
      await page.goto('/dashboard')
    })
  4. Configure Playwright test environment

    main

    The playwright.config.ts file defines the execution environment for Playwright tests. Key configuration areas include:

    • testDir: Specifies the directory where tests are located.
    • projects: Defines different browser configurations (e.g., chromium) using Playwright devices.
    • use: Global settings for all tests, such as baseURL, screenshot behavior, video retention, and launchOptions (e.g., enabling devtools).
    • webServer: Automatically starts and manages the application server before running tests. It uses a command to start the app and a url to verify it is ready. The reuseExistingServer option allows using an already running server, which is useful in local development.
    • forbidOnly: Prevents tests from running if .only is present in the code, typically enabled in CI environments to ensure full test suites run.
    • fullyParallel: Enables running tests in parallel to improve speed.
    • reporter: Sets the output format for test results (e.g., 'list').
    import { defineConfig, devices } from '@playwright/test'
    
    export default defineConfig({
      testDir: './tests',
      projects: [
        {
          name: 'chromium',
          use: { ...devices['Desktop Chrome'] },
        },
      ],
      use: {
        baseURL: 'http://localhost:5173',
        screenshot: 'only-on-failure',
        video: 'retain-on-failure',
        launchOptions: {
          devtools: !process.env.CI,
        },
      },
      forbidOnly: !!process.env.CI,
      fullyParallel: true,
      reporter: 'list',
      webServer: {
        command: 'npm run app:build && npm run app:start',
        url: 'http://localhost:5173',
        reuseExistingServer: !process.env.CI,
        stderr: 'pipe',
      },
    })
  5. Configure `skipAssetRequests` for performance

    main

    By default, @msw/playwright skips common asset requests (e.g., *.html, *.css, *.js) to prevent performance degradation in Playwright when routing every single asset through the MSW matching engine.

    If your test suite requires mocking specific static assets, set skipAssetRequests: false in the NetworkFixtureOptions.

  6. Define a network fixture with `defineNetworkFixture`

    main

    Use defineNetworkFixture to create a network mocking instance for a Playwright BrowserContext. This fixture allows you to intercept HTTP and WebSocket requests using MSW handlers.

    Options

    • context: The Playwright BrowserContext to attach the fixture to.
    • handlers: An array of MSW handlers (AnyHandler) to use for mocking.
    • onUnhandledRequest: Strategy for handling requests that don't match any handler (e.g., 'bypass', 'error', 'warn').
    • skipAssetRequests: (Boolean, default: true) If true, common asset requests (like .css, .js, .html) are skipped to improve performance. Set to false if you need to mock these assets.
    import { defineNetworkFixture } from '@msw/playwright';
    import { http, rest } from 'msw';
    
    const networkFixture = defineNetworkFixture({
      context: browserContext,
      handlers: [
        http.get('/api/user', () => {
          return HttpResponse.json({ id: '1', name: 'John Doe' });
        }),
      ],
      skipAssetRequests: true,
    });
    
    // To start intercepting:
    await networkFixture.enable();
    
    // To stop intercepting:
    await networkFixture.disable();
  7. Manage fixture lifecycle with `enable` and `disable`

    main

    The NetworkFixture returned by defineNetworkFixture provides methods to control when network interception is active within a Playwright BrowserContext.

    • enable(): Activates the interception of HTTP and WebSocket requests using the provided handlers. This must be called before the tests that require mocking run.
    • disable(): Deactivates interception, disposes of the MSW setup, and removes all Playwright routes (both HTTP and WebSocket) created by the fixture.
    // Start mocking
    await networkFixture.enable();
    
    // ... run tests ...
    
    // Stop mocking
    await networkFixture.disable();
  8. Configure a network fixture with NetworkFixtureOptions

    main
    The NetworkFixtureOptions type defines the configuration available when calling defineNetworkFixture. Use this type to specify setup parameters for your network interception logic.