doo is a library and lein plugin to run cljs.test on different js environments.
Clojure JavaScript Shell
Clone or download

README.md

doo

CircleCI Build status Clojars Project

A library and Leiningen plugin to run cljs.test in many JS environments. For Boot plugin, see boot-cljs-test.

...and I would have gotten away with it, too, if it wasn't for you meddling kids.

The latest stable release:

{:plugins [[lein-doo "0.1.10"]]}

To use doo you need to use [org.clojure/clojurescript "0.0-3308"] or newer.

Usage

Plugin

All arguments are optional provided there is a corresponding default under :doo in project.clj:

lein doo

lein doo {js-env}

lein doo {js-env} {build-id}

lein doo {js-env} {build-id} {watch-mode}
  • js-env can be any chrome, chrome-headless, firefox,firefox-headless, ie, safari,opera, slimer, phantom, node, rhino, nashorn, lumo, or planck. In the future it is planned to support v8, jscore, and others.
    • Note that chrome-headless requires karma-chrome-launcher >= 2.0.0 and Chrome >= 59
    • Note that firefox-headless requires karma-firefox-launcher >= 1.1.0 and Firefox >= 56
  • watch-mode (optional): either auto (default) or once which exits with 0 if the tests were successful and 1 if they failed.
  • build-id is one of your cljsbuild profiles. For example test from:
:cljsbuild
  {:builds [{:id "test"
             :source-paths ["src" "test"]
             :compiler {:output-to "resources/public/js/testable.js"
                        :main your-project.runner
                        :optimizations :none}}]}

Notice that :main is set to the namespace your-project.runner where you define which test namespaces you want to run, using:

(ns your-project.runner
    (:require [doo.runner :refer-macros [doo-tests]]
              [your-project.core-test]
              [your-project.util-test]))

