Visual Regression Testing with Storybook 7
Published: 2023-05-13 07:38:49

Storybook 7 has deprecated the [storyshots plugin](https://storybook.js.org/addons/@storybook/addon-storyshots), which was commonly used to set up a [visual regression testing workflow](https://storybook.js.org/docs/ember/writing-tests/visual-testing) with [jest-image-snapshot](https://github.com/americanexpress/jest-image-snapshot) (as an alternative to [their paid Chromatic](https://www.chromatic.com/) 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](https://github.com/storybookjs/storybook/issues/22263), and no alternative workflow documented with their new [test-runner](https://storybook.js.org/addons/@storybook/test-runner) yet. It is even broken in v7, with recommendations to [use workarounds](https://github.com/storybookjs/storybook/issues/22142) instead of a mainline fix yet.

## Overview

The new test-runner functionality uses [`playwright`](https://playwright.dev/) and [`jest`](https://jestjs.io/) 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`](https://github.com/americanexpress/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

```sh
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:

```ts
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_

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

## Running visual regression tests

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

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

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

```sh
yarn run storybook &
```

and then run `test-storybook`:

```sh
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:

```sh
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) 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 artifacts with a local http server.

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

```sh
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
```