Run ClojureScript tests with Kaocha. New and improved.
kaocha-cljs2 is part of a growing collection of quality Clojure libraries and tools released on the Lambda Island label. If you are using this project commercially then you are expected to pay it forward by becoming a backer on Open Collective, so that we may continue to enjoy a thriving Clojure ecosystem.
Running ClojureScript tests is fundamentally different from running Clojure tests in two ways: ClojureScript needs to be compiled first, and then it needs to run inside a JavaScript environment like Node.js or a browser.
So there is a certain amount of preparation needed. First something invokes the ClojureScript compiler, which outputs JavaScript, then something needs to launch a JavaScript runtime (a browser, Node), and make sure that JavaScript gets loaded into it.
Finally Kaocha needs to establish communication with that runtime, so that it can invoke tests and collect results.
In the original kaocha-cljs
we tried to do all of that. We relied on the
ClojureScript repl-env
abstraction to do compilation behind the scenes, and to
launch a browser tab or node process, and communicate with it.
In kaocha-cljs2
we have chosen a different approach. We no longer care about
how you compile your ClojureScript or how you launch your runtime. You can
automate that or do it manually, but it's your concern. We will of course
provide examples for common tools and use cases.
This means that we are forward compatible with any ClojureScript build tool,
current or future. We also no longer care about compiler settings like the
optimization level or how you manage dependencies and third party JavaScript.
All we ask is that you include a :preload
in your build, so that we are able
to communicate with it.
Because we have separated the different responsibilities to separate projects, it does make it a little harder to keep track. These are the different pieces involved.
Extensible test runner. Written in Clojure, so runs on the JVM. Can run test suites of many different types. Has CLI and REPL interfaces, and can be customized with plugins.
Test runner written in ClojureScript. Consists of:
chui-core
: which provides the test runner logic and APIchui-ui
: which provides a browser-based UI, andchui-remote
: which connects to and interact with Funnel. By adding the remote to your ClojureScript build you allow it to talk to kaocha-cljs2. Using the UI is optional.
Stand-alone WebSocket message relay. Funnel runs in the background and acts as a
communication hub, providing discoverability (which chui-remote
processes are
connected?), and enabling communication between chui-remote
and
kaocha-cljs2
.
A Kaocha test suite type for ClojureScript test suites. Makes the Kaocha ecosystem of tooling available to ClojureScript.
When you ask kaocha to run tests of type :kaocha.type/cljs2
, it
would delegate to the implementation of kaocha-cljs2
, which
would connect to funnel and forward the tests to chui-remote (which
runs in the browser or nodejs).
┌──────────────────────────────┐
│ KaoCha │
│ ┌─────────────────┤
│ │ kaocha-cljs2 │
└────────────┴─────────────────┘
│
▼
┌──────────────────────────────┐
│ Funnel │
└──────────────────────────────┘
▲
│
│
┌────────────┬────────────────┐
│ Browser │chui-remote │
│ ├────────────────┤
│ │chui test-runner│
│ └────────────────┤
└─────────────────────────────┘
;; deps.edn
lambdaisland/kaocha-cljs2 {:mvn/version "0.2.72"}
;; project.clj
[lambdaisland/kaocha-cljs2 "0.2.72"]
Kaocha-cljs2 relies on Funnel, a websocket message relay, for communicating with the JavaScript runtime.
Follow the instructions for installing and running
Funnel. We recommend starting Funnel
in a separate terminal and to leave it running indefinitely. Start it with -vv
initially so you can see what's going on.
./funnel -vv
INFO [lambdaisland.funnel] {:started ["ws://localhost:44220" "wss://localhost:44221"], :line 328}
Add lambdaisland.chui.remote
as a
preload to your
ClojureScript compiler configuration. This will cause ClojureScript to "phone
home" when it gets loaded.
Where this goes exactly depends on the build tool you are using. You are looking
for a map containing keys like :output-to
, :main
, or :optimizations
.
{;; :main foo.bar ....
:preloads [lambdaisland.chui.remote]}
Here is an example shadow-cljs configuration:
{:builds
{:test-kaocha {:target :browser-test
:runner-ns kaocha.cljs2.shadow-runner
:test-dir "target/kaocha-test"
:ns-regexp ".*-test$"
:devtools {:http-port 1818
:http-root "target/kaocha-test"
:preloads [lambdaisland.chui.remote]}}}}
Now verify that your ClojureScript build is "phoning home". Compile it and run
it (in a browser, node, ...) and look for a :connection-opened
message in the
output from Funnel.
;; tests.edn
#kaocha/v1
{:tests [{:type :kaocha.type/cljs2}]}
In principle this is all you need, this will look for any connected
chui-remote
clients in the same project directory, so that if you are working
on multiple projects we connect to and run the tests from the right project.
To do this the current working directory gets injected into the ClojureScript build, so if you are running the ClojureScript compiler from a separate process then make sure it's running in the same directory where you are running Kaocha.
If you want Kaocha to kick off the ClojureScript compilation, and to launch a JavaScript runtime, then it's recommended you do this with a before hook.
#kaocha/v1
{:plugins [:kaocha.plugin/hooks]
:tests [{:type :kaocha.type/cljs2
:kaocha.hooks/before [my.kaocha.hooks/compile-and-launch]}]}
See the examples directory and this repository for specific examples.
When kaocha-cljs2 starts executing it will try to find chui-remote
clients to
talk to. If there are none it will wait for a client to connect before
continuing. If there are multiple then it will run tests against all of them.
You can change this behavior by supplying a :kaocha.cljs2/clients-hook
. This
needs to be fully qualified symbol pointing at a function which takes a test
suite map and returns a collection of :funnel/whoami
maps.
Everyone has a right to submit patches to kaocha-cljs2, and thus become a contributor.
Contributors MUST
- adhere to the LambdaIsland Clojure Style Guide
- write patches that solve a problem. Start by stating the problem, then supply a minimal solution.
*
- agree to license their contributions as MPL 2.0.
- not break the contract with downstream consumers.
**
- not break the tests.
Contributors SHOULD
- update the CHANGELOG and README.
- add tests for new functionality.
If you submit a pull request that adheres to these rules, then it will almost certainly be merged immediately. However some things may require more consideration. If you add new dependencies, or significantly increase the API surface, then we need to decide if these changes are in line with the project's goals. In this case you can start by writing a pitch, and collecting feedback on it.
*
This goes for features too, a feature needs to solve a problem. State the problem it solves, then supply a minimal solution.
**
As long as this project has not seen a public release (i.e. is not on Clojars)
we may still consider making breaking changes, if there is consensus that the
changes are justified.
Copyright © 2020 Arne Brasseur and Contributors
Licensed under the term of the Mozilla Public License 2.0, see LICENSE.