Using ClojureScript for Cordova app development is described in a previous post. This post will expand on how to do live reloading when code changes and also writing JavaScript unit tests with QUnit. Sample code structure is given below.

example-cordova-app
├── Gruntfile.js
├── config.xml
├── hooks
├── node_modules
├── package-lock.json
├── package.json
├── platforms
│   └── browser
│       ├── browser.json
│       ├── ...
├── plugins
├── res
├── example-cordova-cljs
│   ├── out
│   ├── project.clj
│   ├── resources
│   ├── src
│   │   └── my_app
│   │       └── core.cljs
│   ├── target
│   └── test
│       └── my_app
│           └── core_test.clj
└── www
    ├── css
    │   └── style.css
    ├── img
    ├── index.html
    ├── js
    │   ├── app.js
    │   ├── libs
    │   ├── main.js
    └── test
        ├── qunit.css
        ├── qunit.js
        ├── test.html
        └── tests.js

We can use browser platform to do quick testing during development and cordova-plugin-browsersync to do live reloading of www folder.

1. Install cordova-plugin-browsersync.

cordova plugins add cordova-plugin-browsersync

2. Once the plugin is installed, we can start the watcher from terminal.

cordova run browser -- --live-reload

When ClojureScript changes, it compiles and places the file into www, and the above plugin will detect the change and do a reload. Refresh the browser and the latest code changes will be reflected. This is also useful when we mix JavaScript and ClojureScript.

Unit Testing with QUnit

We can write ClojureScript test, which is a different workflow. Place test scripts under www/test folder. A sample test.html is shown below.

<!doctype html>
<html>
<head>
    <link rel="stylesheet" type="text/css" href="qunit.css">
    <script type="text/javascript" src="qunit.js"></script>
    <script type="text/javascript" src="tests.js"></script>
    <title>Testsuite</title>
</head>
<body>
    <div id="qunit"></div>
    <div id="qunit-fixture"></div>
</body>
</html>

Test scripts can go to test.js.

// test.js
if (document.loaded) {
    test();
} else {
    window.addEventListener('load', test, false);
}

function test() {
    QUnit.module("test");
    QUnit.test("Example", function (assert) {
        assert.ok(true, "ok is for boolean test");
        assert.equal(1, "1", "comparison");
    });
}

We will use grunt to run these tasks. Add both live reload and unit test tasks in Gruntfile.js.

module.exports = function(grunt) {
    grunt.initConfig({
        pkg: grunt.file.readJSON('package.json'),
        qunit: {
            files: ['www/test/**/*.html']
        },
        exec: {
            start: {
                command: 'cordova run browser -- --live-reload'
            }
        }
    });

    grunt.loadNpmTasks('grunt-contrib-qunit');
    grunt.loadNpmTasks('grunt-exec');

    grunt.registerTask('test', ['qunit']);
    grunt.registerTask('start', ['exec:start']);
};

The required dependencies added to package.json follows.

{
    "name": "net.jsloop.example.app",
    // ...
    "main": "main.js",
    "scripts": {
        "start": "cordova run browser -- --live-reload",
        "test": "grunt test"
    },
    "dependencies": {
        "browser-sync": "^2.23.6",
        "cordova-browser": "^5.0.3",
        "cordova-plugin-browsersync": "^1.1.0",
        "cordova-plugin-whitelist": "^1.3.3",
        // ...
    },
    "cordova": {
        "plugins": {
            "cordova-plugin-whitelist": {},
            "cordova-plugin-browsersync": {}
        },
        "platforms": [
            "browser"
        ]
    },
    "devDependencies": {
        "grunt": "^1.0.2",
        "grunt-contrib-qunit": "^2.0.0",
        "grunt-exec": "^3.0.0"
    }
}

The tasks start, test are available as grunt task and we can link main ones to npm as well.

# grunt
grunt start  # start watcher
grunt test   # run testsuite
# npm
npm start
npm test