| |

API Mocking With MSW: Share Mock Handlers Between Unit Tests and Playwright E2E

Mock Service Worker (MSW) intercepts requests at the network level — no application code changes needed. Perfect for frontend testing when backend is unavailable, unstable, or slow.

🎭 Want to master this with real projects? Join the Playwright Automation Mastery course at The Testing Academy.

Contents

MSW vs Playwright page.route()

FeatureMSWpage.route()
Works without browserYes (Node.js)No (needs page)
Shared between unit + E2EYesNo (E2E only)
Request matchingREST + GraphQL handlersURL pattern matching
TypeScript handlersStrongly typedGeneric
Setup complexityService worker configOne line per route

Setup MSW

npm install -D msw

Define Handlers

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

export const handlers = [
  http.get('/api/users', () => {
    return HttpResponse.json([
      { id: 1, name: 'John', email: 'john@test.com' },
      { id: 2, name: 'Jane', email: 'jane@test.com' },
    ]);
  }),

  http.post('/api/users', async ({ request }) => {
    const body = await request.json();
    return HttpResponse.json(
      { id: 3, ...body },
      { status: 201 }
    );
  }),

  http.get('/api/users/:id', ({ params }) => {
    if (params.id === '999') {
      return HttpResponse.json(
        { message: 'User not found' },
        { status: 404 }
      );
    }
    return HttpResponse.json({ id: params.id, name: 'User ' + params.id });
  }),
];

🚀 Level Up Your Playwright

From locators to CI pipelines — build a production-grade Playwright + TypeScript framework step by step.

Use in Playwright Tests

// Inject MSW handlers via page.route() bridge
import { handlers } from '../mocks/handlers';

test.beforeEach(async ({ page }) => {
  for (const handler of handlers) {
    // Convert MSW handlers to page.route() calls
    await page.route(handler.info.path, async route => {
      const response = await handler.resolver(/* ... */);
      await route.fulfill({
        status: response.status,
        body: JSON.stringify(response.body),
      });
    });
  }
});

Error Scenario Testing

// Override handler for specific test
test('handle server error', async ({ page }) => {
  await page.route('**/api/users', route => {
    route.fulfill({ status: 500, body: '{"error":"Internal Server Error"}' });
  });
  await page.goto('/users');
  await expect(page.getByText('Failed to load users')).toBeVisible();
});

GraphQL Mocking with MSW

import { graphql, HttpResponse } from 'msw';

export const graphqlHandlers = [
  graphql.query('GetUsers', () => {
    return HttpResponse.json({
      data: {
        users: [{ id: 1, name: 'John' }]
      }
    });
  }),

  graphql.mutation('CreateUser', async ({ variables }) => {
    return HttpResponse.json({
      data: {
        createUser: { id: 99, name: variables.name }
      }
    });
  }),
];

🎓 Master Playwright End to End

Join hundreds of SDETs building real automation frameworks. Lifetime access, hands-on projects, and a job-ready portfolio.

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.