Storybook Testing
Storybook serves as the component documentation and local interaction layer. Stories span all three UI packages (shared, admin, client) and are aggregated into a single Storybook instance hosted from packages/shared.
The public component library deploys as a standalone Vercel-hosted Storybook site at https://design.greengoods.app/. The deployed build uses the public browser dialect as its Storybook chrome and exposes the design-tool import bundle from the same root URL.
How To Approach Tests
Storybook stories serve two practical purposes: living component documentation and a fast local surface for exploring component states. The philosophy is that every shared foundation should have a story, and stories should demonstrate the component's range of states — default, edge cases, responsive behavior, and error states.
Storybook is now a light regression gate. The repo CI verifies the required Storybook contract for shared foundations plus curated admin surfaces, runs a small browser-mode Storybook test lane for storybook-ci stories, then builds the unified Storybook to catch compile-time issues. Keep the CI tag curated; do not tag every story by default.
Architecture
The Storybook config lives at packages/shared/.storybook/main.ts and pulls stories from three glob patterns:
stories: [
"../src/**/*.stories.@(ts|tsx)", // shared
"../../../packages/admin/src/**/*.stories.@(ts|tsx)", // admin
"../../../packages/client/src/**/*.stories.@(ts|tsx)", // client
]
A custom packageScopedAliasPlugin Vite plugin resolves @/ imports dynamically based on the importing file's package. Files under packages/admin/ resolve @/ to packages/admin/src/, and files under packages/client/ resolve to packages/client/src/.
The preview CSS imports the shared theme plus the admin M3 token/override CSS used by Admin/* stories. Shell and canvas stories should use private helpers from packages/shared/.storybook so their frame matches the intended canvas context without depending on package app entrypoints.
Addons
The current Storybook config enables:
@storybook/addon-a11y-- Accessibility audits via axe-core@storybook/addon-docs-- Autodocs pages fortags: ["autodocs"]@storybook/addon-vitest-- Browser-mode story smoke andplay()tests@storybook/addon-mcp-- Local MCP endpoint for agent access to Storybook knowledge@chromatic-com/storybook-- Visual testing UI integration when Chromatic is configured
Completing Test Coverage
Story Format
All stories use Component Story Format 3 (CSF3). Each story file exports a meta default export and named story exports:
import type { Meta, StoryObj } from "@storybook/react";
import { MyComponent } from "./MyComponent";
const meta = {
title: "Shared/Primitives/MyComponent",
component: MyComponent,
tags: ["autodocs"],
} satisfies Meta<typeof MyComponent>;
export default meta;
type Story = StoryObj<typeof meta>;
export const Default: Story = {
args: { label: "Click me" },
};
export const Disabled: Story = {
args: { label: "Disabled", disabled: true },
};
Title Hierarchy
Stories are organized by package and ownership in the sidebar:
Shared/Primitives/*,Shared/Canvas/*,Shared/Form/*,Shared/Feedback/*,Shared/Display/*,Shared/Cards/*,Shared/Progress/*-- Storybook-backed shared foundationsShared/Tokens/*-- Design token documentation (colors, typography, shadows, animation, material roles)Admin/Primitives/*-- Admin-onlyAdmin*wrappersAdmin/Shell/*-- Admin-owned canvas shell and account surfacesAdmin/Workflows/*-- Curated reusable admin workflow surfacesClient/*-- Existing client component stories only
For consolidated state views, prefer a StateCatalog story name over generic Gallery. Keep individual stories for states that agents need to link to directly, and use the theme toolbar instead of adding one-off dark-mode duplicates unless the component has a dark-mode-specific behavior.
Deterministic Fixtures
Admin stories and shared stories consumed by admin must be deterministic:
- Use fixture helpers from
packages/shared/.storybook/fixtures.ts. - Do not use
Date.now(), zero-argumentnew Date(),picsum.photos, or placeholder IPFS CIDs. - Use the frozen Storybook clock (
STORYBOOK_NOW_SECONDS,hoursAgo,daysAgo,daysFromNow) for relative-time or expiry states. - Use data URL fixture images (
FIXTURE_WORK_MEDIA,FIXTURE_IMAGE_*) instead of live external media.
This is the model for future shared/client cleanup. Full cleanup can happen incrementally, but anything that backs admin review should follow it now.
Design Token Stories
The packages/shared/src/components/Tokens/ directory contains stories that document the design system's visual language:
Colors.stories.tsx-- Semantic color tokens fromtheme.cssTypography.stories.tsx-- Font scales and text stylesShadows.stories.tsx-- Elevation levelsAnimations.stories.tsx-- Motion tokensDesignToolImports.stories.tsx-- Import map for Google Stitch, Claude Design, Storybook MCP, and other tools
These are not interactive components -- they serve as living documentation of the design system.
Design Tool Imports
Storybook prepares a generated static bundle before local dev, test, and build commands run:
cd packages/shared && bun run storybook:prepare-design-assets
The bundle is served from the Storybook root. In the Vercel standalone deploy, that means:
https://design.greengoods.app/DESIGN.md-- canonical Warm Earth DesignMD sourcehttps://design.greengoods.app/DESIGN.browser.md-- preferred public-browser dialect for the component libraryhttps://design.greengoods.app/design-md.generated.json-- machine-readable DesignMD tokenshttps://design.greengoods.app/theme.css-- runtime CSS token projectionhttps://design.greengoods.app/storybook-design-manifest.json-- machine-readable map across design files, story roots, and import surfaceshttps://design.greengoods.app/index.json-- Storybook component and state cataloghttps://design.greengoods.app/social-card.png-- 1200x630 social preview image for shared Storybook links
Google Stitch should load the root DesignMD file, the browser dialect file, and the generated token JSON. Claude Design should load the same files plus index.json so it can reference actual story roots and component states. Storybook MCP remains a local development server capability via @storybook/addon-mcp; the static deploy provides the shareable story index and design exports.
Vercel Deploy
Standalone Storybook publication is owned by Vercel, not GitHub Actions. Configure the Vercel project with:
- Root Directory --
packages/shared - Include source files outside of the Root Directory in the Build Step -- enabled
- Build config -- read from
packages/shared/vercel.json - Production domain --
design.greengoods.app
The shared-package vercel.json moves back to the repository root during install/build commands so Bun can resolve the workspace lockfile and cross-package Storybook stories, then serves packages/shared/storybook-static as the root of design.greengoods.app.
The standalone site also injects Open Graph and Twitter card metadata through Storybook head files. Storybook root URLs and ?path=/docs/... URLs share the same social preview image because the manager shell serves those routes from one static HTML entrypoint.
Agent Workflow
For agent-driven TDD, treat Storybook as the state catalog and Vitest/RTL as the assertion layer:
- add or update the story that expresses the intended state
- write the focused Vitest/RTL test for the behavior or contract
- add a
play()interaction only when it catches meaningful behavior without making the story brittle - tag only stable, high-value story files with
storybook-ci - use Storybook locally to inspect the resulting UI states and interaction paths
That keeps stories useful for exploration without turning CI into a slow, brittle browser harness.
Mock Patterns in Stories
Stories that depend on React Query or routing use decorators to provide the necessary context:
export default {
title: "Admin/Workflows/GardenCard",
decorators: [withRouter(["/garden"])],
};
Private Storybook helpers live under packages/shared/.storybook. Prefer those helpers for router, query, theme, and canvas wrappers before adding one-off decorators. For components that rely on shared hooks, mock the hook return values using parameters or wrapper decorators rather than mocking modules directly.
Viewport Patterns
Stories for responsive components include viewport-specific stories:
export const Mobile: Story = {
parameters: {
viewport: { defaultViewport: "mobile1" },
},
};
Admin components use standard responsive breakpoints (sm:, md:, lg:), while some client components use container queries (@[480px]:) for container-aware responsiveness.
Running Tests
# Development server
cd packages/shared && bun run storybook
# Curated browser-mode Storybook smoke / play tests
cd packages/shared && bun run test:stories:ci
# Build static site
cd packages/shared && bun run build-storybook
# Check the required Storybook contract for shared foundations + curated admin surfaces (CI gate)
cd packages/shared && bun run check:stories
CI Integration
The storybook.yml workflow triggers on PRs that modify Storybook config, story files, the curated story coverage contract, and component or view files that feed the unified Storybook build. It runs three required checks:
- Storybook contract (
check:stories) -- Ensures shared foundations plus curated admin surfaces have corresponding stories - Storybook interaction smoke (
test:stories:ci) -- Runs browser-mode Vitest against curatedstorybook-cistories - Build verification (
build-storybook) -- Confirms the static Storybook site compiles without errors across shared, admin, and client stories
The built artifact is uploaded via actions/upload-artifact@v4 for review.
Chromatic Flow
Chromatic runs after the local Storybook gates, not instead of them:
check:storiesverifies that required shared foundations and curated admin surfaces have stories.test:stories:ciruns browser-mode Vitest against stablestorybook-cistories.build-storybookcreatespackages/shared/storybook-staticand uploads it as the CI review artifact.- If
CHROMATIC_PROJECT_TOKENis configured,bun run --filter @green-goods/shared chromatic -- --exit-zero-on-changespublishes that built Storybook to Chromatic.
The first lane is intentionally non-blocking for visual diffs: --exit-zero-on-changes lets Chromatic collect baselines and surface screenshot changes without failing the PR while the design lane is being established. Once the team has approved baselines and decided which component roots should be visual-release gates, remove --exit-zero-on-changes and protect the Chromatic check.
The standalone component library deploy is owned by Vercel. The Storybook GitHub Actions lane remains the validation gate for Storybook coverage, interaction smoke tests, and the static Storybook build artifact.
Resources
- Storybook Documentation -- Official Storybook docs
- CSF3 Format -- Component Story Format reference
- Storybook config:
packages/shared/.storybook/main.ts - Design tokens:
packages/shared/src/components/Tokens/ - CI workflow:
.github/workflows/storybook.yml - Storybook deploy config:
packages/shared/vercel.json
Next page
Next: Test Cases
Learn about the test case structure and quality standards across the project.
Test Cases