Simple Architecture
Just an HTTP header. No Docker, no separate processes, no network proxies. Install, configure scenarios, test. Learn more →
Choosing the right testing tool depends on your architecture, team, and what you’re testing. This guide helps you understand where Scenarist fits and when other tools might be better suited.
Scenarist is built on MSW and adds a complete scenario management layer designed for modern testing workflows:
Simple Architecture
Just an HTTP header. No Docker, no separate processes, no network proxies. Install, configure scenarios, test. Learn more →
Test ID Isolation
Run hundreds of parallel tests with different scenarios against a single server. Each test’s header routes to its own scenario.
Runtime Switching
Change scenarios mid-test without restarts. Perfect for testing retry flows, error recovery, and multi-step user journeys.
First-Class Playwright
Dedicated fixtures with type-safe scenario switching and automatic test ID handling. Each test gets isolated state without manual header management.
Response Sequences
Ever tested a polling UI that shows pending → processing → complete? Most tools need complex state management. Scenarist: three lines of config.
Next.js Multi-Process (Solved)
Next.js has documented singleton issues that break MSW. Scenarist’s adapter includes built-in globalThis guards—one stable MSW instance regardless of module loading.
Scenarist's adapters aren't thin wrappers—they solve framework-specific challenges that would otherwise require significant boilerplate:
Next.js Adapter:
[MSW] Multiple handlers with the same URL errors and memory leaks. Scenarist's built-in singleton pattern (global.__scenarist_instance) handles this automatically.Without these solutions, you'd need to understand Next.js internals and implement the globalThis singleton pattern yourself—Scenarist handles it with a simple export const.
Most mock tools require separate instances for parallel test isolation. Scenarist uses header-based routing instead:
┌─────────────────────────────────────────────────────────────────┐│ Traditional approach: 10 parallel tests = 10 mock servers ││ ││ Test 1 → WireMock:8081 Test 6 → WireMock:8086 ││ Test 2 → WireMock:8082 Test 7 → WireMock:8087 ││ Test 3 → WireMock:8083 Test 8 → WireMock:8088 ││ Test 4 → WireMock:8084 Test 9 → WireMock:8089 ││ Test 5 → WireMock:8085 Test 10 → WireMock:8090 │├─────────────────────────────────────────────────────────────────┤│ Scenarist: 10 parallel tests = 1 server, 10 headers ││ ││ Test 1 ─┬─ x-scenarist-test-id: test-1 ─┬─→ scenario-a ││ Test 2 ─┤ x-scenarist-test-id: test-2 ─┤─→ scenario-b ││ ... ├─────────► App Server ─────────┤ ... ││ Test 9 ─┤ x-scenarist-test-id: test-9 ─┤─→ scenario-a ││ Test 10─┴─ x-scenarist-test-id: test-10─┴─→ scenario-c │└─────────────────────────────────────────────────────────────────┘Result: No container orchestration, no port allocation, no startup overhead. Tests run faster and CI stays simple.
| Feature | Scenarist | WireMock | Nock | Testcontainers | Playwright Mocks |
|---|---|---|---|---|---|
| Test isolation | Per-test via header | Per-server instance | Per-test setup | Per-container | Per-page |
| Runtime switching | Yes (single API call) | Yes (Admin API) | No | No | No |
| Server Components | Full support | Yes (network proxy) | No (E2E) / Yes (integration) | Yes (with WireMock module) | No |
| Setup complexity | npm install | JAR/Docker/npm | npm install | Docker required | Built-in |
| Parallel tests | Built-in (header routing) | Multiple instances or scenarios | Scope/persist management | Per-container | Per-page |
| Test framework | First-class Playwright | Generic HTTP | Generic | Generic | Built-in |
| Response sequences | Built-in | Built-in (Scenarios) | Manual | Via mock server | Manual |
| Stateful mocks | Built-in capture/inject | Built-in state machine | Manual | Via mock server | Manual |
| Language | TypeScript/JS | Language-agnostic | JavaScript | Language-agnostic | JavaScript |
Note: “Server Components” refers to E2E testing of React Server Components where requests originate on the server.
Testing tools fall into different categories based on how and where they intercept requests:
Network-Level Mocking
Scenarist, Nock, MSW
Intercept HTTP requests within your Node.js process. No external services needed. Fast setup, TypeScript-native.
Server-Based Mocking
WireMock
Standalone mock server that receives real network traffic. Language-agnostic but requires separate process management.
Container-Based Testing
Testcontainers
Runs real services in Docker containers. Different purpose—testing against real databases and services, not mocking.
Browser-Level Mocking
Playwright’s page.route()
Intercepts requests in the browser via Playwright’s built-in API. Perfect for SPAs, but cannot intercept server-side requests (Server Components, API routes).
Scenarist is built on top of Mock Service Worker (MSW)—the same battle-tested interception library used by thousands of projects. We don’t replace MSW; we add a scenario management layer on top.
What MSW provides:
What Scenarist adds:
If you need low-level control or use MSW for non-testing purposes (API development, storybook), use MSW directly. If you need scenario management for testing, Scenarist handles that layer.
Learn more about Scenarist + MSW →
Being explicit about when Scenarist isn’t the right choice:
Compare: Scenarist vs WireMock →
Testcontainers and Scenarist solve different problems—they’re often complementary. Many teams use both: Testcontainers for databases, Scenarist for external HTTP APIs.
Compare: Scenarist vs Testcontainers →
page.route() when…Note: This refers to Playwright’s native page.route() API for browser-side request interception—not Scenarist’s @scenarist/playwright-helpers package, which provides test fixtures for server-side scenario management.
Compare: Scenarist vs Playwright Mocks →
Still not sure? Here’s a decision tree:
1. Are you testing server-side code (Server Components, API routes)?
2. Do you need parallel tests with different scenarios?
3. Do you need to switch scenarios during a test?
4. Are you using Playwright for E2E testing?
5. Do you need response sequences or stateful mocks?
6. Are you in a non-JavaScript environment?
7. Does your app use databases alongside external HTTP APIs?