Using Mocha to test ClojureScript
As a bit of an experiment, last month I had a look at how to use Mocha to write CLJS tests, including exercising reagent components via JSDom and testing library. The end result was (opinion warning!) surprisingly pleasant.
(describe "[foo.components.views/article ...]"
(it "asserts click behaviour"
(let [!count (atom 0)
mounted (render-el [fcv/article {:on-click #(swap! !count inc)
:title "Title"}])
button (by-test-id mounted "a1")]
(click button)
(click button)
(assert (= @!count 2))))
(it "contains the title"
(let [title (str (random-uuid))
mounted (render-el [fcv/article {:title title}])
h1 (by-test-id mounted "maintitle")]
(assert h1 "Title Exists")))
(it "asserts against ratom updates"
(let [mounted (render-el [fcv/article {:title "THING"}])
button (by-test-id mounted "a2")]
(assert (.getByText mounted "THING"))
(click button)
;; Returns a promise to a query, or throws failing the test
(.findByText mounted "clicked"))))
The technique is to make a shadow-cljs build outputting a bundle from the tests, which Mocha is then told to watch and run when it changes. Macros wrap expressions with the globals mocha injects, describe
, it
, etc, and those are executed and reported as you would expect. They are incredibly dumb macros, which are purely to reduce boilerplate.
The output, using the spec reporter, looks like:
> test
> NODE_ENV=test mocha --exit --reporter spec 'target/*_test.js'
foo/func
✔ is true
- has a pending test
✔ wraps functions
✔ catch assertion failure
Promises are handled automatically
✔ happy path resolution
✔ happy path rejection
✔ should warn about timeouts without any interruption
using promesa
✔ changes state (80ms)
[foo.components.views/article ...]
✔ asserts click behaviour
✔ contains the title
✔ asserts against ratom updates
10 passing (152ms)
1 pending
In previous life as a JS dev, Mocha served well - it's fast, simple and flexible. I'd be curious what a CLJS native solution that had similar goals would look like...
Other things to do would be to use linkedom instead of JSDom, look into a better assertion library than assert
etc.