Using MSW in Storybook to Mock Sitecore XM Cloud GraphQL Queries
Simplifying Sitecore GraphQL testing in Storybook with MSW with Next,js
Start typing to search...
In Sitecore development, GraphQL plays a crucial role in fetching structured and hierarchical content. However, testing components that rely on live GraphQL endpoints can be cumbersome, especially when backend services are incomplete or unstable.
Fortunately, MSW (Mock Service Worker) and its Storybook addon offer a seamless way to mock GraphQL responses, allowing developers to simulate real-world scenarios directly in Storybook.
In this guide, we’ll show you how to mock Sitecore GraphQL queries in Storybook for a Next.js Sitecore XM Cloud project, ensuring your components are robust and reliable.
GraphQL allows you to fetch complex content efficiently, but testing against live data isn’t always practical. Mocking GraphQL queries helps you:
By mocking GraphQL queries, you gain full control over the data your components receive, making the development process smoother and more efficient.
Let’s begin by setting up a GraphQL API route in your Next.js project. This route will interact with the Sitecore GraphQL endpoint to fetch content.
Example API Route (pages/api/carouselCards.ts):
import { gql, GraphQLClient } from 'graphql-request';
import config from 'temp/config';
import type { NextApiRequest, NextApiResponse } from 'next';
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
try {
const { sitecorePath, sitecoreLanguage } = req.body;
const data = await fetchCarouselData(sitecorePath, sitecoreLanguage);
res.status(200).json(data);
} catch (error) {
console.error('Error fetching Carousel Data:', error);
res.status(500).json({ error: 'Internal Server Error' });
}
}
const fetchCarouselData = async (sitecorePath: string, sitecoreLanguage: string) => {
const graphQLClient = new GraphQLClient(config.graphQLEndpoint);
graphQLClient.setHeader('sc_apikey', config.sitecoreApiKey);
const query = gql`
query GetCarouselData($path: String!, $language: String!) {
item(path: $path, language: $language) {
id
name
fields {
title {
value
}
description {
value
}
}
}
}
`;
return graphQLClient.request(query, {
path: sitecorePath,
language: sitecoreLanguage,
});
};
To fetch data from the GraphQL API route, we’ll create a custom hook using SWR. This hook allows you to handle data fetching and caching effortlessly. For more on SWR, see this comprehensive guide.
Custom Hook (hooks/useCarouselData.ts):
import useSWR from 'swr';
type CarouselArgs = {
sitecorePath: string;
sitecoreLanguage: string;
};
const fetcher = async (url: string, body: CarouselArgs) => {
const response = await fetch(url, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(body),
});
if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`);
return response.json();
};
export const useCarouselData = (args: CarouselArgs) => {
const { data, error, isValidating } = useSWR(['/api/carouselCards', args], ([url, body]) =>
fetcher(url, body)
);
return {
carouselData: data,
isLoading: isValidating,
error,
};
};
Now that we have our API route and custom hook, it’s time to mock the GraphQL query in Storybook using MSW.
Here’s a simplified version of the mock data for the GetCarouselData query:
const mockGraphQLResponse = {
data: {
item: {
id: 'mock-id',
name: 'Mocked Carousel',
fields: {
title: { value: 'Mocked Title' },
description: { value: 'This is a mocked description.' },
},
},
},
};
You can mock the GraphQL query at the story level or apply it globally across all stories.
1. Per Story Mocking
Use this method for testing isolated components with specific scenarios.
import { graphql } from 'msw';
import { Meta } from '@storybook/react';
export default {
title: 'Components/Carousel',
component: CarouselComponent,
parameters: {
msw: {
handlers: [
graphql.query('GetCarouselData', (req, res, ctx) => {
return res(ctx.data(mockGraphQLResponse));
}),
],
},
},
} as Meta;
2. Global Mocking in preview.tsx
Apply global handlers to make mocks available across all stories.
import { graphql } from 'msw';
export const parameters = {
msw: {
handlers: [
graphql.query('GetCarouselData', (req, res, ctx) => {
return res(ctx.data(mockGraphQLResponse));
}),
],
},
};
Here’s how you can use the useCarouselData hook in your component:
const CarouselComponent = ({ sitecorePath, sitecoreLanguage }: { sitecorePath: string; sitecoreLanguage: string }) => {
const { carouselData, isLoading, error } = useCarouselData({ sitecorePath, sitecoreLanguage });
if (isLoading) return <div>Loading...</div>;
if (error) return <div>Error: {error.message}</div>;
return (
<div>
<h2>{carouselData.item.fields.title.value}</h2>
<p>{carouselData.item.fields.description.value}</p>
</div>
);
};
Mocking Sitecore GraphQL calls offers several benefits:
Mocking GraphQL queries in Storybook with MSW is a game-changer for Sitecore developers. It allows you to efficiently develop and test components by simulating various data scenarios, from successful responses to edge cases, all without relying on live backend services. This ensures your components are robust, reliable, and ready for production.
For those working with REST APIs alongside GraphQL, don’t miss our guide on mocking REST API calls in Storybook. Combined, these tools create a powerful development workflow, enabling you to deliver high-quality Sitecore applications with confidence and efficiency.