Tests
There are a few testing frameworks out there for JS — mocha, jasmine, jest (which is React specific).
Each of them has their pros and cons, and at Docker we've decided to use a combination of Mocha (for tests) and Chai (for assertions). We also use JSDom to create a virtual DOM environment which we use to render React components.
Why?
- Mocha and Chai are easy to use, fast, and compatible with ES7 via Babel
- Mocha doesn't automatically mock everything in the way Jest does. That's a ton of magic you normally end up undoing. Basically, don't use Jest.
- JSDom is lighter weight than spinning up a browser or PhantomJS instance
- This means faster tests
- This means faster continuous integration cycles
- JSDom means we can virtually render without shallow rendering.
- This is super important because shallow rendering means you can't test decorators. Shallow rendering only renders one level deep. Decorators typically wrap your custom component with a parent — so only the parent decorator will render.
The setup
Setting up Mocha, Chai and JSDom to work with a Redux project is relatively easy. There are three steps:
- Install everything via NPM
- Change the package.json test command to use Mocha
- Add a JSDom setup
1. Installing packages
We need a few packages to get our tests running:
npm install --save-dev mocha chai jsdom
2. Changing the test command of package.json
Our package.json
commands should look like this;
"scripts": {
"test": "$(npm bin)/mocha --compilers js:babel/register --recursive --require ./test.setup.js src/scripts/**/_tests/"
...
}
Whoa. Complex AF, right? Here's what it does:
- Sets up Mocha to use BabelJS' "register" hook. Essentially every included file is put through Babel's preprocessor, which means you can write your tests in ES7 and use ES7 includes.
- Requires a test setup file which fakes a DOM using JSDom. This file is included below.
- Uses a splat to search for every folder which contains a
_tests
directory. All JS files in these folders will be run as tests.
3. The JSDom setup
The test.setup.js
file contains this:
import { jsdom } from 'jsdom';
global.document = jsdom('<!doctype html><html><body></body></html>');
global.window = document.defaultView;
global.navigator = global.window.navigator;
Kinda simple - set up a few global variables which use JSDom to create a fake document. Boom, you're good to render in pure JS with React.
Writing tests
If you're not so familiar with writing tests first read the Mocha documentation. Writing tests for a Redux app isn't that different from what you'd find in lodash.
Some pointers for things you should test:
- Test your middleware. This is basically everything that DRYs up your app.
- Test your reducers to ensure they're modifying state as expected.
- Test your selectors to ensure they're working as expected. You don't want to have to render a component to validate selectors.
- Test to ensure that your components render correctly given variants of data (for example, if something is hidden/shown depending on props). This is for bonus marks if you want an A+ from your teacher.
- Test your utility files and functions that are shared.
Bonus: optimizing CI tests with Docker
When you run tests via CI you'll need to npm install
every time you run tests. This can be hella slow. Instead, we can build a docker image which uses a hash of package.json to cache build images. We only end up waiting for a docker pull
instead of an npm install
, which is much faster.