Skip to main content

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:

  1. @storybook/addon-a11y -- Accessibility audits via axe-core
  2. @storybook/addon-docs -- Autodocs pages for tags: ["autodocs"]
  3. @storybook/addon-vitest -- Browser-mode story smoke and play() tests
  4. @storybook/addon-mcp -- Local MCP endpoint for agent access to Storybook knowledge
  5. @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 foundations
  • Shared/Tokens/* -- Design token documentation (colors, typography, shadows, animation, material roles)
  • Admin/Primitives/* -- Admin-only Admin* wrappers
  • Admin/Shell/* -- Admin-owned canvas shell and account surfaces
  • Admin/Workflows/* -- Curated reusable admin workflow surfaces
  • Client/* -- 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-argument new 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 from theme.css
  • Typography.stories.tsx -- Font scales and text styles
  • Shadows.stories.tsx -- Elevation levels
  • Animations.stories.tsx -- Motion tokens
  • DesignToolImports.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 source
  • https://design.greengoods.app/DESIGN.browser.md -- preferred public-browser dialect for the component library
  • https://design.greengoods.app/design-md.generated.json -- machine-readable DesignMD tokens
  • https://design.greengoods.app/theme.css -- runtime CSS token projection
  • https://design.greengoods.app/storybook-design-manifest.json -- machine-readable map across design files, story roots, and import surfaces
  • https://design.greengoods.app/index.json -- Storybook component and state catalog
  • https://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:

  1. Root Directory -- packages/shared
  2. Include source files outside of the Root Directory in the Build Step -- enabled
  3. Build config -- read from packages/shared/vercel.json
  4. 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:

  1. add or update the story that expresses the intended state
  2. write the focused Vitest/RTL test for the behavior or contract
  3. add a play() interaction only when it catches meaningful behavior without making the story brittle
  4. tag only stable, high-value story files with storybook-ci
  5. 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:

  1. Storybook contract (check:stories) -- Ensures shared foundations plus curated admin surfaces have corresponding stories
  2. Storybook interaction smoke (test:stories:ci) -- Runs browser-mode Vitest against curated storybook-ci stories
  3. 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:

  1. check:stories verifies that required shared foundations and curated admin surfaces have stories.
  2. test:stories:ci runs browser-mode Vitest against stable storybook-ci stories.
  3. build-storybook creates packages/shared/storybook-static and uploads it as the CI review artifact.
  4. If CHROMATIC_PROJECT_TOKEN is configured, bun run --filter @green-goods/shared chromatic -- --exit-zero-on-changes publishes 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