Skip to content
github-actions[bot] edited this page Sep 27, 2024 · 6 revisions

Zimic

TypeScript-first HTTP request mocking

npm   •   Docs   •   Examples   •   Issues   •   Roadmap

CI  Coverage  License NPM Downloads  Stars 


Contents


Zimic is a lightweight, thoroughly tested, TypeScript-first HTTP request mocking library, inspired by Zod's type inference and using MSW under the hood.

Features

Zimic provides a flexible and type-safe way to mock HTTP requests.

  • Statically-typed mocks: Declare the schema of your HTTP endpoints and create fully typed mocks. If you have an OpenAPI v3 schema, use zimic typegen to automatically generate types and keep your mocks in sync with your API.
  • 🔗 Network-level intercepts: Internally, Zimic combines MSW and interceptor servers to act on 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 was designed to encourage clarity, simplicity, and robustness in your mocks. Check our getting started guide and starting mocking!
import { type HttpSchema } from 'zimic/http';
import { httpInterceptor } from 'zimic/interceptor/http';

// 1. Declare your types
interface User {
  username: string;
}

interface RequestError {
  message: string;
}

// 2. Declare your HTTP schema
// https://bit.ly/zimic-interceptor-http-schemas
type MySchema = HttpSchema<{
  '/users': {
    POST: {
      request: { body: User };
      response: {
        201: { body: User }; // User created
        400: { body: RequestError }; // Bad request
        409: { body: RequestError }; // Conflict
      };
    };
    GET: {
      request: {
        headers: { authorization?: string };
        searchParams: { username?: string; limit?: `${number}` };
      };
      response: {
        200: { body: User[] }; // Users listed
        400: { body: RequestError }; // Bad request
        401: { body: RequestError }; // Unauthorized
      };
    };
  };
}>;

// 3. Create your interceptor
// https://bit.ly/zimic-interceptor-http#httpinterceptorcreateoptions
const myInterceptor = httpInterceptor.create<MySchema>({
  type: 'local',
  baseURL: 'http://localhost:3000',
  saveRequests: true, // Allow access to `handler.requests()`
});

// 4. Manage your interceptor lifecycle
// https://bit.ly/zimic-guides-testing
beforeAll(async () => {
  // 4.1. Start intercepting requests
  // https://bit.ly/zimic-interceptor-http#http-interceptorstart
  await myInterceptor.start();
});

afterEach(() => {
  // 4.2. Clear interceptors so that no tests affect each other
  // https://bit.ly/zimic-interceptor-http#http-interceptorclear
  myInterceptor.clear();
});

afterAll(async () => {
  // 4.3. Stop intercepting requests
  // https://bit.ly/zimic-interceptor-http#http-interceptorstop
  await myInterceptor.stop();
});

// Enjoy mocking!
test('should list users', async () => {
  const users: User[] = [{ username: 'diego-aquino' }];
  const token = 'my-token';

  // 7. Declare your mocks
  // https://bit.ly/zimic-interceptor-http#http-interceptormethodpath
  const myHandler = myInterceptor
    .get('/users')
    // 7.1. Use restrictions to make declarative assertions and narrow down your mocks
    // https://bit.ly/zimic-interceptor-http#http-handlerwithrestriction
    .with({
      headers: { authorization: `Bearer ${token}` },
    })
    .with({
      searchParams: { username: 'diego' },
      exact: true,
    })
    // 7.2. Respond with your mock data
    // https://bit.ly/zimic-interceptor-http#http-handlerresponddeclaration
    .respond({ status: 200, body: users });

  // 8. Run your application and make requests
  // ...

  // 9. Check the requests you expect
  // https://bit.ly/zimic-interceptor-http#http-handlerrequests
  const requests = myHandler.requests();
  expect(requests).toHaveLength(1);

  // The following expects are automatically checked by the restrictions
  // we declared above. Requests not matching them will cause warnings and not
  // be intercepted.

  // If you are not using restrictions, asserting the requests manually is
  // a good practice:
  expect(requests[0].headers.get('authorization')).toBe(`Bearer ${token}`);

  expect(requests[0].searchParams.size).toBe(1);
  expect(requests[0].searchParams.get('username')).toBe('diego');

  expect(requests[0].body).toBe(null);
});

What is Zimic for?

Zimic is a development and testing tool that helps you mock HTTP responses in a type-safe way. Some of our best use cases:

  • Testing: If your application relies on external services over HTTP, you can mock them with Zimic to make your tests simpler, faster and more predictable. Each interceptor references a schema declaration to provide type inference and validation for your mocks. After breaking changes, adapting the interceptor schema will help you to quickly identify all of the affected mocks and keep your test scenarios consistent with the real-life API.
  • Development: If you are developing a feature that depends on an external service that is unreliable, unavailable, or costly, you can use Zimic to mock it and continue your development without interruptions. Zimic can also be used to create mock servers, using remote interceptors and interceptor servers, which can be accessible by multiple applications in your development workflow and even be containerized.

How does Zimic work?

Zimic allows you to intercept HTTP requests and return mock responses. In local HTTP interceptors, Zimic uses MSW to intercept requests in the same process as your application. In remote HTTP interceptors, Zimic uses a dedicated local interceptor server to handle requests. This opens up more possibilities for mocking, such as handling requests from multiple applications. Both of those strategies act on real HTTP requests after they leave your application, so no parts of your application code are skipped and you can get more confidence in your tests.

Documentation

Tip

You can search these docs by clicking on 🔍 Search on the sidebar. Then, type your query in the search bar at the top of the page:

Using the GitHub search bar

Note

Zimic has gone a long way in v0, but we're not yet v1!

Reviews and improvements to the public API are possible, so breaking changes may exceptionally land without a major release during v0. Despite of that, we do not expect big mental model shifts. Usually, migrating to a new Zimic release requires minimal to no refactoring. During v0, we will follow these guidelines:

  • Breaking changes, if any, will be delivered in the next minor version.
  • Breaking changes, if any, will be documented in the version release, along with a migration guide detailing the introduced changes and suggesting steps to migrate.

From v0.8 onwards, we expect Zimic's public API to become more stable. If you'd like to share any feedback, please feel free to open an issue or create a discussion!

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.