Skip to content

Tool Comparison

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.

Framework Adapters Solve Real Problems

Scenarist's adapters aren't thin wrappers—they solve framework-specific challenges that would otherwise require significant boilerplate:

Next.js Adapter:

  • Module duplication protection — Next.js dev mode and Turbopack can load modules multiple times, causing [MSW] Multiple handlers with the same URL errors and memory leaks. Scenarist's built-in singleton pattern (global.__scenarist_instance) handles this automatically.
  • Pages + App Router isolation — Separate global state keys enable gradual migration without scenario cross-contamination.
  • Conditional exports — Zero MSW code in production bundles via automatic tree-shaking.

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.

FeatureScenaristWireMockNockTestcontainersPlaywright Mocks
Test isolationPer-test via headerPer-server instancePer-test setupPer-containerPer-page
Runtime switchingYes (single API call)Yes (Admin API)NoNoNo
Server ComponentsFull supportYes (network proxy)No (E2E) / Yes (integration)Yes (with WireMock module)No
Setup complexitynpm installJAR/Docker/npmnpm installDocker requiredBuilt-in
Parallel testsBuilt-in (header routing)Multiple instances or scenariosScope/persist managementPer-containerPer-page
Test frameworkFirst-class PlaywrightGeneric HTTPGenericGenericBuilt-in
Response sequencesBuilt-inBuilt-in (Scenarios)ManualVia mock serverManual
Stateful mocksBuilt-in capture/injectBuilt-in state machineManualVia mock serverManual
LanguageTypeScript/JSLanguage-agnosticJavaScriptLanguage-agnosticJavaScript

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:

  • Request interception at the network level
  • Works with any HTTP client (fetch, axios, etc.)
  • Proven reliability and active maintenance

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 →

  • Testing server-side code (Server Components, API routes, middleware)
  • Running parallel tests that need different external API states
  • Wanting to switch scenarios at runtime without restarts
  • Using Playwright and want first-class fixtures with type-safe scenario switching
  • Need response sequences for polling APIs, retry flows, or state machines
  • Need stateful mocks that capture request data and inject it into responses
  • Working in TypeScript/JavaScript ecosystems
  • Testing how your app handles various external API scenarios (errors, timeouts, edge cases)

Being explicit about when Scenarist isn’t the right choice:

  • Pure client-side SPAs — If all HTTP calls originate in the browser, Playwright’s built-in mocks may be simpler
  • Java/Python/.NET shops — WireMock’s ecosystem is better suited for non-JavaScript teams
  • Need recording/playback — Use Nock (nockBack) or WireMock if you need to capture real API responses
  • Simple unit tests without parallelism — Nock is lighter-weight if you don’t need scenario management
  • Database testing — Scenarist mocks HTTP only. See Testing Database Apps for database strategies
  • Contract testing — Use WireMock with Spring Cloud Contract or similar frameworks
  • Working in non-JavaScript environments (Java, Python, .NET)
  • Need recording/playback of real API interactions
  • Want a standalone mock server independent of your test process
  • Team is already familiar with WireMock’s ecosystem

Compare: Scenarist vs WireMock →

  • Writing simple unit tests with per-test mock setup
  • Don’t need parallel test isolation
  • Prefer lighter-weight approach without framework adapters
  • Already using Nock and don’t need scenario management

Compare: Scenarist vs Nock →

  • Testing against real databases (PostgreSQL, MongoDB)
  • Need actual service behavior, not mocks
  • Testing infrastructure integration (Redis, Kafka, Elasticsearch)
  • Want production-like environment in tests

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 →

Choose Playwright’s built-in page.route() when…

Section titled “Choose Playwright’s built-in page.route() when…”
  • Testing client-side only applications (SPAs)
  • All HTTP calls originate from the browser
  • Don’t have server-side rendering or Server Components
  • Want zero additional dependencies for simple browser-side mocking

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)?

  • Yes → Scenarist, WireMock, or Nock (not Playwright mocks)
  • No (client-side only) → Playwright mocks may be sufficient

2. Do you need parallel tests with different scenarios?

  • Yes → Scenarist (built-in isolation) or WireMock (multiple instances)
  • No → Any tool works

3. Do you need to switch scenarios during a test?

  • Yes → Scenarist (single API call) or WireMock (Admin API)
  • No → Any tool works

4. Are you using Playwright for E2E testing?

  • Yes → Scenarist (first-class fixtures with type-safe scenarios and automatic test ID isolation)
  • No → Any tool works

5. Do you need response sequences or stateful mocks?

  • Yes → Scenarist (built-in, per-test-ID isolation) or WireMock (built-in Scenarios)
  • No → Any tool works

6. Are you in a non-JavaScript environment?

  • Yes → WireMock
  • No → Scenarist or Nock

7. Does your app use databases alongside external HTTP APIs?