Skip to main content

Configuration

Happo will look for configuration in a .happo.js file in the current working folder. You can override the path to this file through the --config CLI option or a HAPPO_CONFIG_FILE environment variable. The config file isn't subject to babel transpilation, so it's best to stay with good old CommonJS syntax unless you're on the very latest Node version. The configuration file can either export an object containing the configuration options or an (async) function that resolves with the configuration options.

apiKey and apiSecret

These tokens will authenticate you with happo.io. It is recommended to never store these tokens in plain text. Use environment variables instead.

module.exports = {
apiKey: process.env.HAPPO_API_KEY,
apiSecret: process.env.HAPPO_API_SECRET,
};

targets

This is where you specify the browsers you want to be part of your happo run. E.g.

module.exports = {
targets: {
// The first part ('firefox-desktop' in this case) is just a name we give
// the specific browser target. You'll see this name in the reports generated
// as part of a happo run.
'firefox-desktop': new RemoteBrowserTarget('firefox', {
viewport: '1024x768',
}),
'firefox-mobile': new RemoteBrowserTarget('firefox', {
viewport: '320x640',
}),
chrome: new RemoteBrowserTarget('chrome', {
viewport: '800x600',
}),
edge: new RemoteBrowserTarget('edge', {
viewport: '800x600',
}),
},
};

Viewports can range from 300x300 to 2000x2000 for Chrome and Firefox. Edge, and Safari need to be in the 400x400 to 1200x1200 range. The ios-safari target runs on an iPhone with a fixed viewport of 375x667. The ipad-safari target is always 1080x810

This is a list of all supported browser targets:

  • firefox
  • chrome
  • edge
  • safari
  • ios-safari (runs on iPhone 7)
  • ipad-safari (runs on iPad)

Target freezeAnimations

By default, Happo will freeze CSS animations on the first frame. If you want to freeze things on the last frame, use the freezeAnimations option.

module.exports = {
targets: {
ie: new RemoteBrowserTarget('edge', {
viewport: '1024x768',
freezeAnimations: 'last-frame',
}),
},
};

Target chunks

Targets are executed in parallel by default. If you want to split up a specific target into multiple chunks (running in parallel), the experimental chunks option for RemoteBrowserTarget can help out:

module.exports = {
targets: {
ie: new RemoteBrowserTarget('chrome', {
viewport: '1024x768',
chunks: 2,
}),
},
};

Happo.io will do its best to run chunks in parallel, but there's no guarantee. The chunks option also has some overhead. If your test suite isn't large, using more than one chunk might actually slow things down.

Target maxHeight

You can also use maxHeight to override the default max height used by Happo workers (5000 pixels). This is useful if you're taking screenshots of long components/pages in your test suite. An example:

module.exports = {
targets: {
chrome: new RemoteBrowserTarget('chrome', {
viewport: '1024x768',
maxHeight: 10000,
}),
},
};

Target scrollStitch

This option is available in the safari target (it has no effect in other targets). By default, Safari cuts off screenshots at window height. If you need to include content "below the fold", you can use the scrollStitch option. When enabled, the full screenshot will be constructed by scrolling the page section by section, then stitching together a full screenshot when all sections are available.

module.exports = {
targets: {
safari: new RemoteBrowserTarget('safari', {
viewport: '1024x768',
scrollStitch: true,
}),
},
};

Target hideBehavior

This option controls how Happo handles elements with the data-happo-hide attribute. The default is to make the elements with this attribute invisible. By using the value ignore, you can make the content appear in the screenshots but not taken into account when comparing.

module.exports = {
targets: {
safari: new RemoteBrowserTarget('safari', {
viewport: '1024x768',
hideBehavior: 'ignore',
}),
},
};

Target useFullPageFallbackForTallScreenshots

This option applies to Chrome and Firefox only.

When Chrome and Firefox workers are to take a screenshot of a page taller than 4000 pixels, they apply a workaround that involves resizing the viewport briefly so that all the content fits inside it. Without this workaround, some of the content below the bottom edge of the viewport can disappear (inconsistently). In some cases, this workaround can lead to other issues. Especially when you are using the vh CSS unit. A page with an element of height: 100vh will take up the entire screenshot when the viewport-altering fallback is in effect. To turn off the workaround completely, set useFullPageFallbackForTallScreenshots: false.

module.exports = {
targets: {
chrome: new RemoteBrowserTarget('chrome', {
viewport: '1024x768',
useFullPageFallbackForTallScreenshots: false,
}),
firefox: new RemoteBrowserTarget('firefox', {
viewport: '1024x768',
useFullPageFallbackForTallScreenshots: false,
}),
},
};

Target applyPseudoClasses

