Jest
Painless JavaScript Unit Testing

Adaptable

Jest uses Jasmine assertions by default and Jest is modular, extendible and configurable.

Sandboxed and Fast

Jest virtualizes JavaScript environments, provides browser mocks and runs tests in parallel across workers.

Mock by Default

Jest automatically mocks JavaScript modules, making most existing code testable.


Why use Jest?

  • Automatically finds tests to execute in your repo.
  • Sandboxes test files and resets state automatically for every test.
  • Automatically mocks dependencies for you when running your tests.
  • Allows you to test asynchronous code synchronously as well as Promises and async/await.
  • Uses static analysis to find and only run relevant test files during local development.
  • Provides a manual mocking library.
  • Runs your tests with a fake DOM implementation (via jsdom) on the command line.
  • Runs tests in parallel processes to minimize test runtime.
  • Works with any compile-to-JS language and integrates seamlessly with Babel.
  • Creates coverage reports.

Getting Started

First install Jest with npm by running:

npm install --save-dev jest-cli

Great! Now let's get started by writing a test for a hypothetical sum.js file:

function sum(a, b) {
  return a + b;
}
module.exports = sum;

Create a directory __tests__/ with a file sum-test.js:

jest.unmock('../sum'); // unmock to use the actual implementation of sum

describe('sum', () => {
  it('adds 1 + 2 to equal 3', () => {
    const sum = require('../sum');
    expect(sum(1, 2)).toBe(3);
  });
});

Add the following to your package.json:

"scripts": {
  "test": "jest"
}

Run npm test:

[PASS] __tests__/sum-test.js (0.010s)

The code for this example is available at examples/getting_started.

And you are ready to enjoy working with Jest!

Babel Integration #

If you'd like to use Babel, it can easily be enabled:

npm install --save-dev babel-jest babel-polyfill

Don't forget to add a .babelrc file in your project's root folder. For example, if you are using ES2015 and React.js with the babel-preset-es2015 and babel-preset-react presets:

{
  "presets": ["es2015", "react"]
}

You are now set up to use all ES2015 features and React specific syntax, for example:

jest.unmock('../CheckboxWithLabel');

import React from 'react';
import ReactDOM from 'react-dom';
import TestUtils from 'react-addons-test-utils';
import CheckboxWithLabel from '../CheckboxWithLabel';

describe('CheckboxWithLabel', () => {
  it('changes the text after click', () => {
    // Render a checkbox with label in the document
    const checkbox = TestUtils.renderIntoDocument(
      <CheckboxWithLabel labelOn="On" labelOff="Off" />
    );

    const checkboxNode = ReactDOM.findDOMNode(checkbox);

    // Verify that it's Off by default
    expect(checkboxNode.textContent).toEqual('Off');

    // ...
  });
});

Check out the React tutorial for more.

And you are good to go! The next time you run Jest it will print something like

 Using Jest CLI v<version>, jasmine2, babel-jest

The React, Relay and react-native repositories have excellent examples of tests written by Facebook engineers.

Advanced Features #

Only run test files related to changes with jest -o #

On large projects and applications it is often not feasible to run thousands of tests when a single file changes. Jest uses static analysis to look up dependency trees in reverse starting from changed JavaScript files only. During development, it is recommended to use jest -o or jest --onlyChanged which will find tests related to changed JavaScript files and only run relevant tests.

Install Jest globally #

Jest can be installed globally: npm install -g jest-cli which will make a global jest command available that can be invoked from anywhere within your project.

Async testing #

Promises and even async/await can be tested easily. Jest provides a helper called pit for any kind of async interaction.

Assume a user.getUserName function that returns a promise, now consider this async test with Babel and babel-plugin-transform-async-to-generator or babel-preset-stage-3:

jest.unmock('../user');

import * as user from '../user';

describe('async tests', () => {
  // Use `pit` instead of `it` for testing promises.
  // The promise that is being tested should be returned.
  pit('works with promises', () => {
    return user.getUserName(5)
      .then(name => expect(name).toEqual('Paul'));
  });

  pit('works with async/await', async () => {
    const userName = await user.getUserName(4);
    expect(userName).toEqual('Mark');
  });
});

Check out the Async tutorial for more.

Automated Mocking and Sandboxing #

Jest isolates test files into their own environment and isolates module execution between test runs. Jest swaps out require() to inject mocks that were either created manually by the user or automatic mocks through the automocking feature.

Use the --watch option to automatically re-run tests #

Jest can automatically re-run tests when files change:

jest --watch

Use --bail to abort after the first failed test. #

If you don't want to wait until a full test run completes --bail can be used to abort the test run after the first error.

Use --coverage to generate a code coverage report #

Code coverage can be generated easily with --coverage.

-----------------------|----------|----------|----------|----------|
File                   |  % Stmts | % Branch |  % Funcs |  % Lines |
-----------------------|----------|----------|----------|----------|
 react/                |     91.3 |    60.61 |      100 |      100 |
  CheckboxWithLabel.js |     91.3 |    60.61 |      100 |      100 |
-----------------------|----------|----------|----------|----------|

Use --json for CI integrations #

Jest can be integrated into Continuous Integration test runs and wrapped with other scripts to further analyze test results.

Example Output:

{
  "success": true,
  "startTime": 1456983486661,
  "numTotalTests": 1,
  "numTotalTestSuites": 1,
  "numRuntimeErrorTestSuites": 0,
  "numPassedTests": 1,
  "numFailedTests": 0,
  "numPendingTests": 0,
  "testResults":[
    {
      "name": "react/__tests__/CheckboxWithLabel-test.js",
      "status": "passed",
      "startTime": 1456983488908,
      "endTime": 1456983493037
    }
  ]
}