{"_id":"@alexmchan/msw-testing","_rev":"3-9dad2c38ae53abbedfde5fa48184f958","name":"@alexmchan/msw-testing","dist-tags":{"latest":"3.0.0"},"versions":{"2.0.0":{"name":"@alexmchan/msw-testing","version":"2.0.0","_id":"@alexmchan/msw-testing@2.0.0","maintainers":[{"name":"alexanderchan","email":"alexander.m.chan@gmail.com"}],"homepage":"https://github.com/alexanderchan/memocache#readme","bugs":{"url":"https://github.com/alexanderchan/memocache/issues"},"dist":{"shasum":"7ba72adb4ce26963f7094864b615cbe3e7d502f1","tarball":"https://registry.npmjs.org/@alexmchan/msw-testing/-/msw-testing-2.0.0.tgz","fileCount":17,"integrity":"sha512-IcGbIgkU9x6qfPjjMD6c13ScTarrggGoZgI1YeasacYZtBvVqddrDHuFz22DIKmNtQ19Ty+seopsAPnxBdkYJg==","signatures":[{"sig":"MEUCIHhtqPwmJTnz1BU7LpoF978iwbOcS+q2+aEHBCc4oP0lAiEAq5mMX1miXGowNCHTQa7BiEmLtE0JGgT2PTX+49H0ThI=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":42339},"main":"dist/index.cjs","type":"module","_from":"file:alexmchan-msw-testing-2.0.0.tgz","types":"dist/index.d.cts","exports":{".":{"import":"./dist/index.cjs","default":"./dist/index.cjs"}},"scripts":{"lint":"eslint .","build":"tsup-node","lint:fix":"eslint . --fix","build:watch":"yarn run build --watch"},"_npmUser":{"name":"alexanderchan","email":"alexander.m.chan@gmail.com"},"_resolved":"/private/var/folders/7z/p1d5g8xj233bp74pfgx6fykh0000gp/T/adc01f2518c07fdb9c67e9ee17e50fe1/alexmchan-msw-testing-2.0.0.tgz","_integrity":"sha512-IcGbIgkU9x6qfPjjMD6c13ScTarrggGoZgI1YeasacYZtBvVqddrDHuFz22DIKmNtQ19Ty+seopsAPnxBdkYJg==","repository":{"url":"git+ssh://git@github.com/alexanderchan/memocache.git"},"_npmVersion":"10.9.2","description":"--- title: MSW Testing utils description: Recording with msw ---","directories":{},"_nodeVersion":"22.13.0","_hasShrinkwrap":false,"devDependencies":{"msw":"^2.6.6","tsup":"^8.3.5","eslint":"^9.15.0","prettier":"^3.4.1"},"peerDependencies":{"msw":">=2.0.0","prettier":">=3.0.0"},"_npmOperationalInternal":{"tmp":"tmp/msw-testing_2.0.0_1739548510846_0.20470089046299056","host":"s3://npm-registry-packages-npm-production"}},"2.0.1":{"name":"@alexmchan/msw-testing","version":"2.0.1","_id":"@alexmchan/msw-testing@2.0.1","maintainers":[{"name":"alexanderchan","email":"alexander.m.chan@gmail.com"}],"homepage":"https://github.com/alexanderchan/memocache#readme","bugs":{"url":"https://github.com/alexanderchan/memocache/issues"},"dist":{"shasum":"74608b020a1062bdcb890a9147b095b93cd02d72","tarball":"https://registry.npmjs.org/@alexmchan/msw-testing/-/msw-testing-2.0.1.tgz","fileCount":17,"integrity":"sha512-ujP1XsbVs2lkKXKSrrqogtEzF71iQLo0plTsjZLJHvIQiYWQS620WHEdeIXZh8bloLQooYX7qtp6Vfm2ohYmAQ==","signatures":[{"sig":"MEQCICx70Hki3nUWzzZ7br/2Lz/EtnIFKo4ZiQoKzXiE3VomAiAMZgKuWKv6NN29bmHnGTzA7NEU4cCUoNpYA92Ycvy65Q==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":42338},"main":"dist/index.cjs","type":"module","_from":"file:alexmchan-msw-testing-2.0.1.tgz","types":"dist/index.d.cts","exports":{".":{"import":"./dist/index.cjs","default":"./dist/index.cjs"}},"scripts":{"lint":"eslint .","build":"tsup-node","lint:fix":"eslint . --fix","build:watch":"yarn run build --watch"},"_npmUser":{"name":"alexanderchan","email":"alexander.m.chan@gmail.com"},"_resolved":"/private/var/folders/7z/p1d5g8xj233bp74pfgx6fykh0000gp/T/aa533ecd54fb594a35006d16ba671722/alexmchan-msw-testing-2.0.1.tgz","_integrity":"sha512-ujP1XsbVs2lkKXKSrrqogtEzF71iQLo0plTsjZLJHvIQiYWQS620WHEdeIXZh8bloLQooYX7qtp6Vfm2ohYmAQ==","repository":{"url":"git+ssh://git@github.com/alexanderchan/memocache.git"},"_npmVersion":"10.9.2","description":"--- title: MSW Testing utils description: Recording with msw ---","directories":{},"_nodeVersion":"22.13.0","_hasShrinkwrap":false,"devDependencies":{"msw":"^2.6.6","tsup":"^8.3.5","eslint":"^9.15.0","prettier":"^3.4.1"},"peerDependencies":{"msw":">=2.0.0","prettier":">=3.0.0"},"_npmOperationalInternal":{"tmp":"tmp/msw-testing_2.0.1_1739548673089_0.29649775226755737","host":"s3://npm-registry-packages-npm-production"}},"3.0.0":{"name":"@alexmchan/msw-testing","version":"3.0.0","type":"module","main":"dist/index.js","types":"dist/index.d.ts","exports":{".":{"import":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"default":{"types":"./dist/index.d.cts","default":"./dist/index.cjs"}}},"repository":{"url":"git+ssh://git@github.com/alexanderchan/memocache.git"},"peerDependencies":{"msw":">=2.0.0","prettier":">=3.0.0"},"devDependencies":{"msw":"^2.12.10","prettier":"^3.8.1","tsup":"^8.5.1","typescript":"^5.9.3","vite-tsconfig-paths":"^6.1.1","vitest":"^4.1.0"},"scripts":{"build":"tsup-node","build:watch":"pnpm run build --watch","typecheck":"tsc --noEmit","test":"vitest run","lint":"biome check .","lint:fix":"biome check --write ."},"_id":"@alexmchan/msw-testing@3.0.0","description":"--- title: MSW Testing utils description: Recording with msw ---","bugs":{"url":"https://github.com/alexanderchan/memocache/issues"},"homepage":"https://github.com/alexanderchan/memocache#readme","_integrity":"sha512-wziMjVTcnIJcpewTi8uMFIggUM7iTmPiXhCdguQ9hXkx6sSoYS4HTZVWGvNTjg4X9HenJdGCZ2fJkjtPmnyQpQ==","_resolved":"/private/var/folders/r7/v6yxz7l93hj4jz_lp08p8fbh0000gn/T/a59a08709459882df4e7748fce2e513a/alexmchan-msw-testing-3.0.0.tgz","_from":"file:alexmchan-msw-testing-3.0.0.tgz","_nodeVersion":"24.16.0","_npmVersion":"11.13.0","dist":{"integrity":"sha512-wziMjVTcnIJcpewTi8uMFIggUM7iTmPiXhCdguQ9hXkx6sSoYS4HTZVWGvNTjg4X9HenJdGCZ2fJkjtPmnyQpQ==","shasum":"94a1ec4b39d707cd1a62c4e829a0a7ede8eebb44","tarball":"https://registry.npmjs.org/@alexmchan/msw-testing/-/msw-testing-3.0.0.tgz","fileCount":7,"unpackedSize":29646,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQCt5ePAzduj3nOe3ftWJ95LVQpGLc7P0vqXzSS9XRqc+QIhANoPXz6AwJ8tzImj4poSAKGnu1Mc1HxXhF/tiIHmzO+W"}]},"_npmUser":{"name":"alexanderchan","email":"alexander.m.chan@gmail.com"},"directories":{},"maintainers":[{"name":"alexanderchan","email":"alexander.m.chan@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/msw-testing_3.0.0_1784073623302_0.6671040410788609"},"_hasShrinkwrap":false}},"time":{"created":"2025-02-14T15:55:10.711Z","modified":"2026-07-15T00:00:23.571Z","2.0.0":"2025-02-14T15:55:11.012Z","2.0.1":"2025-02-14T15:57:53.249Z","3.0.0":"2026-07-15T00:00:23.436Z"},"bugs":{"url":"https://github.com/alexanderchan/memocache/issues"},"homepage":"https://github.com/alexanderchan/memocache#readme","repository":{"url":"git+ssh://git@github.com/alexanderchan/memocache.git"},"description":"--- title: MSW Testing utils description: Recording with msw ---","maintainers":[{"name":"alexanderchan","email":"alexander.m.chan@gmail.com"}],"readme":"---\ntitle: MSW Testing utils\ndescription: Recording with msw\n---\n\n# @alexmchan/msw-testing\n\nA utility library for [Mock Service Worker (MSW)](https://mswjs.io/) that provides request recording, logging, and network control capabilities for testing HTTP interactions.\n\n## Features\n\n- 📝 Record HTTP requests and responses automatically\n- 💾 Log recorded requests to files in MSW handler format\n- 🔒 Control network connections during tests\n- 🔄 Convert recorded requests to reusable MSW handlers\n\n## Installation\n\n```bash\nnpm install @alexmchan/msw-testing msw prettier\n# or\nyarn add @alexmchan/msw-testing msw prettier\n```\n\n## Usage\n\n### Recording HTTP Requests\n\nThe request recorder captures all HTTP interactions and can log them to a file in MSW handler format:\n\n```typescript\nimport { http, passthrough } from 'msw'\nimport { setupServer } from 'msw/node'\nimport {\n  createMswRecorderHandler,\n  createMswFileLogger,\n  disableNetConnectHandler,\n} from '@alexmchan/msw-testing'\n\n// Create a file logger\nconst logging = await createMswFileLogger({\n  filenameWithPath: './test/recorded-handlers.ts',\n})\n\n// Create the recorder handler\nconst recorderHandler = createMswRecorderHandler({\n  logging,\n})\n\n// Define your handlers array\nexport const handlers = [\n  // Allow local requests to pass through\n  http.all('http://127.0.0.1*', () => passthrough()),\n\n  // Your mock handlers\n  http.get('https://api.example.com/users', () => {\n    return new HttpResponse(JSON.stringify({ users: [] }))\n  }),\n\n  // Record all other requests\n  recorderHandler,\n\n  // Optionally block unhandled requests\n  disableNetConnectHandler,\n]\n\n// Set up MSW server with handlers\nconst mockServer = setupServer(...handlers)\n\n// In your test setup\nbeforeAll(() => {\n  mockServer.listen()\n})\n\nafterEach(() => {\n  // Reset handlers between tests\n  mockServer.restoreHandlers()\n})\n\nafterAll(() => {\n  mockServer.close()\n})\n```\n\n### Disabling Network Connections\n\nTo ensure all HTTP requests are properly mocked during testing, add the `disableNetConnectHandler` as the last handler:\n\n```typescript\nimport { http } from 'msw'\nimport { setupServer } from 'msw/node'\nimport { disableNetConnectHandler } from '@alexmchan/msw-testing'\n\nconst mockServer = setupServer([\n  // Your mock handlers first\n  http.get('https://api.example.com/data', () => {\n    return new HttpResponse(JSON.stringify({ data: 'test' }))\n  }),\n\n  // Disable unmocked requests last\n  disableNetConnectHandler,\n])\n```\n\nThis will throw an error for any request that doesn't match your defined handlers, helping identify missing mocks.\n\n### Example Output\n\nWhen using the recorder, it generates MSW v2 handlers in this format:\n\n```typescript\nhttp.get('https://api.example.com/users', () => {\n  return new HttpResponse(\n    JSON.stringify({\n      users: [\n        { id: 1, name: 'John' },\n        { id: 2, name: 'Jane' },\n      ],\n    }),\n    {\n      status: 200,\n      headers: {\n        'content-type': 'application/json',\n      },\n    },\n  )\n})\n```\n\n### Complete Example with Tests\n\nHere's a complete example showing how to use the library in a test file:\n\n```typescript\nimport { http, HttpResponse, passthrough } from 'msw'\nimport { setupServer } from 'msw/node'\nimport {\n  createMswRecorderHandler,\n  createMswFileLogger,\n  disableNetConnectHandler,\n} from '@alexmchan/msw-testing'\nimport { afterAll, beforeAll, expect, it } from 'vitest'\nimport supertest from 'supertest'\n\n// Create logger and recorder\nconst logging = await createMswFileLogger()\nconst recorderHandler = createMswRecorderHandler({\n  logging,\n})\n\n// Define handlers\nconst handlers = [\n  // Allow local requests to pass through\n  http.all('http://127.0.0.1*', () => passthrough()),\n\n  // Example mock handler\n  http.get('https://api.example.com/products/:id', ({ params }) => {\n    return new HttpResponse(\n      JSON.stringify({ id: params.id, name: 'Test Product' }),\n      { status: 200 },\n    )\n  }),\n\n  // Record unhandled requests\n  recorderHandler,\n\n  // Block any other requests\n  disableNetConnectHandler,\n]\n\nconst mockServer = setupServer(...handlers)\n\n// Test setup\nbeforeAll(() => mockServer.listen())\nafterEach(() => mockServer.restoreHandlers())\nafterAll(() => mockServer.close())\n\n// Example test\nit('should handle product not found', async () => {\n  // Add a temporary handler for this test\n  mockServer.use(\n    http.get('https://api.example.com/products/not-found', () => {\n      return new HttpResponse(null, {\n        status: 404,\n        statusText: 'Not found',\n      })\n    }),\n  )\n\n  const response = await fetch('https://api.example.com/products/not-found')\n  expect(response.status).toBe(404)\n})\n```\n\n## API Reference\n\n### createMswRecorderHandler\n\nCreates an MSW handler that records all HTTP requests and responses.\n\n```typescript\nfunction createMswRecorderHandler({\n  logging?: (requestString: string, requestLogItem: RequestLogItem) => void\n}): HttpHandler\n```\n\n### createMswFileLogger\n\nCreates a logger function that writes recorded requests to a file.\n\n```typescript\nfunction createMswFileLogger({\n  filenameWithPath?: string // defaults to process.cwd() + '/tmp/msw-recorder.ts'\n}): Promise<(requestString: string, requestLogItem: RequestLogItem) => void>\n```\n\n### disableNetConnectHandler\n\nAn MSW handler that blocks all unmatched HTTP requests and writes them out.\n\n```typescript\nconst disableNetConnectHandler: HttpHandler\n```\n\n## Types\n\n### RequestLogItem\n\n```typescript\ntype RequestLogItem = {\n  request: {\n    method: string\n    url: string\n    requestBody?: string\n    requestJson?: unknown\n  }\n  response: {\n    status?: number\n    headers?: Record<string, string>\n    responseBody?: string\n    responseJson?: unknown\n    statusText?: string\n    type?: HttpResponse['type']\n  }\n}\n```\n\n## Diagram\n\n![msw diagram](https://raw.githubusercontent.com/alexanderchan/memocache/refs/heads/main/docs/src/assets/msw-diagram-1.svg)\n","readmeFilename":"README.md"}