ESC

Type to search the knowledge base.

Component Testing Storybook

Use Storybook as a component workshop and optional test runner — stories as living specs, interaction tests, and a11y checks.

intermediate3 min read
  • testing
  • component-testing

Storybook isolates UI components with controls and stories. Teams use it for design review, documentation, visual regression, and — increasingly — interaction tests that run in CI without a full app shell.

Docs: Storybook, Interaction testing, Test runner.

Stories as executable examples

// Button.stories.tsx
import type { Meta, StoryObj } from '@storybook/react';
import { Button } from './Button';

const meta: Meta<typeof Button> = {
  component: Button,
  args: { children: 'Save' },
};
export default meta;

type Story = StoryObj<typeof Button>;

export const Primary: Story = {
  args: { variant: 'primary' },
};

export const Disabled: Story = {
  args: { disabled: true },
};

Each story is a known state: empty, loading, error, long text, RTL — the same states you’d unit-test.

Interaction tests (play functions)

import { expect, fn, userEvent, within } from 'storybook/test';

export const Submits: Story = {
  args: { onClick: fn() },
  play: async ({ canvasElement, args }) => {
    const canvas = within(canvasElement);
    await userEvent.click(canvas.getByRole('button', { name: /save/i }));
    await expect(args.onClick).toHaveBeenCalled();
  },
};

These run in a real browser via Storybook test runner or Vitest browser mode integrations — closer to user behavior than shallow unit tests.

What Storybook is good at

Strength Why
Hard-to-reach states Force error props without backend
Design system QA Matrix of variants
A11y addon axe on stories
Visual regression Chromatic / Loki / Playwright screenshots
Docs Args table + MDX

What it is not

  • Full routing, auth, and multi-page flows — use E2E.
  • Business logic pure functions — unit test without Storybook overhead.
  • A substitute for Testing Library in package unit tests when you don’t want SB tooling.

Many teams use both: Testing Library for CI-fast logic/UI, Storybook for catalog + visual + some interactions.

Composition with MSW

// preview or story parameters
parameters: {
  msw: {
    handlers: [http.get('/api/user', () => HttpResponse.json(user))],
  },
}

Stories that fetch can stay deterministic — MSW.

CI sketch

# build static storybook + run test-runner
npm run build-storybook
npx test-storybook --url http://127.0.0.1:6006

Or Storybook’s Vitest integration depending on version.

Footguns

  1. Stories that only render happy path.
  2. Heavy app providers required for every story — extract light decorators.
  3. Snapshotting entire DOM of stories as the only test.
  4. Ignoring a11y addon failures.

Interview out-loud answer

“Storybook documents component states and can run interaction tests in a browser. I use it for design-system matrices and visual/a11y checks; I still unit-test pure logic and E2E critical journeys. Stories should include empty/error/long-content states.”

Story naming and matrix

Name stories by state, not by ticket (Loading, Empty, Error, LongNameTruncation). For design systems, a matrix of variant × size × disabled is worth the story count; for app pages, prefer a handful of high-value states.

Extra practice

Write a minimal demo in a scratch file or the playground: one happy path, one failure path, and one boundary input. If you cannot exhibit a bug that the pattern prevents, you do not own the concept yet — re-read the primary docs linked below and tighten the example until the failure is obvious.

Further reading

Related guides