Skip to main content

Configuration

Happo looks for configuration in a .happo.js file in your current working directory. You can override this path using the --config CLI option or the HAPPO_CONFIG_FILE environment variable. The config file doesn't undergo babel transpilation, so use CommonJS syntax unless you're on the latest Node version. The configuration file can export either an object containing configuration options or an (async) function that resolves to configuration options.

apiKey and apiSecret

These tokens authenticate you with happo.io. 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

Specify the browsers you want to include in your happo run. For example:

module.exports = {
targets: {
// The first part ('firefox-desktop' in this case) is a name you give
// to the specific browser target. You'll see this name in the reports
// generated during 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',
}),
},
};

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

Supported browser targets:

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

Target freezeAnimations

By default, Happo freezes CSS animations on the first frame. To freeze animations on the last frame instead, use the freezeAnimations option.

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

Target chunks

Targets run in parallel by default. To split a specific target into multiple chunks (running in parallel), use the experimental chunks option for RemoteBrowserTarget:

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

Happo.io attempts to run chunks in parallel, but there's no guarantee. The chunks option adds some overhead, so if your test suite isn't large, using more than one chunk might actually slow things down.

Target maxHeight

Use maxHeight to override the default maximum height used by Happo workers (5000 pixels). This is useful when taking screenshots of tall components or pages. For example:

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

Note: The maximum width defaults to the maximum height, so if you set maxHeight, you may also want to set maxWidth at the same time.

Target maxWidth

Use maxWidth to override the default maximum width used by Happo workers (defaults to maxHeight, which defaults to 5000 pixels). This is useful when taking screenshots of wide components or pages. For example:

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

Target hideBehavior

This option controls how Happo handles elements with the data-happo-hide attribute. By default, elements with this attribute are made invisible. Use the value ignore to make the content appear in screenshots but exclude it from comparison.

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 take screenshots of pages taller than 4000 pixels, they apply a workaround that briefly resizes the viewport so all content fits inside it. Without this workaround, content below the viewport's bottom edge can disappear inconsistently. However, this workaround can cause other issues, especially when 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 active. To disable this 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

When set to true, this option allows you to add data-happo-hover, data-happo-focus, and data-happo-active attributes to your DOM elements and have Happo apply the corresponding :hover, :focus, or :active styles. For example, if you have this markup:

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

To apply the hover style before taking the screenshot (making the button blue), change the markup to:

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

Similarly, you can add focus to elements using data-happo-focus:

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

And add data-happo-active to elements to simulate the :active state:

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

Target prefersColorScheme

Set prefersColorScheme: 'dark' or prefersColorScheme: 'light' to set the color scheme preference in the browser. Note: This option has no effect in iOS Safari.

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

When enabled, styles affected by the color scheme will be activated:

background: white;
color: black;

@media (prefers-color-scheme: dark) {
background: black;
color: white;
}

Target prefersReducedMotion

Set prefersReducedMotion: true to make the browser prefer reduced motion when rendering the UI. Note: This option has no effect in iOS Safari.

// .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;
}
}

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 prevents the variant from being included in the report.

To resolve this, tell Happo to skip injecting the pointer-events: none CSS block using the allowPointerEvents option:

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

If you're interested in testing hover, focus, and active states with Happo, you may also want to use the applyPseudoClasses option.

project

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

include

This option only applies when using the Happo Examples integration

Controls which files Happo will extract examples from. The default is '**/@(*-happo|happo).@(js|jsx)'. This option is useful if you want to apply a different naming scheme, such as **/*-examples.js.

stylesheets

This option only applies when using the Happo Examples integration

If you rely on external stylesheets, list their URLs or absolute file paths in this config option, such as ['/path/to/file.css', 'http://cdn/style.css']. If you're using conditionally applied stylesheets, 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 examples that conditionally apply the stylesheet will receive styles from that stylesheet.

type

This option only applies when using the Happo Examples integration

Either react (default) or plain. Determines the strategy Happo will use when rendering examples. When set to react, example functions are expected to return a React component (e.g., export default () => <Foo />). When set to plain, example functions are expected to write directly to document (e.g., export default () => { document.body.appendChild(foo()) }).

customizeWebpackConfig

This option only applies when 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. Always return the passed config. For example:

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

In many cases, directly depending on the modules object of an existing webpack configuration is sufficient. For instance, this is what you need to get started 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. 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 using the Happo Examples integration

An array of absolute paths specifying 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 using the Happo Examples integration

Controls whether examples are pre-rendered in a JSDOM environment (or Chrome if you're 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 shadow DOM). The downside of remote rendering is that errors are harder to surface.

module.exports = {
prerender: false,
};

pages

An array containing pages you want to screenshot. For example:

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

The url of a page must be publicly accessible, otherwise the Happo browser workers won't be able to access it.

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

setupScript

This option only applies when using the Happo Examples integration

An absolute path to a file that will be executed before rendering your components. This is useful if you 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 using the Happo Examples integration

An absolute path to a file exporting a function where you can wrap the rendering of Happo examples. This is useful if you have a theme provider or 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 using the Happo Examples integration

A selector used to find a DOM element that Happo will use as the container. In most cases, leave this empty and let Happo determine the root element automatically. However, in some cases it's useful to override the default behavior and provide a different root. For example, 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 using the tmpdir configuration option.

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

jsdomOptions

This option only applies when using the Happo Examples integration

Happo uses jsdom internally. By default, it provides sensible 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, they 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 acceptable 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.

Warning: If the threshold is too high, you risk hiding diffs that you wouldn't want to be hidden. Be careful when using this option.

module.exports = {
compareThreshold: 0.005,
};

To help find the right value, 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 examine the logged output to determine what threshold value you want to use.

asyncTimeout

This option only applies when 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 is https://api.github.com. If you're using GitHub Enterprise, enter the URL to your local GitHub API here, such as https://ghe.mycompany.zone/api/v3 (the default for GHE installation is for the API to be located at /api/v3).