Skip to content

Latest commit

 

History

History

zimic-interceptor

@zimic/interceptor

TypeScript-first HTTP intercepting and mocking

npm   •   Docs   •   Examples   •   Issues   •   Roadmap

CI  Coverage  License  Stars

NPM Downloads - @zimic/interceptor  Bundle size - @zimic/interceptor 



@zimic/interceptor provides a flexible and type-safe way to intercept and mock HTTP requests.

Note

🌱 This library is in beta.

Features

  • 🌐 HTTP interceptors: Intercept HTTP requests and return mock responses. Use local or remote interceptors to adapt your mocks to your development and testing workflow.
  • Fully typed mocks: Use your @zimic/http schema and create type-safe mocks for your HTTP requests.
  • 🔗 Network-level interceptor: @zimic/interceptor combines MSW and interceptor servers to handle real HTTP requests. From you application's point of view, the mocked responses are indistinguishable from the real ones.
  • 🔧 Flexibility: Mock external services and reliably test how your application behaves. Simulate success, loading, and error states with ease using standard web APIs.
  • 💡 Simplicity: @zimic/interceptor was designed to encourage clarity, simplicity, and robustness in your mocks.

Getting started

Check our getting started guide.

Installation

Manager Command
npm npm install @zimic/http @zimic/interceptor --save-dev
yarn yarn add @zimic/http @zimic/interceptor --dev
pnpm pnpm add @zimic/http @zimic/interceptor --dev

Basic usage

  1. Declare your HTTP schema using @zimic/http:

    import { type HttpSchema } from '@zimic/http';
    
    interface User {
      username: string;
    }
    
    interface RequestError {
      code: string;
      message: string;
    }
    
    type Schema = HttpSchema<{
      '/users': {
        POST: {
          request: { body: User };
          response: {
            201: { body: User };
            400: { body: RequestError };
            409: { body: RequestError };
          };
        };
    
        GET: {
          request: {
            headers: { authorization: string };
            searchParams: { query?: string; limit?: `${number}` };
          };
          response: {
            200: { body: User[] };
            400: { body: RequestError };
            401: { body: RequestError };
          };
        };
      };
    
      '/users/:userId': {
        PATCH: {
          request: {
            headers: { authorization: string };
            body: Partial<User>;
          };
          response: {
            204: {};
            400: { body: RequestError };
          };
        };
      };
    }>;

    You can also use zimic-http typegen to automatically generate types for your HTTP schema.

  2. Create your interceptor:

    import { httpInterceptor } from '@zimic/interceptor/http';
    
    const interceptor = httpInterceptor.create<Schema>({
      type: 'local',
      baseURL: 'http://localhost:3000',
      saveRequests: true, // Allow access to `handler.requests`
    });
  3. Manage your interceptor lifecycle:

    4.1. Start intercepting requests:

    beforeAll(async () => {
      await interceptor.start();
    });

    4.2. Clear your interceptors so that no tests affect each other:

    beforeEach(() => {
      interceptor.clear();
    });

    4.3. Check that all expected requests were made:

    afterEach(() => {
      interceptor.checkTimes();
    });

    4.4. Stop intercepting requests:

    afterAll(async () => {
      await interceptor.stop();
    });
  4. Enjoy mocking!

    5.1. Mock a response:

    test('example', async () => {
      const users: User[] = [{ username: 'me' }];
    
      const handler = interceptor
        .get('/users')
        .with({
          headers: { authorization: 'Bearer my-token' },
          searchParams: { query: 'u' },
        })
        .respond({
          status: 200,
          body: users,
        })
        .times(1);
    
      /// ...
    });

    Learn more about with(restrictions), respond(declaration), and times(times).

    5.2. After your application made requests, check if they are as you expect:

    test('example', async () => {
      // Your application makes requests...
    
      expect(handler.requests).toHaveLength(1);
    
      expect(handler.requests[0].headers.get('authorization')).toBe('Bearer my-token');
    
      expect(handler.requests[0].searchParams.size).toBe(1);
      expect(handler.requests[0].searchParams.get('username')).toBe('my');
    
      expect(handler.requests[0].body).toBe(null);
    });

Note

Step 5.2 manually verifies the requests made by the application. This is optional in this example because the with and times calls (step 5.1) already act as a declarative validation, expressing that exactly one request is expected with specific data. If fewer or more requests are received, the test will fail when interceptor.checkTimes() is called in the afterEach hook.

Documentation

Examples

Visit our examples to see how to use Zimic with popular frameworks, libraries, and use cases.

Changelog

The changelog is available on our GitHub Releases page.

Contributing

Interested in contributing to Zimic? Check out our contributing guide to get started!