ContactSign inSign up
Contact

Mocking APIs and Network Requests

When testing components or pages that make network requests, it’s important to mock those requests to keep your tests isolated and predictable. Chromatic integrates with functional testing frameworks to enable visual testing of your UI. Therefore, APIs are mocked by your functional testing framework, not by Chromatic itself.

Storybook

Storybook offers several addons for mocking APIs (e.g. fetching data from a REST or GraphQL API). We recommend using the MSW addon.

Mocking network requests with MSW addon

Mock Service Worker (MSW) is an API mocking library that uses service workers to capture network requests and provide mocked data in response. The MSW addon integrates this functionality into Storybook. Here’s a basic example:

DocumentScreen.stories.tsx
// Replace your-framework with the name of your framework (e.g. nextjs, vue3-vite)
import type { Meta, StoryObj } from "@storybook/your-framework";

import { http, HttpResponse, delay } from "msw";

import { DocumentScreen } from "./DocumentScreen";

const meta = {
  component: DocumentScreen,
} satisfies Meta<typeof DocumentScreen>;

export default meta;
type Story = StoryObj<typeof meta>;

// 👇 The mocked data that will be used in the story
const mockDocuments = [
  {
    id: 1,
    userID: 1,
    title: "Something",
    content:
      "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
    status: "approved",
  },
  {
    id: 2,
    userID: 1,
    title: "Something else",
    content:
      "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
    status: "pending",
  },
  {
    id: 3,
    userID: 2,
    title: "Another thing",
    content:
      "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
    status: "rejected",
  },
];

export const MockedSuccess: Story = {
  parameters: {
    msw: {
      handlers: [
        http.get("/api/documents", () => {
          return HttpResponse.json(mockDocuments);
        }),
      ],
    },
  },
};

export const MockedError: Story = {
  parameters: {
    msw: {
      handlers: [
        http.get("/api/documents", async () => {
          await delay(800);
          return new HttpResponse(null, {
            status: 403,
          });
        }),
      ],
    },
  },
};

For more details, check out the Mocking network requests page in the Storybook documentation.

Can I use MSW to mock browser APIs like navigator.share?

Yes, but MSW is built to intercept and mock network requests (like fetch or XHR), not to directly mock browser APIs like the navigator object.

You can use Object.defineProperty for direct browser APIs mocking. It modifies objects like window or navigator, and lets you define them in your code. Here’s an example of how to mock the navigator.share:

Object.defineProperty(navigator, "share", {
  configurable: true, // Allows the property to be redefined later
  value: async (data) => {
    console.log("Mocked share:", data);
    return Promise.resolve(); // Simulate a successful share
  },
});

Learn more about the Object.defineProperty in MDN documentation.

Module mocking

If you rely on third-party libraries that make network requests, you can mock those modules in your stories. This is useful when you want to avoid inconsistencies in your tests due to external dependencies. Refer to the video below and the module mocking documentation for more information on how to do this.

Module mocking in Storybook

Playwright

Playwright allows you to mock network requests, including XHRs and fetch requests. You can also use HAR files to mock multiple network requests made by the page. Check out the Playwright documentation for more details.

tests/DocumentScreen.spec.js|ts
test("mocks documents api", async ({ page }) => {
  // Mock the api call before navigating
  await page.route("*/**/api/documents", async (route) => {
    const json = [
      {
        id: 1,
        userID: 1,
        title: "Something",
        content:
          "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
        status: "approved",
      },
      {
        id: 2,
        userID: 1,
        title: "Something else",
        content:
          "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
        status: "pending",
      },
      {
        id: 3,
        userID: 2,
        title: "Another thing",
        content:
          "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
        status: "rejected",
      },
    ];
    await route.fulfill({ json });
  });
  // Go to the page
  await page.goto("https://myapp.com/documents");

  // Assert that the "Something else" is visible
  await expect(page.getByText("Something else")).toBeVisible();
});

Cypress

Cypress allows you to stub API responses with the cy.intercept() method, letting you define the body, HTTP status code, headers, and other response characteristics. You can also use cy.fixture() to load mock data from a file. For more details, check out the Cypress documentation.

cypress/e2e/DocumentScreen.cy.js|ts
cy.intercept(
  {
    method: "GET", // Route all GET requests
    url: "/api/documents",
  },
  [
    {
      id: 1,
      userID: 1,
      title: "Something",
      content:
        "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
      status: "approved",
    },
    {
      id: 2,
      userID: 1,
      title: "Something else",
      content:
        "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
      status: "pending",
    },
    {
      id: 3,
      userID: 2,
      title: "Another thing",
      content:
        "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
      status: "rejected",
    },
  ], // and force the response to be mock data
).as("getDocuments"); // and assign an alias