If set to true, this option will allow you to add data-happo-hover, data-happo-focus, and data-happo-active attributes to your DOM elements and have Happo apply either :hover, :focus, or :active styles. Let's say you have this markup:

<button>Hover me</button>
<style>
button:hover {
background-color: blue;
}
</style>

If you want the hover style to be applied before taking the screenshot (making the button blue), you can change the markup to this:

<button data-happo-hover>Hover me</button>
<style>
button:hover {
background-color: blue;
}
</style>

Similar to hover, you can also add focus to elements using data-happo-focus:

<input type="text" data-happo-focus />

And finally, you can also add data-happo-active to elements that simulate :active state:

<button data-happo-active>Click me</button>
<style>
button:active {
background-color: red;
}
</style>

Target prefersReducedMotion

Set prefersReducedMotion: true to make the browser prefer less motion when rendering the UI.

// .happo.js
module.exports = {
targets: {
chrome: new RemoteBrowserTarget('chrome', {
viewport: '1024x768',
prefersReducedMotion: true,
}),
},
};

When enabled, media queries that use prefers-reduced-motion: reduce will be activated.

@media (prefers-reduced-motion: reduce) {
button {
animation: none;
}
}

The prefersReducedMotion option is available in Chrome, Firefox, Safari and Edge.

Target allowPointerEvents

By default, Happo injects this css to prevent spurious hover effects caused by the system mouse pointer:

* {
pointer-events: none !important;
}

If you rely on mouse interaction in your tests, e.g. when using Storybook interactive stories, you might see an error like this in your logs:

Error: Unable to perform pointer interaction as the element has pointer-events: none

In some cases, this error will prevent the variant from being included in the report.

To resolve this, tell Happo to skip injecting the pointer-events: none CSS block. You can do that through the allowPointerEvents option.

// .happo.js
module.exports = {
targets: {
chrome: new RemoteBrowserTarget('chrome', {
viewport: '1024x768',
allowPointerEvents: true,
}),
},
};

If you are interested in testing hover, focus, and active states with Happo, you may also be interested in the applyPseudoClasses option.

project

If you have multiple projects configured for your happo.io account, you can specify the name of the project you want to associate with. If you leave this empty, the default project will be used.

include

This option only applies when you're using the Happo Examples integration

