A disturbing amount of open (and closed) source javascript projects that I’ve worked on are severely lacking in tests, whether unit or otherwise. Of course, I do find time to click around the apps and make sure they basically work, and while I find that works for smaller apps, it’s obvious that if you want long-term stability, and any one to even take a look at your app, one of the most basic requirements is having properly functioning tests.
Also, to put it frankly, a lack of tests in 2016 (Happy new years, by the way), is just a mark of inexperience. To embark on a software-building experience these days without taking some time to write unit/integration/acceptance tests is like hunting Moby Dick without bringing along any life vests. Yes, you might spear the beast a few times, but you’re going to feel not-so-good when she inevitably breaks your ship in half and you didn’t bring along anything to make swimming easier.
I fully realize that while I write this, Firegraph stands without nary a test to it’s name. I’ll get to it, I promise, I’m just an inexperienced programmer :).
To make this not the case for my newest project, I created an actual Github issue (tied to the first release milestone, of course) to add proper tests (at least unit tests) to the project. As I embarked on this today, I really began to realize how much I’d forgotten about testing. At one point in my career, I was (or at least felt) acutely aware of how Jasmine, Mocha, PhantomJS/NightmareJS, all fit together, and which parts of the browser/nodejs were involved in using these frameworks. This time, however, I’m working with a JSPM project, and was actually almost completely unsure how everything really fit together.
For those who might not be quite up to speed:
To successfully use two technologies like Mocha and JSPM together often requires knowing some of the quirks and real from-scratch use models of both technologies, and the borders that have to be merged/mended to allow them to work harmoniously. This is where frameworks that do everything for you, or even just scaffold things for you tend to let you down, sometimes you need to be able to recreate such an atmosphere from scratch. I had just a tad bit of trouble even getting mocha installed for this project as well as realizing it was what I wanted to use over something like Jasmine (which is more for a browser-context).
After re-acclimating myself to Mocha (and remembering how much I liked their “nyan” reporter when I first saw it), I embarked on the google knowledge quest to merge these two things together. Here’s the step-by-step I was trying to complete
Getting started with Mocha and JSPM
test/
directorytest/test.js
file that will contain the actual testing codeWhile the first two issues were easy, the third one threw me for a little loop. Since JSPM handles transpilation with Babel (the ES6/ES2015 transpiler) manually, it was a bit of a thinking exercise to figure out whether I needed to transpile everything manually. The first thought that popped into my head was that since Mocha was NodeJS based, all I needed to do was add the --harmony
flag to some node invocation somewhere, and everything would be fine. Of course, mocha did in fact support the --harmony
flag, but it wasn’t quite what I expected. The *actual* solution was to install a special babel compiler for mocha, babel-register
, and use that when I ran mocha. So roughly the solution ended up looking like:
$ npm install --save-dev babel-register $ mocha --compilers js:babel-register
Of course, I added that to the test
script in package.json
(while using the locally installed version of mocha in ./node_modules/.bin
).
Setting up the SystemJS dependencies was the next difficulty to overcome. It’s hard to test a file that includes ES6/ES2015 imports that can’t be resolved, due to the glue that SystemJS provides not being set up properly. Luckily, SystemJS provides a relatively easy-to-use javascript API. This meant that I could include something like this in my code to start getting things to compile somewhat properly:
import "should"; import _ from "lodash"; import System from "systemjs"; // Importing SystemJS code import "../config"; // Importing the same SystemJS config the app is using ... Actual test code ...
This got me a little further, but I ran into a problem when I started using SystemJS as follows:
describe("Some thing", () => { it("Should expose the right stuff", done => { SystemJS.import("./package") .then(pkg => { // Do some stuff }) .catch(done); }); });
I was finding that the imports weren’t being resolved properly, but that was because the config that was loading was somehow deriving file paths that started from the base of the file system. This means paths like file:///jspm_packages/package/lib/package
were being checked, and of course, this translated to checking the root file system for a folder called “jspm_packages”, when of course all you find there is things like “usr” and “home” and “var”.
The fix for this happened to be relatively painless (though it introduced quite some worry and anxiety initially): Changing the SystemJS config to use a relative path for the baseURL config property:
... Somewhere in config.js ... baseURL: "./", // Changed from "/" ... the rest of config.js ...
After that fix, I could run tests properly. Here’s what the code ended up looking like:
mport System from "systemjs"; import "../config"; import "should"; import _ from "lodash"; const EXPECTED_CONSTANTS = [ "SOME", "LIST", "OF", "CONSTANTS" ] describe("Project constants", () => { // Ensure that the generated constants export contains the functions we expect it("Should contain all the constants we expect", (done) => { System.import("./js/constants") // note this is relative to top level project folder, not test file .then(constants => { constants.default.should.have.keys(EXPECTED_CONSTANTS); // note here that I had to access the default export done(); }) .catch(done); }); });
With this test saved in the tests/
folder, I ran mocha with the following command:
./node_modules/.bin/mocha --compilers js:babel-register -R nyan
And all of a sudden I had a functioning test!
I’m sure this will get more difficult once I start trying to add acceptance tests (and using Phantom/Nightmare), but for now, it’s nice to know the project has one (possibly useless and pointless) test.