Using devcards for testing a ClojureScript Chrome extension


A few weeks ago I wrote a short piece about the available tools for building Chrome extensions in ClojureScript.

Among the tools I reviewed was khroma, a still very much work-in-progress ClojureScript library providing idiomatic access for the Chrome API. One of original comments I had was that khroma was still incomplete, and had some not entirely evident function names.

I have since taken up khroma development and begun extending and refactoring it. However, a question immediately came up: how do we go about testing it? Your first impulse might be to say “why, don’t we have cljs.test?”.

Yes, we do, but we can’t run these tests automatically from the command line: the APIs are only available when you’re running inside Chrome as an extension with the right permissions.

Moreover, I’d like to be able to provide usage samples and data review for the myriad of events you can hook up to, some of which aren’t easily testable because they depend on user input, or asynchronous inter-page communication. How to go about this, then?

Enter devcards.


devcards is a new library by Bruce Hauman, who also created figwheel (and if you don’t know what figwheel is, you’re in for a treat - watch his ClojureWest 2015 talk).

Just like figwheel made our lives easier with automatic code reloading where we don’t lose our data, devcards makes it trivial to interactively display bits of code (and their result) on a single page.

That doesn’t sound spectacular enough?

How about it’s all live?

And you can get a history of results and how their value changed?

This won’t be a tutorial. devcards’ own README, as well as the so-called hard sell, contain plenty of documentation for how to get started. I’ll focus instead of some of the use cases for devcards in my particular scenario.

Running tests

Perhaps the straightforward use case (other than just rendering documentation) is running ClojureScript tests. If you’re unfamiliar with cljs.test, it provides all the functionality for defining tests and evaluating assertions, but doesn’t impose a specific way in which those tests are run.

In our case, we need to be able to run these tests from within Chrome, and not as any random loaded page - we need to be acting as an extension.

khroma-tests is a Chrome extension which uses devcards to display the result of its tests.

Let’s see a trivial case: evaluating the result of getting the active tab:

You’ll see the assertions are wrapped on an async block. That’s because Chrome’s extension functions will usually return asynchronously.

That’s just fine with khroma. The test card will get rendered like this:

khroma get tab test

How about a more elaborate test? Below we’ll create tabs, switch between them, and query for the events that get fired as a result.

The way it gets displayed shows one of the nice things about devcards: not only do we get to render the result of our tests (all are passing here), but we also get to annotate and document the intent, not just the assertions.

khroma tab life cycle

Showing event history

Then there’s those cases you just can’t test, because they depend entirely on user actions. For example, we can’t force the machine to idle or lock from an extension, but we can show our users how the values for the events we receive when it happens.

The code below listens for events on a channel and, when they arrive, appends them to an atom. I then use a card to monitor this atom and render it as it updates.

khroma idle history

How about time-traveling through history?

Notice that small triangle on the image above? Turns out it’s a history control. devcards can optionally keep a history of an atom’s value, and you can see how it changed through time.

Isn’t that great? Imagine having to debug by hand the possible transitions of a value that’s governed by assorted events. With devcards, you can just observe it and show its history.

On the following example, I’m logging notifications of local extension storage changes, so we can easily review how it mutated as we ran the tests. We’ll just add to the vector to see all transitions at a glance, but could just have easily swapped it and just show the latest.

… or showing a function’s source?

When all else fails, we can always show a code sample. Unlike a case where we’d paste code inside our documentation, devcards allows us to directly reference and render a function’s source.

This means our rendered documentation will always be up to date, without us having to keep manually updating it. No more documentation rot!

devcard source render example


devcards is yet another superb addition to your ClojureScript toolbox. Thanks to it, I can now comfortably proceed extending khroma with the confidence that whatever changes or refactoring I have to make, I’ll be able to easily evaluate their effects.

If you want to see more examples, head out to the khroma-tests repository and take it for a spin

khroma-tests is included on the main khroma repository as of khroma 0.3.0. Read this for use instructions.



Ricardo J. Méndez