Catch Storybook Regressions Without Writing a Single Test

DOM snapshot tests (toMatchSnapshot) compare markup, not pixels. Rename a wrapper and the test fails on an unchanged UI; change a color token and the markup is identical while the component visibly breaks. What users actually see is exactly what those tests miss.

Storybook renders every component state in isolation but never compares one build to the last, so a regression only shows up if someone clicks through every story by hand. This guide turns that same Storybook build into a visual regression suite - no test code, no plugin, no fixture. You build Storybook, upload the static output, and Buddy screenshots every story and compares it against an approved baseline.

Why Storybook alone does not catch regressions

Checking a story by eye does not scale, and it gets worse when components share tokens: one --color-fg or --space-4 change ripples through every story that uses it. In review you see one small CSS diff - not the forty stories it just altered.

A visual test compares the rendered image of each story build over build, catching those cascades without anyone clicking through the catalog. Every story you have already written is a test case, so coverage grows on its own, with no extra tests to maintain.

What you need

  • bdy CLI installed (requires Node.js v20+)
  • A Visual Tests suite token exported as BUDDY_VT_TOKEN, copied from the suite settings (inside a Buddy pipeline the token is injected automatically) - or skip the token entirely: sign in with bdy login and link the directory to a suite once with bdy tests visual link

Image loading...The suite Connect screen with the CLI install command, the suite token, and the build and upload commands

No changes to your components, your stories, or your package.json are required.

Create the first baseline

Visual Tests needs a baseline: the first accepted rendering of each story that future uploads are compared against.

Build Storybook and upload the static output. Every upload starts a new session:

bash
npm run build-storybook cd storybook-static && bdy tests visual upload $$

Buddy renders each story across all browsers, operating systems, and device resolutions enabled in the suite settings, then compares the result against the approved baseline. On the first upload there is no baseline yet, so every story arrives as New and Unreviewed.

Image loading...The snapshot list after the first upload, with every story arriving as New

Approve the stories to establish the baseline. From now on, these approved renderings are what every future upload is measured against.

Catch a regression

Now change a shared design token - the kind of edit that looks harmless in review:

diff
- --color-fg: #111111; /* High-contrast text. */ + --color-fg: #c7ccd6; /* Faded and barely readable. */ - --space-4: 1rem; + --space-4: 10rem; /* A typo that breaks every layout. */

Rebuild and upload again:

bash
npm run build-storybook cd storybook-static && bdy tests visual upload $$

Because the suite now has a baseline, Buddy renders every affected story and produces a side-by-side comparison: the approved baseline on the left, the new rendering on the right.

Image loading...A side-by-side diff of a Card story with the sharp baseline on the left and faded text with broken spacing on the right

Enable Show differences to dim the unchanged areas and highlight what moved in red. This is where testing at the story level pays off: a single token change surfaces as diffs across every story that consumed it - including the ones nobody thought to check.

Image loading...Show differences mode highlighting the changed regions in red across multiple stories

Review, approve, or reject

The final step is a decision. For an accidental regression, reject the change and fix the branch. For an intentional redesign, approve it and the new rendering becomes the baseline going forward.

Image loading...The approve and reject controls in the story review

Stories that render identically to the baseline are approved automatically and need no attention, so review effort stays focused only on what actually changed.

Handle flaky stories

Some stories differ between builds even when nothing meaningful changed - the usual causes are dynamic content, animation timing, lazy-loaded assets, and pixel-level rendering noise. Left unaddressed, these produce diffs you have to dismiss on every run.

  • Dynamic content such as timestamps or random data changes every render. Use fixed mock data in the story, or mask the volatile region. See Dynamic Content.
  • Animations and transitions get captured mid-frame. Pause or disable them so the story settles before the snapshot. See Flaky rendering.
  • Lazy-loaded images and fonts may not be ready at capture time. See Lazy loading.
  • Rendering noise such as anti-aliasing can flip individual pixels. The suite's Threshold / diff sensitivity controls how different a pixel must be before it counts as changed. Keep it at 0 so subtle color shifts stay detectable, and raise it only if noise causes false positives.

Automate it in a Buddy pipeline

