veza/apps/web/src/docs/MSW_SETUP.md

5.1 KiB

MSW (Mock Service Worker) Setup Guide

FE-API-019: API Mocking for Development

This guide explains how to use MSW (Mock Service Worker) for API mocking during development and testing.

Overview

MSW allows you to intercept and mock HTTP requests at the network level, making it perfect for:

  • Development without a running backend
  • Testing with consistent mock data
  • Simulating error scenarios
  • Testing offline behavior

Configuration

Environment Variable

MSW is controlled by the VITE_USE_MSW environment variable:

# Enable MSW
VITE_USE_MSW=1 npm run dev

# Or use the dedicated script
npm run dev:mocks

# Disable MSW (default)
VITE_USE_MSW=0 npm run dev

Initialization

MSW is automatically initialized in main.tsx when:

  • VITE_USE_MSW is set to 1 or true
  • Running in development mode (import.meta.env.DEV)

The worker is started before the React app renders to ensure all requests are intercepted.

File Structure

apps/web/src/mocks/
├── handlers.ts      # Mock request handlers
├── browser.ts       # Browser worker setup
├── node.ts          # Node.js server setup (for tests)
├── index.ts         # Exports
└── test-setup.ts    # Test configuration

Adding New Handlers

Edit apps/web/src/mocks/handlers.ts to add new mock handlers:

import { http, HttpResponse } from 'msw';

export const handlers = [
  // GET request
  http.get('/api/v1/endpoint', () => {
    return HttpResponse.json({
      data: {
        /* mock data */
      },
    });
  }),

  // POST request with body
  http.post('/api/v1/endpoint', async ({ request }) => {
    const body = await request.json();
    return HttpResponse.json(
      {
        data: {
          /* response */
        },
      },
      { status: 201 },
    );
  }),

  // Request with parameters
  http.get('/api/v1/endpoint/:id', ({ params }) => {
    const { id } = params;
    return HttpResponse.json({
      data: { id /* ... */ },
    });
  }),

  // Request with query parameters
  http.get('/api/v1/endpoint', ({ request }) => {
    const url = new URL(request.url);
    const param = url.searchParams.get('param');
    return HttpResponse.json({
      data: { param /* ... */ },
    });
  }),

  // Error response
  http.get('/api/v1/error', () => {
    return HttpResponse.json(
      { error: 'Something went wrong' },
      { status: 500 },
    );
  }),
];

URL Matching

Important: MSW handlers must match the full URL path that the client sends.

Since apiClient uses baseURL: env.API_URL (e.g., http://127.0.0.1:8080/api/v1), handlers should match:

  • /api/v1/roles (matches full path)
  • http://127.0.0.1:8080/api/v1/roles (matches full URL)
  • /roles (won't match if baseURL is set)

However, MSW can match relative paths if configured correctly. The current setup uses relative paths like /api/v1/*.

Current Handlers

The following endpoints are currently mocked:

Authentication

  • POST /api/auth/login
  • POST /api/auth/register
  • POST /api/auth/refresh
  • GET /api/users/profile
  • PUT /api/users/profile

Chat

  • GET /api/chat/conversations
  • GET /api/chat/conversations/:id/messages
  • POST /api/chat/conversations/:id/messages

Library

  • GET /api/library/tracks
  • POST /api/library/tracks

Health & Errors

  • GET /api/health
  • GET /api/error/500
  • GET /api/error/404
  • GET /api/error/timeout

Testing with MSW

In Unit Tests

import { server } from '@/mocks/test-setup';
import { handlers, errorHandlers } from '@/mocks/handlers';

beforeAll(() => {
  server.listen();
});

afterEach(() => {
  server.resetHandlers();
});

afterAll(() => {
  server.close();
});

// Use error handlers for error scenarios
test('handles error', () => {
  server.use(...errorHandlers);
  // Test error handling
});

In E2E Tests

# Run E2E tests with MSW
npm run test:e2e:msw

Best Practices

  1. Keep handlers realistic: Mock data should match the real API structure
  2. Use variables: Store mock data in constants for reusability
  3. Handle edge cases: Add handlers for error scenarios (400, 401, 500, etc.)
  4. Document changes: Update this guide when adding new handlers
  5. Test both paths: Test with MSW enabled and disabled

Troubleshooting

MSW not intercepting requests

  1. Check that VITE_USE_MSW=1 is set
  2. Verify mockServiceWorker.js exists in public/
  3. Check browser console for MSW initialization messages
  4. Ensure handlers match the exact URL path

Handler not matching

  1. Check the exact URL being sent (check Network tab)
  2. Verify the handler path matches exactly
  3. Use onUnhandledRequest: 'warn' to see unmatched requests

Service Worker issues

  1. Clear browser cache and service workers
  2. Unregister old service workers in DevTools > Application > Service Workers
  3. Restart the dev server

Updating Mock Service Worker

If MSW version is updated, regenerate the service worker:

npx msw init public/ --save