statgen / locuszoom

A Javascript/d3 embeddable plugin for interactively visualizing statistical genetic data from customizable sources.
https://statgen.github.io/locuszoom/
MIT License
156 stars 29 forks source link

Mocha testing #5

Closed Frencil closed 8 years ago

Frencil commented 8 years ago

Unit Testing with Mocha

Overview

This branch introduces Mocha as an automated testing framework for the project. Mocha was selected over other Javascript automated testing frameworks due to its more robust built-in asynchronous and promise support, in addition to ease of implementation.

Integration

In this branch Mocha has been integrated into the Gulp build process such that all Mocha tests will be run before concatenation of application code, and said application will be skipped if any tests fail.

There is a node package for Gulp/Mocha integration that's now in play and the developer installation documentation has been updated to include it.

Tests live in the test directory, which is where Mocha is configured to check by default. It will, by default, run ever javascript file it finds in this directory.

New Considerations

ES 5.x only!

Since Gulp runs in a Node.js environment, not a browser, all automated tests (and therefore the app itself) need to be ES5.x compliant. ES6 features may work in a handful of browsers, such as several recent versions of Chrome, but these will fail in automated tests. This harkens back to earlier discussion about ES6 support for the library and is probably a good thing to keep things ES5.x only for now, for wider support.

As a result there may be some existing functional features in LocusZoom that are ES6 only, and these may create issues when building automated tests. A good example of this was the LocusZoom.formatPosition function which was using Math.log10(), an ES6-only method. Fortunately the same functionality can be achieved with other ES5 Math object functions.

LocusZoom.js is now a Module

Before this branch LocusZoom.js was fully procedural: create a LocusZoom object and begin hanging properties and methods off of it. This works in a browser but not so in a Gulp/Node run-time environment. so it had to be refactored as a module, like so:

(function(exports){
    "use strict";
    exports.foo = "bar";
    exports.method = function("baz"){
    };
})(this.LocusZoom = {});

Note that only the base file needed to be refactored this way. All other application classes, which hang more properties and methods off of the LocusZoom singleton, still work in all environments.

Functional Programming

Now that we've established an automated testing workflow it will be important to consider how we architect the library moving forward. I'd like to migrate to more functional patterns where possible, such that the most common implementation of a method does as little as possible with outside state (e.g. take arguments, do stuff, spit out a result, and do the same thing every time for the same arguments). This will make automated test development an order of magnitude simpler, but may be difficult to implement and maintain across the library.

Initial Tests and Moving Forward

The initial suite of tests in this branch are incredibly basic and serve as a proof of concept. Essentially we test that the LocusZoom singleton is created and has certain properties that should be present. We then do one actual test on the LocusZoom.formatPosition method, since it's far more "functional" than other methods and thus lends itself to easy test authoring.

Moving forward we'll want to consider refactoring existing code to be more functional (as described above) and also consider expanding the tests into multiple suites to run in series; perhaps building a suite focused on each application class.

Review and Merging

This branch could certainly use some review to make sure the conventions it establishes are agreeable moving forward and not restrictively flawed. It would also be good to get confirmation from one other dev that the installation of the toolchain works and the existing tests pass. Other than that, it should be good to merge as-is.