Unit testing UI components

How virtual DOM made our life easier

Auteur: Johan Gorter

The web user interface that we are creating for Profit Next, the next version of our ERP system, will have many features to help the user.  These features include correcting double-capitals, formatting a date while you type and automatically suggesting recently used items. However, not all of these features are immediately visible. If one of these features would break, it is unlikely that this will be noticed anytime soon.

So how do we protect ourselves from accidentally breaking existing features while adding new ones? We do this by creating automated unit tests and requiring 100% code coverage on all frontend code.

One approach to unit testing frontend code is to use a browser. There are many frameworks that allow you to do this. In our experience, this approach is difficult to integrate into the build environment and tests are slow and sometimes flaky.

Lucky for us, because we use our Virtual DOM library, maquette, we do not need a browser to test our frontend code! We run our tests on NodeJS directly against the virtual DOM. We created the utility maquette-query to help us write test-code which is easy to understand. For example:

input.simulate.input({ value: 'John' });
expect(output.textContent).to.equal('Hello John!');

So how does this work? Maquette provides a projector which uses the virtual DOM to update the real DOM. Maquette-query provides an alternative for the projector, the test-projector. All the test-projector does, is keep a copy of the virtual DOM in memory and it allows you to query it. Test-code can now instantiate a UI component and run it in the test-projector. The rest of the test code can now interact with the component by simulating user input and query the virtual DOM to see if the component behaves as it should.

Maquette-query does not need a real DOM, which means that our tests run very fast. Here you can see me running 1700 tests in 2.3 seconds.

In conclusion, we are able to automatically unit-test every feature of our UI components. If we would accidentally break an existing feature, we will see this immediately. We also require 100% code coverage, which should mean that all features that we built are protected using unit-tests.

By the way, we also still use browsers to do cross-platform tests, but these tests are not meant to cover every detail of every component.

Over de auteur