or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

fixture-management.mdhost-configuration.mdindex.mdmode-management.mdproxy-system.md
tile.json

tessl/npm-replay

HTTP request recording and replay system for API testing

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
npmpkg:npm/replay@2.4.x

To install, run

npx @tessl/cli install tessl/npm-replay@2.4.0

index.mddocs/

Replay

Replay is a comprehensive HTTP request recording and replay system designed for API testing. It allows developers to capture HTTP responses during initial test runs and replay them in subsequent runs without making actual network requests, creating deterministic, fast-running test suites.

Package Information

  • Package Name: replay
  • Package Type: npm
  • Language: JavaScript
  • Installation: npm install replay

Core Imports

const Replay = require('replay');

The package exports a single Replay instance that provides all functionality.

Basic Usage

const Replay = require('replay');

// Set mode to record new responses
Replay.mode = 'record';

// Configure fixtures directory
Replay.fixtures = __dirname + '/fixtures';

// Make HTTP requests - they will be recorded automatically
const http = require('http');
http.get('http://api.example.com/data', (response) => {
  // Response will be saved for future replay
});

// Later, in test mode (default)
Replay.mode = 'replay'; // Only replay captured responses

Architecture

Replay is built around several key components:

  • Mode System: Four operational modes (replay, record, cheat, bloody) controlling request behavior
  • Proxy Chain: Pluggable request processing pipeline with built-in handlers
  • Host Management: Flexible routing for localhost, pass-through, and dropped hosts
  • Catalog System: Manages fixture storage and retrieval on disk
  • Module Patching: Automatic interception of Node.js HTTP/HTTPS/DNS modules

Capabilities

Mode Management

Controls how Replay handles HTTP requests with four distinct operational modes.

// Mode property
Replay.mode: string; // 'replay' | 'record' | 'cheat' | 'bloody'

Mode Management

Host Configuration

Flexible host routing system for localhost redirection, pass-through, and connection dropping.

// Host configuration methods
Replay.localhost(...hosts: string[]): Replay;
Replay.passThrough(...hosts: string[]): Replay;
Replay.drop(...hosts: string[]): Replay;
Replay.reset(...hosts: string[]): Replay;

// Host checking methods
Replay.isLocalhost(host: string): boolean;
Replay.isPassThrough(host: string): boolean;
Replay.isDropped(host: string): boolean;

Host Configuration

Fixture Management

Recording and storage configuration for HTTP response fixtures.

// Fixture configuration
Replay.fixtures: string; // Directory path
Replay.headers: RegExp[]; // Headers to record/match

// Catalog access (internal fixture management)
Replay.catalog: Catalog;

Fixture Management

Proxy System

Extensible proxy chain system for custom request processing.

// Proxy chain methods
Replay.use(proxy: (request: any, callback: Function) => void): Replay;

// Built-in proxies
Replay.logger(): Function;

// Chain access (internal proxy chain management)
Replay.chain: Chain;

Proxy System

Environment Variables

// Environment variable configuration
process.env.REPLAY: 'replay' | 'record' | 'cheat' | 'bloody';
process.env.DEBUG: 'replay'; // Enable debug logging

Event Handling

Replay extends EventEmitter for error handling:

// Event handling
Replay.on(event: 'error', listener: (error: Error) => void): Replay;

Usage Examples:

const Replay = require('replay');

// Handle errors from the replay system
Replay.on('error', (error) => {
  console.error('Replay error:', error.message);
  
  // Common error types:
  if (error.code === 'ECONNREFUSED') {
    console.log('Request blocked - no fixture found and not in record mode');
  } else if (error.code === 'CORRUPT FIXTURE') {
    console.log('Fixture file is corrupted or malformed');
  }
});

Error Conditions

Common error scenarios and their handling:

// Connection refused - no fixture available in replay mode
class ReplayConnectionRefusedError extends Error {
  code: 'ECONNREFUSED';
  syscall: 'connect';
  message: 'Connection to {url} refused: not recording and no network access';
}

// Corrupt fixture file
class ReplayCorruptFixtureError extends Error {
  code: 'CORRUPT FIXTURE';
  syscall: 'connect';
  message: string;
}

// Unsupported mode
class ReplayUnsupportedModeError extends Error {
  message: 'Unsupported mode \'{mode}\', must be one of bloody, cheat, record, replay.';
}

Types

// Operational modes
type ReplayMode = 'replay' | 'record' | 'cheat' | 'bloody';

// Proxy handler function
type ProxyHandler = (request: ReplayRequest, callback: (error?: Error, response?: ReplayResponse) => void) => void;

// Response control function
type ResponseControlFunction = (request: ReplayRequest, response: ReplayResponse) => boolean;

// Host pattern (supports wildcards)
type HostPattern = string; // e.g., 'api.example.com', '*.example.com', 'api.*'

// Request object structure
interface ReplayRequest {
  url: URL;
  method: string;
  headers: { [key: string]: string | string[] };
  body?: Array<[Buffer | string, string]>;
  trailers?: { [key: string]: string | string[] };
}

// Response object structure
interface ReplayResponse {
  version: string;
  statusCode: number;
  statusMessage: string;
  rawHeaders: string[];
  headers: { [key: string]: string | string[] };
  body: Array<[Buffer | string, string]>;
  trailers?: { [key: string]: string | string[] };
  rawTrailers?: string[];
}

// Catalog class for fixture management
interface Catalog {
  find(host: string): Matcher[] | null;
  save(host: string, request: ReplayRequest, response: ReplayResponse, callback: (error?: Error) => void): void;
  getFixturesDir(): string;
  setFixturesDir(dir: string): void;
}

// Chain class for proxy management
interface Chain {
  append(handler: ProxyHandler): Chain;
  prepend(handler: ProxyHandler): Chain;
  clear(): void;
  start: ProxyHandler | null;
}

// Matcher class for request/response matching
interface Matcher {
  (request: ReplayRequest): ReplayResponse | null;
}