Testing Om components with cljs-react-test

React, Om, Clojure/ClojureScript, Testing


I’m working for Green Power Monitor which is a company based in Barcelona specialized in monitoring renewable energy power plants and with clients all over the world.

We’re developing a new application to monitor and manage renewable energy portfolios. I’m part of the front-end team. We’re working on a challenging SPA that includes a large quantity of data visualization and which should present that data in an UI that is polished and easy to look at. We are using ClojureScript with Om (a ClojureScript interface to React) which are helping us be very productive.

I’d like to show an example in which we are testing an Om component that is used to select a command from several options, such as, loading stored filtering and grouping criteria for alerts (views), saving the current view, deleting an already saved view or going back to the default view.

This control will send a different message through a core.async channel depending on the selected command. This is the behavior we are going to test in this example, that the right message is sent through the channel for each selected command. We try to write all our components following this guideline of communicating with the rest of the application by sending data through core.async channels. Using channels makes testing much easier because the control doesn’t know anything about its context

We’re using cljs-react-test to test these Om components as a black box. cljs-react-test is a ClojureScript wrapper around Reacts Test Utilities which provides functions that allow us to mount and unmount controls in test fixtures, and interact with controls simulating events.

This is the code of the test:

We start by creating a var where we’ll put a DOM object that will act as container for our application, c.

We use a fixture function that creates this container before each test and tears down React’s rendering tree, after each test. Notice that the fixture uses the async macro so it can be used for asynchronous tests. If your tests are not asynchronous, use the simpler fixture example that appears in cljs-react-test documentation.

All the tests follow this structure:

  1. Setting up the initial state in an atom, app-state. This atom contains the data that will be passed to the control.
  2. Mounting the Om root on the container. Notice that the combobox is already expanded to save a click.
  3. Declaring what we expect to receive from the commands-channel using expect-async-message.
  4. Finally, selecting the option we want from the combobox, and clicking on it.

expect-async-message is one of several functions we’re using to assert what to receive through core.async channels:

The good thing about this kind of black-box tests is that they interact with controls as the user would do it, so the tests know nearly nothing about how the control is implemented.</div>

Originally published in Manuel Rivero's blog.