docs(storybook): document MSW/same-origin contract in preview

Storybook must be run via npm run storybook so VITE_API_URL stays
relative and VITE_STORYBOOK is set; avoids accidental real API calls.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
senke 2026-02-05 12:28:04 +01:00
parent c63d792bf0
commit 8b43574f15

View file

@ -1,3 +1,8 @@
/**
* Storybook preview: MSW intercepts all API calls when run via `npm run storybook` / `npm run build-storybook`.
* Those scripts set VITE_API_URL=/api/v1 (same-origin) and VITE_STORYBOOK=true (logger does not send to backend).
* Do not run Storybook with an absolute API URL or MSW will not intercept.
*/
import type { Preview } from '@storybook/react';
import { initialize, mswLoader } from 'msw-storybook-addon';
import { handlers } from '../src/mocks/handlers';
@ -7,22 +12,7 @@ import '../src/styles/global-effects.css';
import '../src/styles/header.css';
import '../src/lib/i18n'; // Initialize i18n
import React from 'react';
import { ThemeProvider } from '../src/components/theme/ThemeProvider';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { MemoryRouter } from 'react-router-dom';
import { ToastProvider } from '../src/components/feedback/ToastProvider';
import { AudioProvider } from '../src/context/AudioContext';
import { AuthProvider } from '../src/providers/AuthProvider';
// Create a client for stories
const queryClient = new QueryClient({
defaultOptions: {
queries: {
retry: false,
staleTime: Infinity,
},
},
});
import { AppProvidersForStorybook } from './AppProvidersForStorybook';
// Custom viewports for responsive testing
const customViewports = {
@ -51,7 +41,7 @@ const customViewports = {
// Initialize MSW
initialize({
onUnhandledRequest: 'bypass',
onUnhandledRequest: 'warn',
serviceWorker: {
url: './mockServiceWorker.js',
},
@ -88,29 +78,13 @@ const preview: Preview = {
toc: true, // Enable table of contents in docs
},
},
decorators: [
// Global providers decorator
(Story, context) => {
// Apply dark class based on background selection
const isDark = context.globals.backgrounds?.value !== '#ffffff';
return (
<ThemeProvider defaultTheme={isDark ? 'dark' : 'light'}>
<div className={isDark ? 'dark' : ''}>
<QueryClientProvider client={queryClient}>
<ToastProvider>
<AudioProvider>
<AuthProvider>
<MemoryRouter>
<Story />
</MemoryRouter>
</AuthProvider>
</AudioProvider>
</ToastProvider>
</QueryClientProvider>
</div>
</ThemeProvider>
<AppProvidersForStorybook isDark={isDark}>
<Story />
</AppProvidersForStorybook>
);
},
],