A manual upload is easy to forget, so the next step is to run the whole flow on every push. The dedicated Storybook action covers build, upload, and comparison - just select your suite in the Visual Test Suite ID field and keep the default commands. The suite token is provided to the action automatically.

Image loading...The Storybook action configuration with a Visual Test Suite selected

yaml
- pipeline: storybook---visual-tests events: - type: PUSH refs: - "refs/heads/*" actions: - action: Build & upload Storybook type: STORYBOOK commands: |- npm install npm run build-storybook cd storybook-static && bdy tests visual upload visual_tests_suite: my_first_suite - action: Visual Test Session type: APPROVE_VT - action: Deploy preview type: TRANSFER - action: Notify #releases on Slack type: SLACK

Image loading...The pipeline workflow with the Storybook action, the Visual Test Session gate, and the delivery actions behind it

The APPROVE_VT action is a quality gate. When an upload matches the baseline, Buddy auto-approves the unchanged stories and the pipeline runs straight through. When a story differs, the pipeline pauses at the gate until a person approves or rejects the change - so the actions placed after it, such as a preview deployment or a Slack notification, wait behind the review.

Image loading...A pipeline paused at the APPROVE_VT quality gate while the delivery actions wait

Use PUSH with refs: ["refs/heads/*"] rather than WEBHOOK so the diff is evaluated on the feature branch, before merge. A regression is rejected on the branch and never reaches main.

Run it from anywhere

The upload step is the same command wherever it runs, so you are not tied to Buddy pipelines:

  • Buddy pipeline - the Storybook action above, with the suite token injected automatically. See Buddy Pipelines.
  • Locally - run bdy tests visual upload from your machine after a build to check a change before pushing. See Local.
  • Any other CI - GitHub Actions, GitLab CI, and so on. Export BUDDY_VT_TOKEN as a secret and run the same command. See GitHub Actions.

What it costs

Visual Tests are billed for the worker time that renders and compares your stories, not for the number of snapshots. Screenshot workers run on 1 CPU and 2 GB RAM, billed at $0.00024 per CPU-minute plus $0.00024 per GB-minute - $0.00072 per worker-minute. A single worker produces roughly 20 snapshots per minute, so on average a snapshot costs about $0.000036 - roughly $0.036 per 1,000. Because the bill tracks compute time, adding stories, browsers, or resolutions costs only the extra rendering time they take.

Bonus: a hosted Storybook for every version

On top of the visual review, every tested upload stores the built Storybook as a versioned artifact in your project - one version per upload:

Image loading...The Storybook artifact in the project, with one version per tested upload

Any version can be opened straight from the artifact as a fully working, hosted Storybook, protected by Buddy authorization. You can hand a designer or a reviewer a link to one specific build for feedback, without deploying anything yourself or exposing it publicly.

Image loading...A tested Storybook version served by Buddy on its own URL

Summary

  • Storybook documents components but has no memory. It renders the current state and cannot tell you a story regressed since the last build.
  • DOM snapshots miss visual bugs. They compare markup, not rendered pixels, so a token or CSS change can break the UI while the test stays green.
  • No test code required. Build Storybook and run bdy tests visual upload - no plugin, fixture, or spec changes. Every story you already wrote is a test case.
  • Shared-token regressions are caught at scale. One CSS change surfaces as diffs across every story that used it, not just the component you meant to touch.
  • The APPROVE_VT quality gate pauses a branch pipeline until a person approves or rejects a visual change. Place delivery actions after the gate.
  • The same bdy tests visual upload runs anywhere - locally, in a Buddy pipeline, or in any external CI such as GitHub Actions.
  • You pay for worker time rather than a per-snapshot fee - which averages about $0.000036 per snapshot - keeping large suites across many browsers and resolutions inexpensive.
  • You also get a hosted Storybook per version, protected by Buddy authorization, for sharing a specific build with designers and reviewers.
Jarek Dylewski

Jarek Dylewski

Customer Support

A journalist and an SEO specialist trying to find himself in the unforgiving world of coders. Gamer, a non-fiction literature fan and obsessive carnivore. Jarek uses his talents to convert the programming lingo into a cohesive and approachable narration.

Jul 17, 2026
Share