Unit testing with react-scripts

Last update: 25 August, 2019

You can use react-scripts to write unit tests without setting up a build process with Babel and Webpack/Rollup. It’s useful when you want to quickly test an idea, but you’re not sure if you want to create a library yet. It can also be useful when your code lives inside a yarn workspace and doesn’t need a build process anyway.

Install react-scripts

yarn add -D react-scripts

Write test scripts

After installing react-scripts, you can then create some test scripts in your package.json:

{
  "scripts": {
    "test": "react-scripts test",
    "test:ci": "cross-env CI=true react-scripts test",
    "test:ci:alt": "react-scripts test --ci --watchAll=false",
    "test:jsdom": "yarn test --env=jsdom",
    "test:staged": "yarn test:ci --findRelatedTests",
    "test:coverage": "yarn test:ci --coverage"
  }
}

Let’s explain what those scripts do:

  • The test script runs the tests in watch mode—which is the default option.
  • If you want to run the tests and exit, you can set the CI environmental variable to true. That’s what the test:ci script does, with the help of the cross-env package. An alternative to that is to set the --watchAll flag to false.
  • If your tests require the DOM—if you are testing React components for example—you can use the test:jsdom script which sets the --env flag to jsdom.
  • The test:staged script is useful for running tests with a pre-commit hook—with husky and lint-staged for example.
  • Finally, the test:coverage script runs the tests and creates a coverage report. You can configure the coverage script further if you want.

Write tests

To write tests, use the test or it functions and assert your code with the expect function. You can optionally organize your tests inside a describe function. In the following snippet, I wrote some tests for a “flatten” function, that takes a nested array as input and returns a flat array.

The tests:

// src/flatten.test.js

import flatten from "./flatten";

describe("Flatten tests:", () => {
  it("Flattens an array.", () => {
    const nestedArray = [[1, 2, 3], [4]];
    const flatArray = [1, 2, 3, 4];
    expect(flatten(nestedArray)).toEqual(flatArray);
  });

  it("Returns empty array when the input is an empty array.", () => {
    const array = [];
    const result = flatten(array);
    const expectedResult = [];
    expect(result).toEqual(expectedResult);
  });
});

describe("Infinite nesting tests:", () => {
  it("Goes 4 levels deep.", () => {
    const nestedArray = [[1, 2, [3, [[4], 5]]], [6]];
    const flatArray = [1, 2, 3, 4, 5, 6];
    const result = flatten(nestedArray);
    expect(result).toEqual(flatArray);
  });
});

describe("Exact level tests:", () => {
  it("Goes exactly two levels deep.", () => {
    const nestedArray = [[1, [2, [3]], 4], [5]];
    const flatArray = [1, 2, [3], 4, 5];
    const result = flatten(nestedArray, 2);
    expect(result).toEqual(flatArray);
  });
});

The flatten function:

// src/flatten.js

const flatten = (array, level = 9999) => {
  if (!Array.isArray(array)) return array;
  const shouldGoDeeper = lvl => lvl + 1 <= level;
  const toFlat = lvl => (result, item) => {
    if (shouldGoDeeper(lvl) && Array.isArray(item))
      return item.reduce(toFlat(lvl + 1), result);
    return result.concat(item);
  };
  return array.reduce(toFlat(1), []);
};

export default flatten;

Other things to read

Popular posts

Other notes