(doo-tests 'your-project.core-test
           'your-project.util-test)

doo.runner/doo-tests works just like cljs.test/run-tests but it places hooks around the tests to know when to start them and finish them. Since it is a macro that will be calling said namespaces, you need to require them in your-project.runner even if you don't call any of their functions. You can also call (doo.runner/doo-all-tests) which wraps cljs.test/run-all-tests to run tests in all loaded namespaces. Notice that doo-tests needs to be called in the top level and can't be called inside a function (unless you explicitly call that function in the top level).

Then you can run:

lein doo slimer test

which starts an ClojureScript autobuilder for the test profile and runs slimerjs on it when it's done.

You can also call doo without a build-id (as in lein doo phantom) as long as you specify a Default Build in your project.clj.

Boot

doo is packaged as a Boot task in boot-cljs-test.

Library

To run a JavaScript file in your preferred runner you can directly call doo.core/run-script from Clojure:

(require '[doo.core :as doo])

(let [doo-opts {:paths {:karma "karma"}}
      compiler-opts {:output-to "out/testable.js"
                     :optimizations :none}]
  (doo/run-script :phantom compiler-opts doo-opts))

You can run doo.core/run-script with the following arguments:

(run-script js-env compiler-opts)
(run-script js-env compiler-opts opts)

where:

  • js-env - any of :phantom, :slimer, :node, :rhino, :nashorn, :lumo, :planck, :chrome, :chrome-headless, :firefox, :firefox-headless,:ie, :safari, or :opera
  • compiler-opts - the options passed to the ClojureScript when it compiled the script that doo should run
  • opts - a map that can contain: :verbose - bool (default true) that determines if the scripts output should be printed and returned (verbose true) or only returned (verbose false). :debug - bool (default false) to log to standard-out internal events to aid debugging :paths - a map from runners (keywords) to string commands for bash. :exec-dir - a directory path (file) from where runner should be executed. Defaults to nil which resolves to the current dir

Setting up Environments

This is the hardest part and doo doesn't do it for you (yet?). Right now if you want to run slimer, phantom, node or nashorn that ships with the JDK 8, you need to install them so that these commands work on the command line:

phantomjs -v

slimerjs -v

node -v

jjs -h

rhino -help

lumo -h

planck -h

If you want to use a different command to run a certain runner, see Paths.

Remember that Rhino and Node don't come with a DOM so you can't call the window or document objects. They are meant to test functions and logic, not rendering.

Slimer & Phantom

If you want to run both, use lein doo headless {build-id} {watch-mode}.

Do not install Slimer with homebrew unless you know what you are doing. There are reports of it not working with ClojureScript when installed that way because of dated versions.

Note: Slimer does not currently throw error exit codes when encountering an error, which makes them unsuitable for CI testing.

Node

Some requirements:

  • Minimum node version required: 0.12
  • :output-dir is needed whenever you are using :none.
  • :target :nodejs is always needed.
:node-test {:source-paths ["src" "test"]
            :compiler {:output-to "target/testable.js"
                       :output-dir "target"
                       :main example.runner
                       :target :nodejs}}

Karma

Installation

Karma is a comprehensive JavaScript test runner. It uses plugins to extend functionality. We are interested in several "launcher" plugins which start a browser on command. You might want any of:

- karma-chrome-launcher
- karma-firefox-launcher
- karma-safari-launcher
- karma-opera-launcher
- karma-ie-launcher

Alternatively, if you don't want doo to launch the browsers for you, you can always launch them yourself and navigate to http://localhost:9876

We also need to properly report cljs.test results inside Karma. We'll need a "framework" plugin:

- karma-cljs-test

Karma and its plugins are installed with npm. It is recommended that you install Karma and it's plugins locally in the projects directory with npm install karma --save-dev. It is possible to install Karma and its plugins globally with npm install -g karma, but this is not recommended. It is not possible to run mix local and global Karma and Karma plugins.

Karma provides a CLI tool to make running Karma simpler and to ease cross platform compatibility. doo uses the CLI tool as the default runner, if you don't install it you will need to configure doo.

For local installation run:

npm install karma karma-cljs-test --save-dev

and install the Karma CLI tool globally with

npm install -g karma-cli

then install any of the launchers you'll use:

npm install karma-chrome-launcher karma-firefox-launcher --save-dev
npm install karma-safari-launcher karma-opera-launcher --save-dev
npm install karma-ie-launcher --save-dev

The --save-dev option informs npm that you only need the packages during development and not when packaging artifacts.

The installation will generate a node-modules folder with all the installed modules. It is recommended to add node-modules to your .gitignore.

If you are using lein-npm, follow their instructions.

Measuring coverage with Istanbul

It's possible to generate Istanbul coverage reports for JS files produced from CLJS.

To make it work two things are required.

Install your karma coverage plugin.

npm install karma-coverage --save-dev

Add coverage seetings to your project.clj

:doo {:coverage {:packages [my-app.module]
                 :reporter {:check {:global {:statements 100}}}}}

Packages section is essential, it enables coverage cofiguration and defines which files would have coverage instrumentation.

By default HTML reporter is enabled which creates coverage folder with the report and there are no coverage reqirements.

Anything under :reporter is passed as coverageReporter config to Karma config.

See Karma coverage for more details. See Reagent covered for a sample project configuration.

Non-standard Karma configuration

If you are using a local installation and/or node_modules is not located at the project root, you need to tell doo about it. Add this to your project.clj:

:doo {:paths {:karma "path/to/node_modules/karma/bin/karma"}}

:cljsbuild { your-builds }

and make sure that the file karma/bin/karma exists inside node_modules. If your package.json and node_modules folder are in the same directory than your project.clj, then you should use:

:doo {:paths {:karma "./node_modules/karma/bin/karma"}}

:cljsbuild { your-builds }

For more info on :paths see Paths.

Global installation will allow you to use karma in all of your projects. The problem is that it won't be explicitly configured in your project that karma is used for testing, which makes it harder for new contributors to setup.

In some systems (e.g. Ubuntu) you might need to run all npm commands as root: sudo npm install karma --save-dev

Karma Phantom and Karma Slimer (experimental)

To avoid starting a new Slimer/Phantom on every run while using auto, we can use Slimer/Phantom through Karma.

Install any of the launchers you'll use:

npm install karma-phantomjs-launcher --save-dev
npm install karma-slimerjs-launcher --save-dev

and call

lein doo karma-phantom test auto
lein doo karma-slimer test auto

If you are using once, the regular phantom/slimer runners are recommended.

Note: karma-slimer sometimes fails to close the running Slimer instance, which you need to close manually.

Electron (experimental)

After installing Electron install the launcher with

npm install karma-electron-launcher --save-dev

and call

lein doo electron test

Planck

Planck 2.14.0 or later is required.

Paths

You might want to use a different version of node, or the global version of Karma, or any other binary to run your tests for a given environment. You can configure that paths like so:

:doo {:paths {:node "user/local/bin/node12"
              :karma "./frontend/node_modules/karma/bin/karma"}

:cljsbuild { your-builds }

Paths can also be used to pass command line arguments to the runners:

:doo {:paths {:phantom "phantomjs --web-security=false"
              :slimer "slimerjs --ignore-ssl-errors=true"
              :karma "karma --port=9881 --no-colors"
              :rhino "rhino -strict"
              :node "node --trace-gc --trace-gc-verbose"}}

Aliases

You might want to group runners and call them from the command line. For example, while developing you might only be interested in chrome and firefox, but you also want to test with safari before doing a deploy:

:doo {:alias {:browsers [:chrome :firefox]
              :all [:browsers :safari]}}

:cljsbuild { my-builds }

Then you can use:

lein doo browsers my-build  # runs chrome and firefox

lein doo all my-build # runs chrome, firefox, and safari

As you can see, aliases can be recursively defined: watch for circular dependencies or doo will bark.

The only built-in alias is :headless [:phantom :slimer].

Default Build

To save you one command line argument, lein-doo lets you specify a default build in your project.clj:

:doo {:build "some-build-id"
      :paths { ... }
      :alias { ... }}

:cljsbuild
  {:builds [{:id "some-build-id"
             :source-paths ["src" "test"]
             :compiler {:output-to "out/testable.js"
                        :optimizations :none
                        :main example.runner}}]}

Custom Karma configuration

You can supply arbitrary configuration options to Karma under the :karma {:config {}} key. For example, if you want to use karma-junit-reporter, do this:

{:doo {:karma
       {:config {"plugins" ["karma-junit-reporter"]
                 "reporters" ["progress" "junit"]
                 "junitReporter" {"outputDir" "test-results"}}}}}

The options are merged to Doo's Karma configuration. By default, array values are merged by appending. For example, in the example above, the value of "plugins" is appended to the list of plugins needed by Doo. Merging is implemented with meta-merge, so if you need more control, you can use ^:replace and ^:prepend metadata.

Custom Karma launchers

To add custom Karma launchers (eg. as described in the Chrome Karma Plugin) you can add the following config entries to your project.clj as shown in the example below:

The plugin in the :launchers map should match an installed Karma plugin and the name should match a Karma launcher (possibly a custom one as shown in the following example). If needed, add "customLaunchers" configuration under the :config key.

You will then be able to run lein doo chrome-no-security from the comand line.

:doo {:karma
      {:launchers {:chrome-no-security {:plugin "karma-chrome-launcher"
                                        :name "Chrome_no_security"}}
       :config {"customLaunchers"
                {"Chrome_no_security" {"base" "Chrome"
                                       "flags" ["--disable-web-security"]}}}}

Travis CI

To run on travis there is a sample .travis.yml file in the example project: example/.travis.yml

(Currently only tested with PhantomJS.)

Developing

To run the tests for doo, you need to have installed rhino, phantomjs, slimer, chrome, node, and firefox. You will also need to run npm install in the library directory.

License

This project started as a repackaging of cemerick/clojurescript.test, therefore much of the credit goes to Chas Emerick and contributors to that project.

Copyright © 2016-2018 Sebastian Bensusan and Contributors.

Distributed under the Eclipse Public License either version 1.0 or (at your option) any later version.