Skip to main content
Juliano Alves
Back to blog

Storybook for documentation and interaction tests

4 min read
By Juliano Alves

Storybook is an isolated runtime for UI components: props controls, docs pages, and—critically—automated checks that would be painful to reproduce only inside the full application shell.

For teams shipping a design system or large component library, Storybook is the difference between “we think it works” and “we have executable specs for each state.”

Stories as living documentation#

Each story encodes:

  • Initial args (default state)
  • Variants (error, loading, empty, permission denied)
  • Edge props (long text, RTL, reduced motion)

New engineers onboard by reading stories instead of spelunking through route files.

CSF 3 composition#

Compose smaller stories into flows:

export const Default: Story = { args: { status: 'idle' } };
export const Submitting: Story = { args: { status: 'submitting' } };

Use play to chain user steps across composed components when testing integration of local subtrees.

Play functions and interactions#

@storybook/addon-interactions records and runs user flows with Testing Library primitives:

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

export const CheckoutHappyPath: Story = {
  play: async ({ canvasElement, step }) => {
    const canvas = within(canvasElement);

    await step('Fill shipping', async () => {
      await userEvent.type(canvas.getByLabelText(/address/i), '123 Main St');
    });

    await step('Submit', async () => {
      await userEvent.click(canvas.getByRole('button', { name: /pay/i }));
    });

    await expect(await canvas.findByText(/thank you/i)).toBeInTheDocument();
  },
};

step produces readable reports in CI logs when a flow fails.

Accessibility addon#

@storybook/addon-a11y runs axe checks per story. I gate merges on zero serious violations for published primitives. False positives happen—suppress narrowly with comments and issues tracked.

Visual regression#

Storybook alone does not diff pixels. Options:

  • Chromatic (hosted, tight integration)
  • Lost Pixel / Loki (self-hosted or CI Docker)

Visual tests catch unintended style drift; interaction tests catch broken behavior. Use both if the budget allows.

CI wiring#

{
  "scripts": {
    "storybook:build": "storybook build -o storybook-static",
    "storybook:test": "test-storybook --url http://127.0.0.1:6006"
  }
}

Pipeline steps:

  1. storybook:build
  2. Serve static folder (or storybook dev in CI service container)
  3. storybook:test with Playwright browser deps installed

Cache node_modules and Storybook build output fingerprinted by lockfile + config.

Mocking data#

Use MSW in Storybook preview to intercept fetch/axios and return deterministic payloads. Align handlers with OpenAPI examples when possible.

When Storybook hurts#

  • Over-storying: every one-off page variant does not need a story; focus on reusable components.
  • Stale args: stories drift from production defaults—schedule periodic audits.

Summary#

Storybook pays off when stories double as docs + tests: play functions for behavior, a11y addon for baseline compliance, optional visual diff for design fidelity. Wire it into CI so regressions fail before users see them.

© 2026 Juliano Alves. All rights reserved.