Controls what files happo will grab examples from. The default is '**/@(*-happo|happo).@(js|jsx)'. This option is useful if you want to apply a different naming scheme, e.g. **/*-examples.js.

stylesheets

This option only applies when you're using the Happo Examples integration

If you rely on external stylesheets, list their URLs or (absolute) file paths in this config option, e.g. ['/path/to/file.css', 'http://cdn/style.css']. If you're using conditionally applied stylesheets, you need to use objects instead of paths:

module.exports = {
stylesheets: [
{ id: 'main', source: '/path/to/main.css' },
{ id: 'secondary', source: '/path/to/conditional.css', conditional: true },
],
};

By default, all stylesheets are applied at render time. If you specify conditional: true, only those examples that conditionally apply the stylesheet will get styles applied from that stylesheet.

type

This option only applies when you're using the Happo Examples integration

Either react (default) or plain. Decides what strategy happo will use when rendering examples. When the value is react, it is assumed that example functions return a React component (e.g. export default () => <Foo />). When the value is plain, it is assumed that example functions write things straight to document, e.g. export default () => { document.body.appendChild(foo()) }.

customizeWebpackConfig

This option only applies when you're using the Happo Examples integration

A function you can use to override or modify the default webpack config used internally by happo during a run. Make sure to always return the passed in config. E.g.

module.exports = {
customizeWebpackConfig: config => {
config.module.rules.push({
test: /\.css$/,
use: [{ loader: cssLoader }],
});
// it's important that we return the modified config
return config;
},
};

In many cases, directly depending on the modules object of an existing webpack configuration is enough. For instance, this is what you would need to get up and running with a project using create-react-app:

const craWebpackConfig = require('react-scripts/config/webpack.config');

module.exports = {
customizeWebpackConfig: config => {
// Use the built-in webpack config provided by create-react-app
config.module = craWebpackConfig('development').module;
return config;
},
};

If you need to perform asynchronous actions to generate a webpack configuration, you can return a promise that resolves with the config once you are done. Here's an example using async/await:

module.exports = {
customizeWebpackConfig: async config => {
config.module = await doSomethingAsync();
return config;
},
};

plugins

An array of Happo plugins you want to use. Find available plugins on the Plugins page.

const happoPluginStorybook = require('happo-plugin-storybook');

module.exports = {
plugins: [happoPluginStorybook()],
};

publicFolders

This option only applies when you're using the Happo Examples integration

An array of (absolute) paths specifying the places where public assets are located. Useful if you have examples that depend on publicly available images (e.g. <img src="/foo.png" />).

const path = require('path');

module.exports = {
publicFolders: [path.resolve(__dirname, 'src/public')],
};

prerender

This option only applies when you're using the Happo Examples integration

Controls whether or not examples are pre-rendered in a JSDOM environment (or Chrome if you are using happo-plugin-puppeteer). The default is true. Set to false to let your examples render remotely on the happo.io browser workers instead. This can help resolve certain rendering issues (e.g. when using a shadow DOM). The downside of rendering remotely is that errors are harder to surface.

module.exports = {
prerender: false,
};

pages

An array containing pages that you want to screenshot. E.g.

module.exports = {
pages: [
{ url: 'https://www.google.com/', title: 'Google' },
{ url: 'https://www.airbnb.com/', title: 'Airbnb' },
],
};

The url of a page needs to be publicly accessible, else the Happo browser workers won't be able to find it.

The title of a page is used as the "component" identifier in the happo.io UI, so make sure it is unique for each page.

setupScript

This option only applies when you're using the Happo Examples integration

An absolute path to a file that will be executed before rendering your components. This is useful if you for instance want to inject global css styling (e.g. a css reset), custom fonts, polyfills etc. This script is executed in a DOM environment, so it's safe to inject things into the <head>.

const path = require('path');

module.exports = {
setupScript: path.resolve(__dirname, 'happoSetup.js'),
};

renderWrapperModule

This option only applies when you're using the Happo Examples integration

An absolute path to a file exporting a function where you can wrap rendering of Happo examples. This can be useful if you for instance have a theme provider or a store provider.

// .happo.js
const path = require('path');

module.exports = {
renderWrapperModule: path.resolve(__dirname, 'happoWrapper.js'),
};
// happoWrapper.js
import React from 'react';
import ThemeProvider from '../ThemeProvider';

export default component => <ThemeProvider>{component}</ThemeProvider>;

rootElementSelector

This option only applies when you're using the Happo Examples integration

A selector used to find a DOM element that Happo will use as the container. In most cases, you should leave this empty and let Happo figure out the root element itself. But in some cases its useful to override the default behavior and provide a different root. An example would be if you have wrapper components that you don't want to be part of the screenshot.

module.exports = {
rootElementSelector: '.react-live-preview',
};

(example from mineral-ui)

tmpdir

Happo uses webpack internally. By default, bundles are created in the temp folder provided by the operating system. You can override where bundles are stored with the tmpdir configuration option.

module.exports = {
tmpdir: '/some/absolute/path/to/an/existing/folder',
};

jsdomOptions

This option only applies when you're using the Happo Examples integration

Happo uses jsdom internally. By default, it provides sane defaults to the JSDOM constructor. See processSnapsInBundle.js. You can override any options here but your mileage may vary. See https://github.com/jsdom/jsdom#simple-options. Here's an example where the document's referrer is being set:

module.exports = {
jsdomOptions: {
referrer: 'http://google.com',
},
};

compareThreshold

This option is deprecated (since February 2021). The setting has moved into deep-compare settings for projects. See the Compare Threshold guide for more information on how to set things up.

By default, a shallow comparison is made when happo compare is called. If two images have one or more different pixels, it will be reported as a diff -- even if the diff is very small. If you set a compareThreshold, a deep comparison will be performed instead, where individual pixels are inspected.

A color distance is computed for every diffing pixel. If all diffing pixels have a color distance smaller than the compareThreshold, the diff is considered okay and the two images will be considered visually equal.

The difference is calculated according to the paper "Measuring perceived color difference using YIQ NTSC transmission color space in mobile applications" by Y. Kotsarenko and F. Ramos.

A word of warning here. If the threshold is too high, you risk hiding diffs that you wouldn't want to be hidden. Be careful when you start using this option.

module.exports = {
compareThreshold: 0.005,
};

To help find the right value to use, you can make dry-run comparisons. Find one or a few comparisons (via https://happo.io/dashboard) and run happo compare <sha1> <sha2> --dry-run on the SHAs and look at what's being logged to figure out what threshold value you want to use.

asyncTimeout

This option only applies when you're using the Happo Examples integration

If an example renders nothing to the DOM, Happo will wait a short while for content to appear. Specified in milliseconds, the default is 200.

module.exports = {
asyncTimeout: 500,
};

githubApiUrl

Used when you have the CI script configured to post Happo statuses as comments. The default if https://api.github.com. If you're using GitHub Enterprise, enter the URL to the local GitHub API here, e.g. https://ghe.mycompany.zone/api/v3 (the default for GHE installation is for the API to be located at /api/v3).