Cross-browser screenshot testing with happo.io and Storybook

Henric Trotzig
happo.io
Published in
7 min readJan 2, 2019

A lot of people I talk to who are getting started with screenshot testing are also either looking into setting up a component library with Storybook or have an existing one. In this post I’ll walk you through the steps needed to integrate a Storybook setup with happo.io and get screenshots of all components in Chrome, Firefox, Safari, Edge, Internet Explorer and mobile Safari.

1. Creating the project

First, let’s create a basic React app. I’m going to use create-react-app to simplify some of the setup. This command is from the create-react-app docs:

npx create-react-app happo-demo-storybook
cd happo-demo-storybook

Once we have the React project, we’re going to set up Storybook. This command is from the Storybook docs:

npx -p @storybook/cli sb init

Once that’s done, we can make sure our Storybook setup is working by running this command:

yarn storybook

You should see something like this in your browser:

Notice how Storybook created a few example stories for us. We can use those right away in our happo.io test suite, saving us the time it would take to set up this ourselves.

2. Adding Happo

The next step is to add a happo.io integration to our project. First, we’re going to install the happo.io client. We’re also going to install the Storybook plugin for happo, happo-plugin-storybook. This plugin will take all the Storybook stories and turn them into Happo examples.

yarn add --dev happo.io happo-plugin-storybook

To run happo, we need to add a line to our package.json in the "scripts" section (in bold):

"scripts": {
"happo": "happo",
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject",
"storybook": "start-storybook -p 9009 -s public",
"build-storybook": "build-storybook -s public"
},

Before we can run that script however, we need to obtain some API tokens from happo.io. If you haven’t signed up already, go to https://happo.io/signup first and fill out the sign-up form to get a free trial. API tokens are available at https://happo.io/account. Once you have the apiKey and apiSecret , we add those to a .happo.js config file. And while we do that, we’re going to inject the happo-plugin-storybook that we installed earlier, plus tell happo.io what browsers we want to target.

// .happo.js
const { RemoteBrowserTarget } = require('happo.io');
const happoPluginStorybook = require('happo-plugin-storybook');
module.exports = {
apiKey: '<your api key>',
apiSecret: '<your api token>',
targets: {
chrome: new RemoteBrowserTarget('chrome', {
viewport: '1024x768',
}),
firefox: new RemoteBrowserTarget('firefox', {
viewport: '1024x768',
}),
edge: new RemoteBrowserTarget('edge', {
viewport: '1024x768',
}),
'internet explorer': new RemoteBrowserTarget('internet explorer', {
viewport: '1024x768',
}),
safari: new RemoteBrowserTarget('safari', {
viewport: '1024x768',
}),
'ios-safari': new RemoteBrowserTarget('ios-safari', {
viewport: '375x667',
}),
},
plugins: [
// see https://github.com/happo/happo-plugin-storybook for a list of options you can pass to the plugin
happoPluginStorybook(),
],
};

Save this file as .happo.js in the root folder of your project.

Apart from configuring the API tokens, we’ve also told Happo about the browsers we intend to target. In our case, they’re the following:

  • Chrome
  • Firefox
  • Safari
  • Edge
  • Internet Explorer (11)
  • iOS Safari (i.e. iPhone)

At this point there’s only one step left before we can start generating screenshots: we need to tell Storybook about our plugin. Open your .storybook/config.js file and add this somewhere at the top:

import 'happo-plugin-storybook/register';

This snippet will register a few helper functions that Happo use when rendering your stories.

3. Generating screenshots

Now that we have a fully configured Happo setup, it’s time to generate some screenshots! Run this command to create the first report:

yarn happo run

You’ll start seeing logs written to the console. When everything is done, the output will look something like this:

> yarn happo run
No [sha] provided. A temporary one will be used in place: "dev-520bd8b48d8d8ca24565".
Reading files... ✓ 1 found
Creating bundle... ✓
Generating screenshots in 6 targets...
- internet explorer ✓
- ios-safari ✓
- firefox ✓
- chrome ✓
- safari ✓
- edge ✓
Uploading report for dev-520bd8b48d8d8ca24565... ✓
View results at https://happo.io/a/60/p/62/report/dev-520bd8b48d8d8ca24565
Done dev-520bd8b48d8d8ca24565

The link at the bottom leads to a page on happo.io showing all the screenshots generated for us. Here’s how it looks:

A Happo report containing component screenshots from a fresh Storybook installation in different browsers.

This report contains screenshots of all our Storybook stories in all the browser targets that we configured in .happo.js. Notice how some browsers (most notably Internet Explorer) struggles with the emoji characters used in the Button story). This is a good example of why it’s important to test in multiple browsers, and also sort of proof that you shouldn’t rely on emojis in your UI (svg icons or icon fonts are better).

