Testing a React app in Node.js with Jasmine

The Jasmine NPM package was originally designed just to run specs against your Node.js code, but with a couple of other packages, you can use it to run your React specs as well. This tutorial assumes you’re using babel to compile your code and either enzyme or React Testing Library to test it. We’ll also be using jsdom to provide a fake HTML DOM for the specs.

Choose the package managment tool you’ll be using:


Basic setup

Install these packages if you haven’t already:

$ yarn add --dev @babel/core \
                 @babel/register \
                 babel-preset-react-app \
                 cross-env \
                 jsdom \
                 jasmine
$ npm install --save-dev @babel/core \
                         @babel/register \
                         babel-preset-react-app \
                         cross-env \
                         jsdom \
                         jasmine

Then initialize Jasmine:

$ yarn run jasmine init
$ npx jasmine init

That command will create spec/support/jasmine.json and populate it with an initial default configuration. With Jasmine initialized, the first thing we’ll do is make a helper to register babel into the require chain. This will cause TypeScript files to be compiled to Javascript on the fly when they’re loaded. Make a new file called babel.js in the spec/helpers directory:

require('@babel/register');

Or, if using TypeScript:

require('@babel/register')({
    "extensions": [".js", ".jsx", ".ts", ".tsx"]
});

We need to tell Babel what flavor of Javascript we want by adding the following to package.json:

"babel": {
  "presets": ["react-app"]
}

Next, we need to provide a simulated browser environment. Create jsdom.js in spec/helpers with the following contents:

import {JSDOM} from 'jsdom';

const dom = new JSDOM('<html><body></body></html>');
global.document = dom.window.document;
global.window = dom.window;
global.navigator = dom.window.navigator;

In order to ensure these files are loaded before any specs run, we’ll edit spec/support/jasmine.json. We need the Babel helper to be loaded before any helpers that contain TypeScript code, so we modify jasmine.json like so:

"helpers": [
  "helpers/babel.js",
  "helpers/**/*.js"
],

Or, if using Typescript:

"helpers": [
  "helpers/babel.js",
  "helpers/**/*.{js,ts}"
],

Next, set up the test script in package.json to run Jasmine:

  "scripts": {
    "test": "cross-env NODE_ENV=test jasmine",

Handling CSS and image imports

It’s common for React code to import CSS or image files. Normally those imports are resolved at build time but they’ll produce errors when the specs are run in Node. To fix that, we add one more package:

$ yarn add --dev ignore-styles
$ npm install --save-dev ignore-styles

And put the following code in spec/helpers/exclude.js.

import 'ignore-styles';

Optional: Spec file pattern configuration

You also might want to change the way that Jasmine looks for spec files. Jasmine traditionally looks for files in the spec directory with names ending in .spec.js, but a common convention in React projects is to put spec files in the same directories as the code they test and give them names ending in .test.js. If you want to follow that convention, change the spec_dir, spec_files, and helpers setting in spec/support/jasmine.json accordingly:

  "spec_dir": "src",
  "spec_files": [
    "**/*.test.*"
  ],
  "helpers": [
    "../spec/helpers/babel.js",
    "../spec/helpers/**/*.js"
  ],

Or, for TypeScript:

  "spec_dir": "src",
  "spec_files": [
    "**/*.test.*"
  ],
  "helpers": [
    "../spec/helpers/babel.js",
    "../spec/helpers/**/*.{js,ts}"
  ],

Setting up a React testing utility

We’ll need a way to render React components and inspect the result. There are several utility libraries that provide that functionality. The most popular are enzyme and React Testing Library.

Enzyme

To set up Enzyme, we’ll first install these packages:

$ yarn add --dev enzyme \
                 enzyme-adapter-react-16 \
                 jasmine-enzyme
$ npm install --save-dev enzyme \
                         enzyme-adapter-react-16 \
                         jasmine-enzyme

Then we’ll want to make sure that we have enzyme loaded up, so make another file in spec/helpers, we’ll call this one enzyme.js for Javascript or enzyme.ts for TypeScript. (The file extension is important. While most of the helpers can be .js regardless of whether we’re using Javascript or TypeScript, this one has to be .ts in a TypeScript project. Otherwise the type definitions for jasmine-enzyme won’t be imported and spec files that use those matchers will fail to type check.)

import jasmineEnzyme from 'jasmine-enzyme';
import { configure } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';

configure({ adapter: new Adapter() });

beforeEach(function() {
  jasmineEnzyme();
});

See the Enzyme documentation for more information about using Enzyme, and the jasmine-enzyme documenatation for a list of available matchers.

React Testing Library

Setup for react-testing-library is simple. All we need to do is make sure the @testing-library/react package is installed. If you used a recent version of create-react-app to initialize your application, it might already be there. If not, install it:

$ yarn add --dev @testing-library/react
$ npm install --save-dev @testing-library/react

See the React Testing Library documentation for more information. The related jasmine-dom matcher library may also be of interest.

Note that most of the React Testing Library docs are written for Jest, so the code samples require some translation before they’ll work in Jasmine. In particular:

When translating code samples from Jest to Jasmine, you may find it helpful to refer to the Jasmine tutorial, the list of matchers that come with Jasmine, and the list of matchers that come with jasmine-dom.

Wrapping up

You’re all set. Write your specs and run them:

$ yarn test
$ npm test