Tests for a React front-end : available tools

This part describes the available tools that can be used to test a front-end built with React. If you're already familiar with the concepts of a test framework, a test runner, or an assertion library, but you don't know the tools for the React ecosystem, you may jump directly to the short summary at the bottom of this page. If you already know everything about the available tools, and you only want to read about our implementation, feel free to jump to the next part.

Building your test toolchain

A test is a simple part of code that checks if something works as it should, and exits. The paradigm is often to input data into our component, and check it behaves correctly by checking its outputs. To achieve this, we basically need three things : a test framework, a test runner, and an assertion library.

The Test Framework

The test framework provides methods such as describe and it, that allow to describe and organize the specifications of the module under test. These methods will be called by the test runner.
describe is used to group tests, and is often meant to describe the way a module should behave. it is used to focus on one specific task our module under test should achieve, and contains assertions.

For example, here is how the test would look like for a function that is meant to add 3 to its argument, and return the result :


import addThree from 'somewhere';

describe('addThree', function() {
  it('should add 3 to its argument', function() {
    const a = 1;
    const b = addThree(a);

    // assert that [b equals 4] here
  });
  it('should not mutate its argument', function() {
    const a = 1;
    addThree(a);

    // assert that [a still equals 1] here
  });
});

This is extremely simplified, but the main idea is present : we test our module outputs, given some inputs representing typical use cases.

The assertion library

An assertion library is the tool that allows you to write assertions (you didn't guess that, did you ?).

An assertion is the actual test. It is made of a method call, that allows the developer to control that the module under test behaves as expected. such as assert.equal(variable, 3), which will throw an Exception when variable doesn't equal 3, that will be caught and reported by the test runner. There are several assertion libraries available, such as Chai, Assert, or Should.

The test runner

Finally, the test runner runs the tests files, then reports the results to the developer, or to a CI tool such as Jenkins. Its purpose is simple : it runs the code inside of each describe/it block, and checks this produces no error. If an assertion fails, or if anything goes wrong, the test is marked as failed.

Mocha's built-in test runner is fast, has a simple API and allows to report test results in Jenkins. Karma allows to run the tests in the browser (packing them with Webpack and transpiling them with Babel, in our case).

Selenium, along with WebDriver, allows to control a real browser, and thus fully test your interface. It sounds cool, because you're actually testing your product, and you're not caring about implementation details. We tried it, but decided not to use it, because it can make it painful to write tests, it is not very fast, and tests are too eager to break if the structure of the app changes, compared to being able to use a component's internal structure to test it.

Fully-integrated tools

There are several tools that handle more than one responsibility among those evoked earlier. These represent a trade-off : they tend to require less setup, because they are designed to provide everything you need, but you have to comply with their philosophy and they may be harder to extend and customize to fit edge-cases. Such tools include :

  • Jest : Facebook's unit test framework and test runner. It mocks automatically the dependencies of the module under test, and allows to start writing unit tests really quickly.
  • Jasmine : a test framework that comes with its own assertion library and mocking / spying capabilities.
  • Mocha : an open-source test framework, which has no built-in assertion library.

Summary

Here is a little table to sum up everything said previously. You may use it for further reference if you already understand the underlaying concepts, but want to know the perimeter of the available tools :

Test runner
(npm test)
Test framework
(describe, it)
Assertion library
(assert / expect)
Mocking, spying on functions
Facebook Jest
Jasmine
Karma
Mocha
Chai, Should, Expect
Sinon, Proxyquire

Other tools

Other tools might come in handy, especially if you're using a test framework that comes with few additional tools such as Mocha :

  • a library to mock dependencies of the modules under test, such as Proxyquire,
  • a library to write spies and test doubles, such as Sinon.

React is also specific in some ways. As said before, a test is often developed by taking a part of your app, giving it some data, and checking whether its outputs meet the requirements. However, in the case of a React component, testing outputs may be a little more complicated. A React Component can be seen as a module that takes props as input, and returns HTML as output. To make it render its HTML, we have to mount it, and that requires a DOM API, and a few other tools to ease interactions with the generated DOM and the component's subtree. We used a few off-the-shelf tools, and especially AirBNB's Enzyme, to serve this purpose.
However, we sometimes didn't find any suitable tool for our needs, especially when working with Redux and the asynchronous DOM mutations it induces. We are extremely proud to have open sourced some of those, and we would love to hear your feedback on those.

results matching ""

    No results matching ""