Mocking API Calls in Storybook Using MSW On Your Sitecore XM Cloud Project
Simplify API testing in Storybook for Sitecore XM Cloud with MSW
Start typing to search...
As a Sitecore developer, you often work with dynamic content served through REST APIs to fetch additional data or services. Testing these integrations in isolation can be challenging, especially when building or debugging components in Storybook. Thankfully, MSW (Mock Service Worker) and its Storybook addon make it easy to simulate API responses and streamline your development workflow.
Mocking REST API calls brings several critical benefits to Sitecore development:
By integrating mocking into your Storybook setup, you can create a faster, more efficient, and reliable development workflow for your Sitecore projects.
To get started, install the required packages:
npm install msw msw-storybook-addon
Create or update your preview.tsx file in the .storybook folder to initialize MSW and configure it for Storybook:
import { initialize, mswDecorator } from 'msw-storybook-addon';
import '../src/styles/globals.css';
// Initialize MSW
initialize()
const preview = {
parameters: {
// your other code...
},
// Provide the MSW addon loader globally
loaders: [mswLoader],
}
export default preview;
For MSW to intercept requests in your Storybook environment, you'll need to generate a service worker and place it in your public folder:
npx msw init public/
This command will generate the necessary service worker files (mockServiceWorker.js). If your project doesn’t use a public folder (e.g., for some custom setups), refer to the MSW official guide for framework-specific paths.
Notes:
public folder is the default static file directory in Next.js, making it compatible with MSW.public directory for the service worker to function correctly.In Sitecore development, it's common to interact with external APIs to fetch additional data. Let’s assume you have the following Next.js API route for fetching account details:
Example API Route (pages/api/accountDetails.ts)
import type { NextApiRequest, NextApiResponse } from 'next';
import axios from 'axios';
type AccountDetailsResponse = {
[key: string]: unknown;
};
type Data = {
message?: string;
data?: AccountDetailsResponse;
error?: string;
};
export default async function handler(req: NextApiRequest, res: NextApiResponse<Data>) {
try {
if (req.method !== 'POST') {
return res.status(405).json({ error: 'Method Not Allowed' });
}
const body = {
messageHeader: { id: '3fa85f64-5717-4562-b3fc-2c963f66afa6' },
selectedAccount: {
id: 'db82eb2f-8977-47ad-93d1-121e0b9d7756',
name: req.body.name,
email: req.body.email,
accountType: '01',
},
};
const apiKey = process.env.SITECORE_API_KEY;
if (!apiKey) throw new Error('API key is missing');
const response = await axios.post<AccountDetailsResponse>(
'https://endpoint.com/api/account-info',
body,
{
headers: {
'Content-Type': 'application/json',
'api-key': apiKey,
},
}
);
res.status(200).json({ data: response.data });
} catch (error) {
console.error('API handler error:', error);
res.status(500).json({ error: (error as Error).message || 'Internal Server Error' });
}
}
To fetch data from the above API route, use SWR (Stale-While-Revalidate). This hook simplifies data fetching and caching in your Next.js applications.
For more on SWR, see this comprehensive guide.
import useSWR from 'swr';
type AccountArgs = {
name: string;
email: string;
};
const fetcher = async (url: string, arg: AccountArgs) => {
const response = await fetch(url, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(arg),
});
if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`);
return response.json();
};
export const useAccountDetails = (selectedAccount: AccountArgs) => {
const { data, error, isValidating } = useSWR(['/api/accountDetails', selectedAccount], ([url, args]) => fetcher(url, args), {
revalidateOnFocus: false,
});
return {
accountDetails: data?.data,
isAccountDetailsLoading: isValidating,
accountDetailsError: error,
};
};
To simulate the API response in Storybook, we’ll use MSW. first define Mock Data
const accountInfoTestData = {
data: {
selectedAccount: {
id: 'db82eb2f-8977-47ad-93d1-121e0b9d7756',
name: 'Mocked User',
email: '[email protected]',
accountType: '01',
},
},
};
You can apply mocks either per story or globally:
1. Per Story Mocking
Use this method for testing isolated components with specific scenarios.
import { http } from 'msw';
import { Meta } from '@storybook/react';
export default {
title: 'Components/AccountComponent',
component: AccountComponent,
parameters: {
msw: {
handlers: [
http.post('/api/accountDetails', (req, res, ctx) => {
return res(ctx.json(accountInfoTestData));
}),
],
},
},
} as Meta;
2. Global Mocking in preview.tsx
Apply global handlers to make mocks available across all stories.
import { http } from 'msw';
export const parameters = {
msw: {
handlers: [
http.post('/api/accountDetails', (req, res, ctx) => {
return res(ctx.json(accountInfoTestData));
}),
// Or just sample return
// http.post('/api/accountDetails', () => {
// return HttpResponse.json(accountInfoTestData);
// }),
],
},
};
Here’s how you can utilize the useAccountDetails hook in your component:
const AccountComponent = ({ selectedAccount }: { selectedAccount: AccountArgs }) => {
const { accountDetails, isAccountDetailsLoading, accountDetailsError } = useAccountDetails(selectedAccount);
if (isAccountDetailsLoading) return <LoadingSpinner message="Loading account details..." />;
if (accountDetailsError) return <div>Error: {accountDetailsError.message}</div>;
return (
<div>
<h2>Account Name: {accountDetails?.selectedAccount?.name}</h2>
<p>Email: {accountDetails?.selectedAccount?.email}</p>
</div>
);
};
Mocking REST API calls in Storybook using MSW provides Sitecore developers with a powerful toolset for isolating and testing components. By simulating real-world scenarios, you can develop and debug your Next.js components without relying on live backend services. This not only speeds up the development process but also ensures your components behave predictably under various conditions, such as successful API responses, errors, or edge cases.
Incorporating mocking into your Storybook workflow offers the following key benefits:
By following the steps outlined in this blog, you’ll have a solid foundation for mocking REST APIs in your Sitecore projects, making your development workflow smoother and more efficient.