Last Updated: February 25, 2016
· zilti

How to set up Specljs for your ClojureScript code


Recently I finally wanted to set up a testing framework for my ClojureScript-code, but I ended up in hours of wasted time just trying to find the relevant stuff and documentation.

I decided to work with Specljs (and speclj for my Clojure code). The first important thing to know is that they're both generated from the same repository hosted on GitHub. There's also clojurescript.test from cemerick if you prefer the core.test syntax. The setup is the same except for the test command and the dependencies/:require-entries.


In my opinion it's best to use PhantomJS for testing. I haven't tried any other solution and don't know of another one; Let me know if you find alternatives.

Setting up the project file

Adding specljs

The first thing we need is to add the dependency:

:profiles {:user {:plugins [[specljs "2.7.4"]]}}

Automatic testing

Usually you'll want to place your tests in another directory than your sourcecode, and you'll want to automatically execute the tests at compile time. This can be achieved to add a new entry in :cljsbuild :builds:

{:source-paths ["cljs" "test-cljs"]
 :compiler { ...}
 :notify-command ["phantomjs" "phantom/unit-test.js" "phantom/tests.html"]}

The notify-command gets executed every time you compile with that specific build entry.

cljsbuild's test-commands

Additionally, or alternatively, you can also add the test-commands entry (inside :cljsbuild), though I found it to have no effect with my configuration, for whatever reason:

:test-commands {"tests" ["phantomjs" "phantom/unit-test.js" "phantom/tests.html"]}}

Supporting files

To run the test, we need two additional files, to be placed inside the "phantom" directory (or any other, make sure to adjust the references in your project.clj file).

One is needed to launch phantomjs and tell it what to do (unit-test.js) and the other loads the script (tests.html). I posted them both in this gist entry.

How to write your testing files

That's one of the major stumbling blocks. The critical part is that you have to require specljs.core, or else you'll get a meaningless phantomjs error preventing you from running your tests.

Here's an example namespace declaration:

(ns my-project.core-test
    (:require specljs.core)
    (:require-macros [specljs.core :refer [describe it should]]))

Of course you can add any other specljs/speclj macro inside the :refer list. See the specljs page for further instructions.

Happy testing!