npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@clevercloud/doublure

v0.0.2

Published

Mock API testing framework with a Fastify-based mock HTTP server, fluent mock configuration, call verification, and SSE support. Integrates with Vitest and Web Test Runner for identical usage in Node.js and browser environments.

Readme

Mock API Testing Infrastructure

A comprehensive testing framework for mocking HTTP APIs in both Node.js and browser environments. This infrastructure provides a complete solution for creating, managing, and verifying mock API responses during testing.

Overview

The Mock API system consists of several key components:

  • Mock Server - HTTP server that responds to API calls with configured responses
  • Admin Interface - Management API for configuring mocks and retrieving call logs
  • Fluent API - Chainable interface for easy mock configuration
  • Verification System - Tools for validating API calls and responses
  • Test Integration - Hooks and plugins for seamless test framework integration

Quick Start

import { mockScenario } from '@clevercloud/doublure';
import { serverStart } from '@clevercloud/doublure/server';

// Start mock server
const { mockClient, stop } = await serverStart();

try {
  // Configure a mock
  await mockScenario(mockClient)
    .when({ method: 'GET', path: '/api/users' })
    .respond({ status: 200, body: [{ id: 1, name: 'John' }] });

  // Make API calls
  const response = await fetch(`${mockClient.baseUrl}/api/users`);
  const users = await response.json();

  // Verify calls
  const calls = await mockClient.getCalls();
  expect(calls).toHaveLength(1);
} finally {
  await stop();
}

Core Components

MockClient (lib/mock-client.ts)

The foundational client for interacting with the mock server infrastructure.

Key Features:

  • Configures mock responses via admin interface
  • Retrieves call logs for verification
  • Resets mock state between tests
  • Works in both Node.js and browser environments

Example:

import { MockClient } from '@clevercloud/doublure';

const mockClient = new MockClient('http://localhost:3001', 'http://localhost:3000');

// Configure a regular HTTP mock
await mockClient.mock({
  request: { method: 'GET', path: '/api/users' },
  response: { status: 200, body: [] },
});

// Configure a Server-Sent Events mock
await mockClient.mock({
  request: { method: 'GET', path: '/api/events' },
  response: {
    status: 200,
    events: [
      { type: 'message', event: 'DATA', data: 'hello world' },
      { type: 'message', event: 'END_OF_STREAM' },
    ],
    delayBetween: 50,
  },
});

// Get call logs
const calls = await mockClient.getCalls();

MockScenario (lib/mock-scenario.ts)

Fluent API for describing a mocked test scenario: a set of request/response pairs, optionally composed with a callback to exercise them and expectations to verify the calls that were made.

Key Features:

  • Chainable API for mock configuration
  • Single or multiple mocks per scenario
  • Execute a callback after mocks are applied
  • Verify API calls with detailed inspection
import { mockScenario } from '@clevercloud/doublure';

// Mock-only scenario
await mockScenario(mockClient)
  .when({ method: 'GET', path: '/api/users' })
  .respond({ status: 200, body: [] })
  .when({ method: 'POST', path: '/api/users' })
  .respond({ status: 201, body: { id: 1 } })
  .when({ method: 'GET', path: '/api/events' })
  .respond({
    status: 200,
    events: [
      { type: 'message', event: 'DATA', data: 'hello world' },
      { type: 'close' }, // ask the server to close the SSE
    ],
    delayBetween: 50,
  });

// HTTP response verification
const result = await mockScenario(mockClient)
  .when({ method: 'GET', path: '/api/users' })
  .respond({ status: 200, body: [] })
  .thenCall(async () => {
    return await fetch('/api/users').then((r) => r.json());
  })
  .verify((calls) => {
    expect(calls.count).toBe(1);
    expect(calls.first.method).toBe('GET');
  });

// Server-Sent Events verification
await mockScenario(mockClient)
  .when({ method: 'GET', path: '/api/stream' })
  .respond({
    status: 200,
    events: [
      { type: 'message', event: 'DATA', data: 'event1' },
      { type: 'message', event: 'DATA', data: 'event2' },
      { type: 'close' },
    ],
    delayBetween: 10,
  })
  .thenCall(async () => {
    // Your SSE client code here - could use EventSource in browser
    // or a streaming HTTP client in Node.js to read the events
    await fetch('/api/stream', {
      headers: { Accept: 'text/event-stream' },
    });
  })
  .verify((calls) => {
    expect(calls.count).toBe(1);
    expect(calls.first.headers.accept).toBe('text/event-stream');
  });

