Mock GraphQL and REST in Storybook and Jest with MSW

MSW

MSW mocks for GraphQL queries and mutations in Storybook
Mocked requests show up in browser’s dev tools

Install

npm install msw --save-dev
npx msw init <PUBLIC_DIR> --save
// package.json"msw": {
"workerDirectory": "public"
}

Integration with Storybook

// package.json"scripts: {
"storybook": "start-storybook -s ./public",
"build": "build-storybook -s ./public"
}
// msw-utils.jsimport { setupWorker } from "msw";
import { setupServer } from "msw/node";
function setup() {
let worker;
let server;
if (typeof global.process === "undefined") {
// Setup mock service worker for browser environment
worker = setupWorker();
} else {
// Setup mock service server for node environment
server = setupServer();
}
return { worker, server };
}
export const { worker, server } = setup();
export const mock = (worker || server).use;
export { graphql, rest } from "msw";
// msw-utils.tsimport { SetupWorkerApi, setupWorker } from "msw";
import { SetupServerApi, setupServer } from "msw/node";
function setup() {
let worker: SetupWorkerApi | undefined;
let server: SetupServerApi | undefined;
if (typeof global.process === "undefined") {
// Setup mock service worker for browser environment
worker = setupWorker();
} else {
// Setup mock service server for node environment
server = setupServer();
}
return { worker, server };
}
export const { worker, server } = setup();
export const mock = (worker ?? server)!.use;
export { graphql, rest } from "msw";
// .storybook/preview.jsimport { worker } from "../msw-utils";const MSW_FILE = "mockServiceWorker.js";// In browser, start Mock Service Worker to mock HTTP responses
worker.start({
serviceWorker: { url: `./${MSW_FILE}` },
// Return the first registered service worker found with the name
// of `mockServiceWorker`, disregarding all other parts of the URL
findWorker: scriptURL => scriptURL.includes(MSW_FILE),
onUnhandledRequest: "bypass"
});
  • serviceWorker — This is to tell MSW where to find the generated script “mockServiceWorker.js”.
  • findWorker — This is to use the first found worker with the same file path.
  • onUnhandledRequest — This configuration disables warnings in browser console for un-mocked requests.
your-project
|
+ .storybook
| |
| + preview.js
|
+ public
| |
| + mockServiceWorker.js // Generated script
|
+ src
|
+ msw-utils.js // or msw-utils.ts
|
+ package.json

Mock data in Storybook

// ProfileCard.stories.jsx...
import { graphql, mock } from "../../../msw-utils";
...const PERSON_MOCK = {
id: "478620",
name: { first: "David", last: "Cai" },
gender: "male",
age: 42
};
export const Profile = () => <ProfileCard />;
// ProfileCard.stories.jsx...export const Profile = () => <ProfileCard />;
Profile.decorators = [
story => {
mock(
graphql.query(
"Persons",
(_req, res, ctx) => {
return res(ctx.data({
household: { persons: [PERSON_MOCK] } }));
}
)
);

return story();
}
];
// Query name in a graphql documentexport const QUERY_PERSONS = gql`
query Persons {
household {
persons {
id
name {
first
last
}
gender
age
}
}
}
`;
// ProfileCard.stories.jsx...Profile.decorators = [
story => {
mock(
graphql.query("Persons", ...),
graphql.mutation(
"UpdatePerson",
(req, res, ctx) => {
const { updatedPerson } = req.variables;
return res(ctx.data({
household: { persons: [updatedPerson] }
}));
}
)
);

return story();
}
];
mock(
rest.get("/persons/:personId", (req, res, ctx) => {
const { personId } = req.params;
return res(ctx.json({ id: personId, firstName: "David" }));
})
)

Mock loading state

res(
ctx.delay(2000), // Delay response for 2 seconds
ctx.data({ your: data })
);
ctx.delay("infinite");
ctx.delay(); // Random server response time

Mock error state

res(
ctx.errors([
{ message: "Failed to find person" }
])
);
res(ctx.status(404, "Resource not found"));

Integration with Jest

npm install @storybook/testing-react --save-dev
// ProfileCard.test.jsximport { composeStories } from "@storybook/testing-react";
import * as stories from "./ProfileCard.stories";
const { Self } = composeStories(stories);describe("ProfileCard", () => {
it("should render a profile card", () => {
render(<Self />);
// ...
});
});
// jest.setup.jsimport { server } from "./msw-utils";// Setup Mock Service Server for unit test
beforeAll(() => server.listen());
afterEach(() => server.resetHandlers());
afterAll(() => server.close());
// package.json"jest": {
// ...
"setupFilesAfterEnv": ["<rootDir>/jest.setup.js"]
}

Recap

  • Install msw and @storybook/testing-react (One-time setup)
  • Generate mockServiceWorker.js in a public directory (One-time setup)
  • Change storybook commands to include the generated mockServiceWorker.js (One-time setup)
  • Create msw-utils (One-time setup)
  • Start MSW in .storybook/preview.js (One-time setup)
  • Start MSW in Jest setup file (One-time setup)
  • Mock data in Storybook
your-project
|
+ .storybook
| |
| + preview.js // Storybook preview setup
|
+ public
| |
| + mockServiceWorker.js // Generated script
|
+ src
| |
| + ProfileCard.jsx // Component
| |
| + ProfileCard.stories.jsx // Storybook stories
| |
| + ProfileCard.test.jsx. // Jest test
|
+ jest.setup.js // Jest setup
|
+ msw-utils.js // MSW utils
|
+ package.json

--

--

--

Gamer, hiker, reader, and programmer

Love podcasts or audiobooks? Learn on the go with our new app.

Recommended from Medium

How to Build your own Js Web Tag

a cow is tagged like a website is tagged — dont be a fool and tag with someone elses cows

Fluid Transitions with React Navigation

Log guide for Harmony OS Apps on DevEco Studio IDE part 1

Use Jest to test Redux Async Action Creator with Axios in a Create-React-App app

Create-React-App Command Line Argument

Legacy (Windows) OSCP TJ Null List W/O Metasploit

useReducer Explained

A Few Words on Node.js & An Example of How to Use NPM’s ‘readline-sync’ Package

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
David Cai

David Cai

Gamer, hiker, reader, and programmer

More from Medium

The Best Collected Details on the GraphQL Specification — Overview & Language

Adaptive Parallax with react-spring

How we implemented SVG Arrows in React: The Curvature (2/3)