4.6 KiB
Storybook Contract (Veza Web)
This document defines the development contract for Storybook in apps/web: how to write and maintain stories without breaking the deterministic, zero-leak setup.
1. Use the global decorator only
All stories are wrapped by StorybookDecorator (see .storybook/decorators.tsx). It provides:
I18nextProvider(i18n)ThemeProvider(light/dark via Storybook backgrounds)QueryClientProvider(React Query,retry: false,staleTime: Infinity)ToastProviderAudioProviderAuthProvider(mock logged-in user by default)MemoryRouter(initial route configurable via parameters)
You must not:
- Import or wrap stories with these providers yourself.
- Import app-level providers from
src/(e.g.AuthProvider,QueryClientProvider) inside a story file.
Why: A single decorator avoids duplicate providers, inconsistent configs, and hooks running outside their context (useAuth, useNavigate, useQueryClient, useToast, etc.).
Route-dependent stories
If the component under test uses useParams(), useSearchParams(), or a specific path, set the route in the story’s parameters:
export const MyStory: StoryObj<typeof MyPage> = {
parameters: {
router: {
initialEntries: ['/tracks/123'],
},
},
};
Do not add a local MemoryRouter unless you need a different base path for that story only; the global decorator already provides MemoryRouter and will use parameters.router.initialEntries when present.
2. Mock all API calls with MSW
Storybook runs with MSW (Mock Service Worker) and is configured with onUnhandledRequest: 'error'. Any request that is not handled by a mock will cause an error in the console and can fail the story/audit.
You must:
- Ensure every API call used by your story is covered by a handler in
src/mocks/handlers.ts(or by story-levelparameters.msw.handlersoverrides). - Use relative API base (e.g.
VITE_API_URL=/api/v1in Storybook scripts) so requests are same-origin and intercepted by MSW.
Adding a mock for a new feature:
- Open
apps/web/src/mocks/handlers.ts. - Add an
http.get()orhttp.post()(etc.) handler for the endpoint (e.g.*/api/v1/your/resource). - Return a
HttpResponse.json(...)with a shape that matches what your app expects. - If a story needs a different response (e.g. 404, empty list), override in that story:
parameters: {
msw: {
handlers: [
http.get('*/api/v1/your/resource', () => HttpResponse.json({ data: [] })),
],
},
},
You must not:
- Rely on a real backend when running or building Storybook.
- Add stories that trigger unhandled network requests; they will fail under the current strict MSW setup.
3. Hierarchy and tags
Stories are grouped in the sidebar as follows:
| Segment | Usage |
|---|---|
| App/Pages | Full-page components (e.g. Dashboard, Login, TrackDetail). |
| App/Layouts | Global layout components (Header, Sidebar, DashboardLayout). |
| Components/UI | Atomic UI (Button, Alert, Input). |
| Components/Features | Feature-specific and complex components (Playlists, Chat, Studio, etc.). |
| Docs/Failures | Error states and error boundaries (ErrorBoundary, NotFoundPage, ServerErrorPage). |
Set the meta title in your .stories.tsx accordingly (e.g. title: 'App/Pages/Dashboard/DashboardPage', title: 'Components/UI/Button').
Autodocs are enabled globally; each component gets a generated docs page.
4. Verification
-
Audit: From
apps/web, build Storybook, serve the static build on port 6007, then run:npm run build-storybook npx serve -s storybook-static -p 6007 & node scripts/audit-storybook.jsThe audit must report 0 application errors (console errors, page errors, unhandled network failures). MSW strict mode ensures any unhandled request is treated as an error.
-
Local run: Use
npm run storybook(port 6006). Ensure no console errors when opening the stories you changed.
5. Summary
| Rule | Action |
|---|---|
| Providers | Use only StorybookDecorator; do not import app providers in stories. |
| Routes | Use parameters.router.initialEntries for route-dependent stories. |
| API | Mock every request in handlers.ts or per-story parameters.msw.handlers. |
| Hierarchy | Use App/Pages, App/Layouts, Components/UI, Components/Features, Docs/Failures. |
| Strict MSW | onUnhandledRequest: 'error' is on; add mocks for any new API used by a story. |
This contract keeps Storybook deterministic, free of network leaks, and safe for future changes.