Happo (formerly Diffux-CI) is a command-line tool to visually diff JavaScript components. Read more.
Happo comes bundled as an npm module. To install it, run
npm install -g happo
You'll also need Firefox installed on the machine. Happo uses selenium-webdriver under the hood, and will support whatever version Selenium supports. Happo currently works best with Firefox 47.0.1.
You begin by defining a set of examples that Happo will grab snapshots for. If a previous snapshot exists for a component, Happo will diff the new snapshot with the previous. If a diff is found, a visual representation of the changes will be constructed. You can then use that diff image to decide whether a visual regression has been introduced or not, and take appropriate action based on that information.
You define your examples in a JavaScript file and include it in the
sourceFiles
configuration option.
Here's an example of a button component being added to a Happo suite:
happo.define('button', function() {
var elem = document.createElement('button');
elem.setAttribute('class', '.button');
elem.innerHTML = 'Submit';
document.body.appendChild(elem);
});
Here's an example using React) and ES6:
happo.define('<MyReactComponent>', function() {
const div = document.createElement('div');
document.body.appendChild(div);
const component = (
<MyReactComponent
foo={1}
bar='baz'
/>
);
ReactDOM.render(component, div);
});
Examples are responsible themselves for rendering the element into the DOM. This is because a lot of frameworks (e.g. React) like to stay in control over the DOM. A helper method to reduce some of the boilerplate is probably a good idea in your project.
During development, you might want to zoom in/focus on a single example. In
those situations, you can use the happo.fdefine
function instead of
happo.define
. Using fdefine
will cause happo
to only run for the
examples that are using fdefine
and skip all examples using define
.
By default, Happo renders examples in a 1024 wide window. If you have
components that render differently depending on available screen size you can
use the viewports
option in the object passed in as the second argument to
happo.define
. These need to correspond to configured viewports
in the
.happo.yaml
file. Happo comes pre-configured with three default sizes:
large
(1024x768), medium
(640x888), and small
(320x444).
happo.define('responsive component', function() {
var elem = document.createElement('div');
elem.setAttribute('class', '.responsive-component');
document.body.appendChild(elem);
}, { viewports: ['large', 'small'] });
If your examples need to do something asynchronous before they finish render,
you can return a Promise
from your define method.
happo.define('async component', function() {
return new Promise(function(resolve) {
var elem = document.createElement('div');
document.body.appendChild(elem);
setTimeout(function() {
elem.innerHTML = 'Async content loaded';
resolve();
}, 100);
});
});
Alternatively, use the done
callback passed in to the define method.
happo.define('async component', function(done) {
var elem = document.createElement('div');
document.body.appendChild(elem);
setTimeout(function() {
elem.innerHTML = 'Async content loaded';
done();
}, 100);
});
Happo will clean up the DOM in between rendered examples. If you need more
control over the clean-up process you can override happo.cleanOutElement
with your own implementation. This is useful if you need to clean up event
listeners for instance, or if you use
React and need to unmount components.
happo.cleanOutElement = function(element) {
React.unmountComponentAtNode(element);
};
By default, Happo will compute a bounding rectangle used when snapshotting
based on all root DOM nodes found in the <body>
element. You can override
this default by implementing a happo.getRootNodes
function. If you use
React you might want to use this to better
control the size of the snapshot.
happo.getRootNodes = function() {
return document.querySelectorAll('[data-reactroot]');
};
Happo loads configuration in one of the following ways:
- From a javascript file specified via a
HAPPO_CONFIG_FILE
environment variable - From
.happo.js
in the current working directory
module.exports = {
// Control the interface on which the local server listens (defaults to 'localhost')
// (default: 'localhost')
bind: '0.0.0.0',
// Control the port used for the local server
// (default: 4567)
port: 7777,
// List javascript source files. These can be files or raw URLs.
// (default: [])
sourceFiles: [
'https://unpkg.com/[email protected]',
'application.js',
'happo-examples.js',
],
// List css source files. These can also be files or raw URLs.
// (default: [])
stylesheets: [
'application.css',
],
// List directories where public files are accessible (useful for e.g. font files)
// (default: [])
publicDirectories: [
'public',
],
// Specify the folder where snapshots are saved
// (default: 'snapshots')
snapshotsFolder: 'happo-snapshots',
// Configure the window size when taking snapshots
// (defaults shown below)
viewports: {
large: {
width: 1024,
height: 768,
},
medium: {
width: 640,
height: 888,
},
small: {
width: 320,
height: 444,
},
},
};
This command will fire up a Firefox instance and take snapshots of all your happo examples.
Once happo run
has finished, run happo review
from the command line. This
will open a page that compares the latest run's snapshots against the
previous snapshots.
If you want to debug rendering your examples, you can run happo debug
.
This will open a browser window pointing at /debug
, listing all your
examples. If you click one of them, the example will be rendered in isolation
and you can do use your developer tools to debug.
Uploads all current diff images to an Amazon S3 account and reports back URLs
to access those diff images. Requires that S3_ACCESS_KEY_ID
,
S3_SECRET_ACCESS_KEY
, and S3_BUCKET_NAME
are specified as environment
variables. S3_ACCESS_KEY_ID
and S3_SECRET_ACCESS_KEY
will be the
credentials Happo uses to access the bucket named S3_BUCKET_NAME
.
S3_BUCKET_PATH
can be set as an environment variable to specify a directory
path for where you want diff images uploaded within the S3 bucket.
Furthermore, S3_REGION
controls what
region is used to
find or create the bucket.
``
You can set these in the session by using export
:
export S3_ACCESS_KEY_ID=<YOUR_ACCESS_KEY_VALUE>
export S3_SECRET_ACCESS_KEY=<YOUR_SECRET_ACCESS_KEY_VALUE>
export S3_BUCKET_NAME=<YOUR_BUCKET_NAME>
happo upload
or by adding them in the beginning of the command:
S3_ACCESS_KEY_ID=<...> S3_SECRET_ACCESS_KEY=<...> ... happo upload
If you want the diff page to link back to a commit/PR, you can pass in a URL as
the argument to happo upload_diffs
. E.g.
happo upload "https://test.example"
To debug uploading, you can use the --debug
flag. Additional information will
then be printed to stderr
.
Uploads a small text file to an AWS S3 Account. This is useful if you want to
test your S3 configuration. Uses the same configuration as happo upload
does. As with happo upload
, you can
apply a --debug
flag here for a more verbose output.
happo upload-test --debug
The main purpose for Happo is for it to be run in a CI (Continuous Integration) environment. The command line tools provided are designed to be used as building blocks in a script that you can run in Travis, Jenkins and other Continuous Integration environments.
Below is an example of how you can use Happo to test if a commit introduces any visual change.
- Check out the commit previous to the one to test (e.g.
git checkout HEAD^
) - (optionally) precompile your JavaScript and/or CSS
- Run
happo run
to generate previous snapshots - Check out the commit to test
- (optionally) precompile your JavaScript and/or CSS
- Run
happo run
to diff against previously created snapshots - Run
happo upload
to upload diffs to a publicly accessible location
There's an example script implementing these steps located in happo_example.sh. Use that as a starting point for your own CI script.
Since Happo uses Firefox to generate its snapshots, you need a display. If
you are on a build server, you usually don't have a screen. To run happo
then, you can use a virtual display server such as
xvfb. The
example CI script as well as the internal Travis test
run for Happo uses xvfb-run
in order to obtain a virtual display.