Mock Server (server.ts)

HTTP server implementation that handles both mock responses and admin operations.

Key Features:

  • Serves mock responses based on configured rules
  • Provides admin API for mock management
  • Logs all incoming requests for verification
  • Supports response delays and throttling
  • Server-Sent Events (SSE) streaming with configurable events and delays

Server Endpoints:

  • POST /mock - Configure a new mock response
  • POST /calls - Retrieve call logs for specific requests
  • POST /reset - Clear all mocks and call logs
  • * - Serve configured mock responses

SSE Event Types:

  • { type: 'message', event: 'EVENT_NAME', data?: any, id?: string, retry?: number } - Send SSE message
  • { type: 'close' } - Close the connection

Test Integration

Test Hooks (support/hooks.ts)

Lifecycle hooks for integrating with test frameworks like Mocha, Jest, etc.

Example with Mocha:

import { doublureHooks } from '@clevercloud/doublure/testing';

describe('API Tests', () => {
  const hooks = doublureHooks();
  let newScenario;

  before(async () => {
    newScenario = await hooks.before();
  });

  beforeEach(hooks.beforeEach);

  after(hooks.after);

  it('should handle user requests', async () => {
    const result = await newScenario()
      .when({ method: 'GET', path: '/api/users' })
      .respond({ status: 200, body: [] })
      .thenCall(() => fetch('/api/users').then((r) => r.json()))
      .verify((calls) => {
        expect(calls.count).toBe(1);
        expect(calls.first.method).toBe('GET');
      });

    // Your test code here
  });

  it('should handle SSE streams', async () => {
    await newScenario()
      .when({ method: 'GET', path: '/api/events' })
      .respond({
        status: 200,
        events: [
          { type: 'message', event: 'DATA', data: 'event1' },
          { type: 'message', event: 'END_OF_STREAM' },
        ],
        delayBetween: 10,
      });

    // Your SSE client code here - use EventSource in browser or streaming client in Node.js
    const response = await fetch('/api/events', {
      headers: { Accept: 'text/event-stream' },
    });

    expect(response.headers.get('content-type')).toBe('text/event-stream');
  });
});

Vitest Plugin (support/vitest-plugin.ts)

Plugin for integrating with Vitest browser mode for browser-based testing.

Configuration:

// vitest.config.ts
import { vitestPlugin } from '@clevercloud/doublure/vitest';
import { playwright } from '@vitest/browser-playwright';
import { createConfigBuilder } from 'vitest/config';

export default createConfigBuilder({
  plugins: [vitestPlugin()],
  test: {
    include: ['src/**/*.test.ts'],
    browser: {
      enabled: true,
      headless: true,
      provider: playwright(),
      instances: [{ browser: 'chromium' }],
    },
  },
});

Web Test Runner Plugin (support/web-test-runner-plugin.ts)

Plugin for integrating with Web Test Runner for browser-based testing.

Configuration:

// web-test-runner.config.js
import { mockApiPlugin } from '@clevercloud/doublure/wtr';

export default {
  plugins: [
    mockApiPlugin,
    // other plugins...
  ],
};

Cross-Environment Testing:

The real power of this mock API system is environment transparency. When you combine a browser plugin (Vitest or Web Test Runner) with the test hooks, your test code remains identical whether running in Node.js or the browser.

// This EXACT same test code works in both Node.js and browser:
import { doublureHooks } from '@clevercloud/doublure/testing';

describe('API Tests', () => {
  const hooks = doublureHooks();
  let newScenario;

  before(async () => {
    newScenario = await hooks.before(); // Automatically detects environment
  });

  beforeEach(hooks.beforeEach);

  after(hooks.after);

  it('works everywhere', async () => {
    // Same code, different environments!
    const users = await newScenario()
      .when({ method: 'GET', path: '/api/users' })
      .respond({ status: 200, body: [{ id: 1, name: 'John' }] })
      .thenCall(() => fetch('/api/users').then((r) => r.json()));

    expect(users).toHaveLength(1);
  });
});

Behind the scenes:

  • Node.js: Starts real HTTP servers on free ports
  • Browser: Connects to proxy routes provided by the Vitest or Web Test Runner plugin
  • Your code: Stays exactly the same!

This eliminates the need for environment-specific test code and ensures your tests behave consistently across all environments.