mock-service-worker

Mocking

We simulate/imitate components that we don't want to or can't use directly for any reason using mocks

API Mocking with Mock Service Worker

A typical example is APIs. Thanks to mocking, we can interact with an API that doesn't exist yet (for example, if the backend team

is working on it in parallel) and we always know exactly what data will be returned.

Mock Service Worker is a very powerful and popular tool for this.

MSW Setup

We install MSW with npm install --save-dev msw

Creating Handler Ts file

We create the src/mock/handlers.ts file. Individual routes are mocked here.

This file could look like this, for example:

import { http, HttpResponse } from 'msw'
import { birds } from '../data/birds'
export const handlers = [
  // here we are capturing all GET requests to https://tolleapi.com/hello
  http.get('https://tolleapi.com/hello', () => {
    // and we respond to them with the object {text: "Hello World!"}
    return HttpResponse.json({text: "Hello World!"})
  }),
]

This code defines a handler for mocking an API using Mock Service Worker (MSW).

  • First, the necessary functions are imported from MSW: http and HttpResponse.
  • Then, an array called handlers is created. This array contains the API routes to be mocked.
  • In the example, GET requests to https://tolleapi.com/hello are intercepted.
  • In response to this request, a JSON response in the form of {text: "Hello World!"} is returned.

This handler is useful when developing without a real API. For example, such mocks can be used to continue frontend development while the backend is not yet ready. It can also be used to provide consistent and predictable API responses in tests.

Creating the Browser File

Then we create another file called src/mock/browser.ts

Here our routes are collected and packaged specifically for use in the browser

import { setupWorker } from 'msw/browser'
import { handlers } from './handlers'
export const worker = setupWorker(...handlers)

This code forms part of the Mock Service Worker (MSW) setup.

  • import { setupWorker } from 'msw/browser': Imports the setupWorker function from the browser version of MSW.
  • import { handlers } from './handlers': Imports the API mock handlers we defined earlier.
  • export const worker = setupWorker(...handlers): Calls the setupWorker function to create an MSW worker and configures it with handlers. This worker will run in the browser and intercept specified API requests to produce mock responses.

This code provides the basic configuration needed for MSW to run in the browser environment.

Creating a service worker

Now we create a service worker with npx msw init ./public --save.

This will later intercept and rewrite incoming requests.

We can now integrate MSW.

Reconfiguring the App for mock data

We do this in App.tsx, even before starting React:

import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import App from "./App.tsx";
import "./index.css";

async function enableMocking() {
  if (process.env.NODE_ENV !== "development") {
    return;
  }
  const { worker } = await import("./mocks/browser");
  // worker.start() returns a Promise that resolves when the 
  // Service Worker is ready and starts intercepting requests.
  return worker.start();
}

enableMocking().then(() =>
  createRoot(document.getElementById("root")!).render(
    <StrictMode>
      <App />
    </StrictMode>
  )
);

1. Import Statements

import { StrictMode } from "react";

import { createRoot } from "react-dom/client";

import App from "./App.tsx";

import "./index.css";

These statements import the core components and styles of the React application. StrictMode is used to detect potential issues during development. createRoot is a new rendering method introduced with React 18.

2. enableMocking Function

async function enableMocking() {
  if (process.env.NODE_ENV !== "development") {
    return;
  }
  const { worker } = await import("./mocks/browser");
  return worker.start();
}

2. enableMocking Function

This function does the following:

  • Performs an environment check. It only runs in the development environment.
  • Dynamically imports the MSW worker. This is important to avoid including unnecessary code in the developer build.
  • worker.start() call initiates the Service Worker and makes it ready to intercept API requests.

process.env.NODE_ENV Explanation

process.env.NODE_ENV is a commonly used environment variable in Node.js applications. This variable indicates in which environment the application is running. It typically takes three main values:

  • development: Represents the development environment. In this mode, debugging features are usually enabled.
  • production: Represents the live environment. Performance optimizations are enabled and debugging features are disabled.
  • test: Represents the testing environment. Used when running automated tests.

In our code, the if (process.env.NODE_ENV !== "development") check ensures that the application only uses the mock service in the development environment. This guarantees connection to the real API in the production environment.

3. Initializing the React Application

enableMocking().then(() =>
  createRoot(document.getElementById("root")!).render(
    <StrictMode>
      <App />
    </StrictMode>
  )
);

This section:

  • First calls the enableMocking() function and waits for it to complete.
  • Creates a React root in the DOM element with the id 'root' using createRoot.
  • Renders the App component within StrictMode. StrictMode performs some checks and gives warnings to highlight potential issues.

This structure ensures that MSW is ready before the React application starts. Thus, API calls made when the application starts can be immediately intercepted and mocked. This allows frontend development without a real backend and enables controlled simulation of API responses.

Result

Now everything should be ready and a fetch request to the relevant route should return "mocked" data to us

Github Repo:

https://github.com/snahmd/birdsift

Leave a reply