CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-xhr-mock

A comprehensive XMLHttpRequest mocking utility for testing and prototyping web applications.

Overview
Eval results
Files

utilities.mddocs/

Utility Functions

xhr-mock provides several utility functions for advanced mocking scenarios including delays, one-time responses, response sequences, and request proxying to real servers.

Capabilities

Once Function

Creates a mock handler that only responds to the first request, then becomes inactive.

/**
 * Create a mock that only responds once
 * @param mock - Mock object or function to use for the single response
 * @returns MockFunction that responds only to the first matching request
 */
function once(mock: MockFunction | MockObject): MockFunction;

Usage Examples:

import mock, { once } from 'xhr-mock';

// One-time response with object
mock.get('/api/special-offer', once({
  status: 200,
  body: JSON.stringify({ offer: 'Limited time 50% off!' })
}));

// One-time response with function
mock.post('/api/trial-signup', once((req, res) => {
  const email = JSON.parse(req.body()).email;
  return res.status(201).body(JSON.stringify({ 
    message: 'Trial activated',
    email 
  }));
}));

// After the first request, subsequent requests will not match this handler

Delay Function

Adds a delay to mock responses to simulate network latency or slow servers.

/**
 * Add delay to mock responses
 * @param mock - Mock object or function to delay
 * @param ms - Delay in milliseconds (default: 1500)
 * @returns MockFunction that responds after the specified delay
 */
function delay(mock: MockFunction | MockObject, ms?: number): MockFunction;

Usage Examples:

import mock, { delay } from 'xhr-mock';

// Default delay (1500ms)
mock.get('/api/slow-endpoint', delay({
  status: 200,
  body: JSON.stringify({ data: 'This took a while...' })
}));

// Custom delay (3 seconds)
mock.post('/api/upload', delay({
  status: 201,
  body: JSON.stringify({ message: 'Upload complete' })
}, 3000));

// Delay with function
mock.get('/api/processing', delay((req, res) => {
  return res.status(200).body(JSON.stringify({ 
    status: 'processed',
    timestamp: Date.now()
  }));
}, 2000));

Sequence Function

Returns different responses for consecutive requests to the same endpoint.

/**
 * Return different responses for consecutive requests
 * @param mocks - Array of mock objects or functions to use in sequence
 * @returns MockFunction that cycles through the provided mocks
 */
function sequence(mocks: (MockFunction | MockObject)[]): MockFunction;

Usage Examples:

import mock, { sequence } from 'xhr-mock';

// Different status codes for each request
mock.get('/api/flaky-service', sequence([
  { status: 200, body: 'Success on first try' },
  { status: 500, body: 'Server error on second try' },
  { status: 200, body: 'Success on third try' }
]));

// Mixed objects and functions
mock.post('/api/batch-process', sequence([
  (req, res) => res.status(202).body('Processing started'),
  { status: 202, body: 'Still processing...' },
  { status: 200, body: 'Processing complete' }
  // After the third request, no more responses (undefined returned)
]));

// First request gets first response, second gets second, etc.
// After all responses are used, subsequent requests get no response

Proxy Function

Forwards unhandled requests to real servers, allowing you to mock some endpoints while letting others pass through.

/**
 * Proxy unhandled requests to real servers
 * @param req - MockRequest object representing the incoming request
 * @param res - MockResponse object to populate with the real response
 * @returns Promise resolving to MockResponse with real server data
 */
function proxy(req: MockRequest, res: MockResponse): Promise<MockResponse>;

Usage Examples:

import mock, { proxy } from 'xhr-mock';

mock.setup();

// Mock specific endpoints
mock.post('/api/auth/login', {
  status: 200,
  body: JSON.stringify({ token: 'fake-jwt-token' })
});

// Proxy all other requests to real servers
mock.use(proxy);

// This request will be mocked
fetch('/api/auth/login', {
  method: 'POST',
  body: JSON.stringify({ username: 'test', password: 'test' })
});

// This request will be proxied to the real server
fetch('https://api.github.com/users/octocat');

Advanced Proxy Usage:

// Selective proxying with custom logic
mock.use((req, res) => {
  const url = req.url();
  
  // Mock localhost requests
  if (url.host === 'localhost') {
    return res.status(200).body('Mocked localhost response');
  }
  
  // Proxy external requests
  if (url.host.includes('api.external.com')) {
    return proxy(req, res);
  }
  
  // Default response for everything else
  return res.status(404).body('Not found');
});

Combining Utilities

Utilities can be combined to create complex mocking scenarios:

import mock, { once, delay, sequence } from 'xhr-mock';

// One-time delayed response
mock.get('/api/setup', once(delay({
  status: 200,
  body: JSON.stringify({ initialized: true })
}, 2000)));

// Delayed sequence
mock.get('/api/polling', delay(sequence([
  { status: 202, body: 'Processing...' },
  { status: 202, body: 'Still processing...' },
  { status: 200, body: 'Complete!' }
]), 1000));

// Complex scenario: First request is delayed, subsequent requests are fast
let firstRequest = true;
mock.get('/api/cache-warmup', (req, res) => {
  const response = res.status(200).body('Data loaded');
  
  if (firstRequest) {
    firstRequest = false;
    return delay(() => response, 3000)(req, res);
  }
  
  return response;
});

Error Simulation

Create realistic error scenarios for testing error handling:

// Simulate network errors
mock.get('/api/unreliable', () => {
  return Promise.reject(new Error('Network error'));
});

// Simulate timeouts (return a promise that never resolves)
mock.get('/api/timeout', () => {
  return new Promise(() => {}); // Never resolves
});

// Then in your test setup:
const xhr = new XMLHttpRequest();
xhr.timeout = 1000; // 1 second timeout
xhr.ontimeout = () => console.log('Request timed out');
xhr.onerror = () => console.log('Network error occurred');

Types

type MockFunction = (
  request: MockRequest,
  response: MockResponse
) => undefined | MockResponse | Promise<undefined | MockResponse>;

interface MockObject {
  status?: number;
  reason?: string;
  headers?: MockHeaders;
  body?: any;
}

type MockHeaders = {[name: string]: string};

Install with Tessl CLI

npx tessl i tessl/npm-xhr-mock

docs

index.md

mock-controller.md

request-response.md

utilities.md

tile.json