or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

index.md
tile.json

tessl/npm-pollyjs--adapter-fetch

Fetch adapter for Polly.JS that enables seamless recording and replaying of HTTP interactions using the browser's native fetch API.

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
npmpkg:npm/@pollyjs/adapter-fetch@6.0.x

To install, run

npx @tessl/cli install tessl/npm-pollyjs--adapter-fetch@6.0.0

index.mddocs/

@pollyjs/adapter-fetch

The @pollyjs/adapter-fetch package provides a fetch adapter that enables seamless recording and replaying of HTTP interactions using the browser's native fetch API and Request/Response objects. It integrates with Polly.JS to intercept fetch calls, preserve request/response data, and replay interactions for deterministic testing.

Package Information

  • Package Name: @pollyjs/adapter-fetch
  • Package Type: npm
  • Language: JavaScript (with TypeScript definitions)
  • Installation: npm install @pollyjs/adapter-fetch -D

Core Imports

import FetchAdapter from '@pollyjs/adapter-fetch';

For CommonJS:

const FetchAdapter = require('@pollyjs/adapter-fetch');

Basic Usage

import { Polly } from '@pollyjs/core';
import FetchAdapter from '@pollyjs/adapter-fetch';

// Register the adapter with Polly
Polly.register(FetchAdapter);

// Create a Polly instance that uses the fetch adapter
const polly = new Polly('Recording Name', {
  adapters: ['fetch']
});

// The adapter will now intercept all fetch calls
const response = await fetch('/api/users');
const data = await response.json();

// Stop recording/replaying
await polly.stop();

Capabilities

FetchAdapter Class

The main adapter class that extends the base Polly.JS Adapter to provide fetch API interception and request/response handling.

/**
 * Fetch adapter that patches the global fetch function and Request constructor
 * to enable recording and replaying of HTTP interactions.
 */
export default class FetchAdapter extends Adapter {
  /**
   * Static identifier for the adapter
   * @returns {string} Always returns 'fetch'
   */
  static get id(): string;

  /**
   * Default configuration options for the adapter
   * @returns {object} Configuration object with context property
   */
  get defaultOptions(): {
    context?: any; // Global context object (default: global)
  };

  /**
   * Called when adapter connects to Polly instance.
   * Patches global fetch and Request constructor.
   */
  onConnect(): void;

  /**
   * Called when adapter disconnects from Polly instance.
   * Restores original global fetch and Request constructor.
   */
  onDisconnect(): void;

  /**
   * Called when a request is being processed.
   * Handles abort signal setup and event listeners.
   * @param {object} pollyRequest - The Polly request object
   */
  onRequest(pollyRequest: object): void;

  /**
   * Makes the actual fetch request and processes the response.
   * Handles binary data conversion and buffer compatibility.
   * @param {object} pollyRequest - The Polly request object  
   * @returns {Promise<object>} Response object with statusCode, headers, body, encoding
   */
  async onFetchResponse(pollyRequest: object): Promise<{
    statusCode: number;
    headers: object;
    body: string;
    encoding?: string;
  }>;

  /**
   * Called when responding to the original caller.
   * Handles response construction and error scenarios.
   * @param {object} pollyRequest - The Polly request object
   * @param {Error} error - Any error that occurred during processing
   */
  onRespond(pollyRequest: object, error?: Error): void;
}

Configuration Options

The adapter accepts configuration options through the Polly instance:

interface AdapterOptions {
  /**
   * Global context object containing fetch, Request, Response, Headers.
   * Defaults to the global object (window in browsers, global in Node.js).
   */
  context?: {
    fetch: Function;
    Request: new (url: string | Request, options?: RequestInit) => Request;
    Response: new (body?: any, options?: ResponseInit) => Response;
    Headers: new (headers?: HeadersInit) => Headers;
  };
}

Usage Example:

const polly = new Polly('Recording', {
  adapters: ['fetch'],
  adapterOptions: {
    fetch: {
      context: window // Explicitly specify the global context
    }
  }
});

Features

Request Interception

The adapter patches the global fetch function to intercept all fetch calls, supporting:

  • URL objects: Accepts both string URLs and URL instances
  • Request objects: Supports fetch calls with Request instances
  • All fetch options: Headers, method, body, credentials, etc.
  • Request cloning: Maintains fetch API clone semantics

Response Handling

Comprehensive response processing including:

  • Binary data support: Handles both text and binary response bodies
  • Encoding preservation: Uses base64 encoding for binary content
  • Header serialization: Converts Headers instances to plain objects
  • Status code mapping: Preserves HTTP status codes and status text
  • Empty response handling: Correctly handles 204 No Content responses

Abort Signal Support

Full AbortController/AbortSignal integration:

const controller = new AbortController();

// This request can be aborted
fetch('/api/data', { signal: controller.signal });

// Abort the request
controller.abort(); // Throws DOMException with name 'AbortError'

Cross-Environment Compatibility

The adapter works across different JavaScript environments:

  • Browser environments: Uses window.fetch and related globals
  • Node.js environments: Works with fetch polyfills or native Node.js fetch
  • Different contexts: Supports custom global contexts for testing scenarios

Error Handling

Robust error handling for various scenarios:

  • Missing globals: Validates fetch, Request, Response, Headers are available
  • Concurrent adapters: Prevents multiple fetch adapters from running simultaneously
  • Network errors: Properly propagates fetch network failures
  • Abort scenarios: Handles request cancellation with proper DOMException
  • Buffer compatibility: Manages ArrayBuffer differences across contexts

Internal Implementation Details

The adapter uses several internal symbols and patterns:

  • Symbol-based marking: Uses symbols to mark patched globals and prevent double-patching
  • Argument preservation: Stores original Request constructor arguments for proper cloning
  • Lazy execution: Operations are queued and executed when needed
  • Response URL fixing: Manually sets response.url since Response constructor doesn't allow it

Error Types

/**
 * Errors that may be thrown by the adapter
 */
interface AdapterErrors {
  /** Thrown when required globals (fetch, Request, etc.) are not found */
  AssertionError: Error;
  
  /** Thrown when request is aborted via AbortSignal */
  AbortError: DOMException;
  
  /** Network or other fetch-related errors */
  TypeError: Error;
}

Common Error Scenarios:

// Missing globals
// Error: "fetch global not found."

// Concurrent adapters  
// Error: "Running concurrent fetch adapters is unsupported, stop any running Polly instances."

// Aborted request
// DOMException: "The user aborted a request." (name: 'AbortError')

Advanced Usage Patterns

Custom Context

For testing or specialized environments:

const customGlobals = {
  fetch: mockFetch,
  Request: MockRequest,
  Response: MockResponse,
  Headers: MockHeaders
};

const polly = new Polly('Test', {
  adapters: ['fetch'],
  adapterOptions: {
    fetch: {
      context: customGlobals
    }
  }
});

Integration with Testing

Common pattern for test suites:

import { Polly } from '@pollyjs/core';
import FetchAdapter from '@pollyjs/adapter-fetch';

// Register once in test setup
Polly.register(FetchAdapter);

describe('API Tests', () => {
  let polly;

  beforeEach(() => {
    polly = new Polly('API Test', {
      adapters: ['fetch'],
      recordIfMissing: false // Use existing recordings
    });
  });

  afterEach(async () => {
    await polly.stop();
  });

  it('fetches user data', async () => {
    const response = await fetch('/api/users/1');
    const user = await response.json();
    
    expect(user.id).toBe(1);
  });
});