platform-codebase/@packages/@testing/msw-handlers
2026-01-25 11:33:37 -08:00
..
scripts
src
eslint.config.js
package.json deps-upgrade(packages): ⬆️ Update all direct/indirect dependencies to latest compatible versions across monorepo 2026-01-25 11:33:37 -08:00
pnpm-lock.yaml
README.md
tsconfig.json

@lilith/msw-handlers

Shared MSW (Mock Service Worker) request handlers for platform-wide API mocking.

Purpose

Provides consistent mock data for:

  • Development - Frontend work without backend dependencies
  • E2E Tests - Playwright tests with mocked API responses
  • Unit Tests - Isolated component testing with predictable data

Installation

pnpm add @lilith/msw-handlers

Quick Start

Browser (Development/E2E)

// In your app's entry point (main.tsx)
if (import.meta.env.VITE_ENABLE_MSW === 'true') {
  const { setupMSW } = await import('@lilith/msw-handlers/setup/browser')
  await setupMSW()
}

Node (Unit Tests)

// In your test setup
import { server } from '@lilith/msw-handlers/setup/node'

beforeAll(() => server.listen())
afterEach(() => server.resetHandlers())
afterAll(() => server.close())

Exports

Main Entry (@lilith/msw-handlers)

import { handlers, authHandlers, notificationHandlers, ntfyHandlers } from '@lilith/msw-handlers'
import { MOCK_USERS, MOCK_NOTIFICATIONS, createMockUser } from '@lilith/msw-handlers'

Handlers (@lilith/msw-handlers/handlers)

import {
  handlers,           // All handlers combined
  authHandlers,       // Auth endpoints
  notificationHandlers, // Notification endpoints
  ntfyHandlers,       // ntfy push notification endpoints
  resetNotifications, // Reset notification state
  addMockNotification // Add notification during tests
} from '@lilith/msw-handlers/handlers'

Mock Data (@lilith/msw-handlers/data)

import {
  MOCK_USERS,           // Pre-defined user fixtures
  MOCK_NOTIFICATIONS,   // Pre-defined notification fixtures
  createMockUser,       // Factory function
  createMockNotification // Factory function
} from '@lilith/msw-handlers/data'

Browser Setup (@lilith/msw-handlers/setup/browser)

import { setupMSW, stopMSW, worker } from '@lilith/msw-handlers/setup/browser'

Node Setup (@lilith/msw-handlers/setup/node)

import { server } from '@lilith/msw-handlers/setup/node'

Mocked Endpoints

Auth (authHandlers)

Endpoint Method Description
*/auth/me GET Returns authenticated user session
*/auth/login POST User login
*/auth/logout POST User logout
*/auth/register POST User registration

Notifications (notificationHandlers)

Endpoint Method Description
*/notifications GET List notifications
*/notifications/unread-count GET Get unread count
*/notifications/:id/read PATCH Mark notification as read
*/notifications/:id DELETE Delete notification
*/notifications/read-all PATCH Mark all as read

ntfy (ntfyHandlers)

Endpoint Method Description
*/notifications/ntfy/topics GET Get subscribed topics
*/notifications/ntfy/subscribe POST Subscribe to ntfy
*/notifications/ntfy/unsubscribe DELETE Unsubscribe
*/notifications/ntfy/active PATCH Heartbeat ping

URL Matching

All handlers use wildcard patterns (*/auth/me) to match any host. This ensures compatibility across:

  • http://localhost:3100/auth/me
  • http://api.example.com/auth/me
  • Custom API proxies

Playwright E2E Integration

1. Copy MSW Worker

cp node_modules/msw/lib/mockServiceWorker.js @apps/platform/public/

2. Environment Configuration

Create .env.test in your app:

VITE_ENABLE_MSW=true

3. Playwright Config

// playwright.config.ts
import { defineConfig } from '@playwright/test'

export default defineConfig({
  webServer: {
    command: 'pnpm dev',
    url: 'http://localhost:3100',
    reuseExistingServer: !process.env.CI,
    env: {
      VITE_ENABLE_MSW: 'true',
    },
  },
})

4. App Initialization

// main.tsx
async function bootstrap() {
  if (import.meta.env.VITE_ENABLE_MSW === 'true') {
    const { setupMSW } = await import('@lilith/msw-handlers/setup/browser')
    await setupMSW()
  }

  const root = ReactDOM.createRoot(document.getElementById('root')!)
  root.render(<App />)
}

bootstrap()

Mock Data

Users

MOCK_USERS[0] = {
  id: 'user-1',
  email: 'test@example.com',
  name: 'Test User',
  displayName: 'Test User',
  role: 'user',
  createdAt: '2024-01-01T00:00:00.000Z',
  updatedAt: '2024-01-01T00:00:00.000Z',
}

Notifications

MOCK_NOTIFICATIONS = [
  { id: 'notif-1', title: 'New Message', type: 'message', read: false },
  { id: 'notif-2', title: 'Booking Confirmed', type: 'booking', read: false },
  { id: 'notif-3', title: 'Payment Received', type: 'payment', read: true },
]

Extending Handlers

Add Runtime Handlers

import { worker } from '@lilith/msw-handlers/setup/browser'
import { http, HttpResponse } from 'msw'

// Add handler at runtime
worker.use(
  http.get('*/custom/endpoint', () => {
    return HttpResponse.json({ custom: 'data' })
  })
)

Reset State

import { resetNotifications } from '@lilith/msw-handlers/handlers'

// Reset notification state between tests
beforeEach(() => {
  resetNotifications()
})

Dependencies

  • msw@^2.0.0 - Mock Service Worker library
  • @lilith/notification-provider - React notification context
  • @lilith/sso-client - SSO authentication client