4. Integrating with a CI environment

Screenshot reports are great, but it’s in a CI environment that you’ll get the best value out of Happo. In a traditional pull request model, Happo will generate and compare screenshots between the base commit (usually a commit on the master branch) and the commit that is at the tip of the pull request. To get Happo integrated in a CI environment, we need to take care of a few things:

  1. On github.com: Install the Happo github app in your github organization.
  2. On happo.io: Connect your happo.io account with the right github repo.
  3. In your project: Add happo to your CI configuration.

That last step, adding happo to a CI configuration, is what we’ll take care of next. In the example below, we’re going to use Circle CI. If you have a different provider, you’ll have to adapt the example slightly based on instructions in the happo.io README.

In .circleci/config.yml, add a yarn happo-ci section understeps:

version: 2
jobs:
build:
docker:
- image: circleci/node:10
working_directory: ~/reposteps:
- checkout
- run: yarn install
- run: yarn happo-ci

To make that happo-ci command work, we need to add a line to package.json as well:

"scripts": {
"happo": "happo",
"happo-ci": "happo-ci-circleci",
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject",
"storybook": "start-storybook -p 9009 -s public",
"build-storybook": "build-storybook -s public"
},

At this point, we have everything we need to start seeing Happo reports attached to our pull requests. In the next section, we’ll put things to the test by pushing a pull request introducing a change.

5. Introduce a change

If we look closely at the screenshots generated in our initial report, we see that the “Welcome” component has a “stories” button that doesn’t look right.

The “Welcome” component, as rendered in iOS Safari (iPhone 7). Notice how the “stories” link/button doesn’t look exactly right.

Let’s fix the button! To do that, we’re going to add a static css file and tell .happo.js about its existence (changes in bold).

// .happo.js
const path = require('path');
const { RemoteBrowserTarget } = require('happo.io');
const happoPluginStorybook = require('happo-plugin-storybook');
module.exports = {
apiKey: process.env.HAPPO_API_KEY,
apiSecret: process.env.HAPPO_API_SECRET,
targets: {
chrome: new RemoteBrowserTarget('chrome', {
viewport: '1024x768',
}),
firefox: new RemoteBrowserTarget('firefox', {
viewport: '1024x768',
}),
edge: new RemoteBrowserTarget('edge', {
viewport: '1024x768',
}),
'internet explorer': new RemoteBrowserTarget('internet explorer', {
viewport: '1024x768',
}),
safari: new RemoteBrowserTarget('safari', {
viewport: '1024x768',
}),
'ios-safari': new RemoteBrowserTarget('ios-safari', {
viewport: '375x667',
}),
},
plugins: [
happoPluginStorybook(),
],
stylesheets: [path.resolve(__dirname, 'styles.css')], type: 'react',
};

This is just one way to add styling to an application. If you’re using a css-in-js strategy, you’re probably not going to use the stylesheets configuration option at all. For this example however, it fits in nicely.

Apart from the config, we also need to create the styles.css file. And in that file, we add our fix for the button rendering issue.

/* styles.css */
button {
border: none;
}

When we push our changes to github as a pull request, CircleCI will kick off our happo-ci job. Once that job is done, Happo will post a status back to our pull request.

A Happo build status posted to a pull request.

If we click “Details” next to the Happo status, we are taken to a page on happo.io where we are asked to review changes. We can inspect the diffs with different tools to make sure that they’re okay.

A demo of how you can use happo.io to inspect UI diffs and accept/reject them.

Once we’re done, we’ll use the “Accept” status as a way to signal to others that we’ve reviewed the report and that we think it’s moving us in the right direction. The status we pick here will also be posted back to our pull request over on github.com.

Build status is reflected on github.com after we review the diffs.

The pull request is now ready to be merged. We can feel good knowing that our css fix worked across six different browsers, and we know that our components are regression tested every time we make a pull request.

Resources

I hope this walkthrough is of help when setting up Happo alongside Storybook. If you want to dig deeper into how this demo was constructed, here are a few useful links:

https://github.com/happo/happo-demo-storybook — the demo repository on github.com.

https://happo.io/a/60/p/62/report/dev-520bd8b48d8d8ca24565 — the initial Happo report

https://github.com/happo/happo-demo-storybook/pull/1 — the pull request

https://happo.io/a/60/p/62/compare/f0049369806d9a82bbedac7f169b1dc0d8f38ba9/21a0b304a73a616f38c48d099ec32956d157ba71 — the Happo report for our pull request

--

--