Published on

Storybook 7 - Visual Regression Testing

Authors

Storybook 7 has deprecated the storyshots plugin, which was commonly used to set up a visual regression testing workflow with jest-image-snapshot (as an alternative to their paid Chromatic service, which offers storybook hosting and visual regression testing).

However, at the time of writing (13/5/2023), Storybook are yet to update their documentation to say this is deprecated, with it only being mentioned in Github issues, and no alternative workflow documented with their new test-runner yet. It is even broken in v7, with recommendations to use workarounds instead of a mainline fix yet.

Overview

The new test-runner functionality uses playwright and jest under the hood to run in-browser tests against each of your stories. We can hook this new functionality and run a visual snapshot test with jest-image-snapshot.

Each story in your storybook is transformed into a test using babel, and you can add render assertions with a play() function in your story.

We will customise the underlying test-runner configuration to add a post-test hook to create a snapshot with jest-image-snapshot.

Install dependencies

yarn install jest-image-snapshot @storybook/test-runner -D

Creating a test-runner config

Storybook have thankfully provided useful jest configuration hooks we can use to Install jest-image-snapshot and run it after each generated story test.

Create a file in your storybook directory at .storybook/test-runner.ts with this configuration:

import { TestRunnerConfig } from '@storybook/test-runner'
import { toMatchImageSnapshot } from 'jest-image-snapshot'

const config: TestRunnerConfig = {
  setup: () => {
    expect.extend({ toMatchImageSnapshot })
  },
  postRender: async (page, context) => {
    // Add a post-render delay in case page is still animating
    await new Promise((resolve) => setTimeout(resolve, 500))
    const screenshot = await page.screenshot()
    expect(screenshot).toMatchImageSnapshot({})
  },
}

export default config

Add a babel configuration

If you don't already have a .babelrc (or equivalent), you will need to create one (e.g. if you use swc already, you will still need to create a babel configuration as unfortunately Storybook test-runner needs it to read your .stories.tsx files and create jest unit tests out of them).

.babelrc

{
  "presets": ["@babel/preset-typescript", "@babel/preset-env"]
}

Running visual regression tests

The visual regression tests can be setup in your package.json scripts section:

"scripts": {
  ...
  "test-storybook": "yarn run storybook-test"
}

When running the test-runner you need an instance of storybook running in the background:

yarn run storybook &

and then run test-storybook:

yarn run test-storybook

Establish a baseline

When you run your visual regression tests for the first time, storybook-test will create a baseline. This will save image files under __image_snapshot__ in your source code folder, which you should check in.

Updating your snapshots

You will need to update your snapshots when there has been a valid change to the layout of your story or there has been a regression.

When a regression is found, the test-runner will fail and it will give you an image path on your filesystem you can reference to see what the regression was.

Once you have fixed and validated your stories and are satisfied they are working correctly, you can update your baseline snapshots by running:

yarn run test-storybook -u

and check in the resulting changes to git.

Running visual regression tests in CI/CD

You can use the method above (running storybook in the background) to execute the visual regression tests in a CI/CD pipeline.

If you build your storybook for deployment to a server, you can also execute the tests against that server or against the built artefacts with a local http-server.

For example, to run them locally after building the storybook with yarn build:

yarn add wait-on concurrently http-server -D
npx concurrently -k -s first -n "SB,TEST" -c "magenta,blue" \
  "npx http-server storybook-static --port 6006 --silent" \
  "npx wait-on tcp:6006 && yarn test-storybook