Fetch adapter for Polly.JS that enables seamless recording and replaying of HTTP interactions using the browser's native fetch API.
npx @tessl/cli install tessl/npm-pollyjs--adapter-fetch@6.0.0The @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.
npm install @pollyjs/adapter-fetch -Dimport FetchAdapter from '@pollyjs/adapter-fetch';For CommonJS:
const FetchAdapter = require('@pollyjs/adapter-fetch');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();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;
}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
}
}
});The adapter patches the global fetch function to intercept all fetch calls, supporting:
Comprehensive response processing including:
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'The adapter works across different JavaScript environments:
Robust error handling for various scenarios:
The adapter uses several internal symbols and patterns:
/**
* 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')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
}
}
});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);
});
});