How to Make Code of Algo.js Run in Node.js as in Browser

I have planed to run unit test by reading file as the input for algorithm like graph algorithm for a few months (see issue #18). However, it is not easy or effective to read local file from browser, even using FileReader in JavaScript. An alternative way is that we can read file using the file system of Node.js, where we write JavaScript code as in browser.

So the top proiority is making codes run appropriately in Node.js as they run in browser, including the codes of unit tests. I am going to tell the details of this process today:

  • Making codes of algorithm work in Node.js, and
  • Making codes of unit tests work in Node.js, and
  • Introduce CI into my project.

本文描述了我让代码在浏览器和Node.js两边都能运行的过程,略属娱乐。因为就项目 Algo.js 而言,我认为,重点在算法( Algorithm )。至于引入大文本输入测试(参见 issue #18 ),是为了保证算法的正确和高效,以及今后的重构,当然这也很重要。引入持续集成,是尽可能想让一切都是自动化。

window and global

In browser, we have the global variable named window , Array is window.Array, and Math is window.Math, etc. The Algo.js also plugs object into window:

(function (sorting, undefined) {
    sorting.mergeSort = function () {};
})(window.Sorting = window.Sorting || {})

So that we can sort an array in browser using the script below:

Sorting.mergeSort(3, 1, 4, 1, 5, 9, 2, 6);

More than that, in Algo.js, I extend Array and Math directly:

(function (array, undefined) {
    array.zip = function (a, b) {};
    array.prototype.clone = function () {};
})(window.Array = window.Array || {})

It is not a good practice that we change the object in window directly. But in my opinion, the most important part in Algo.js is Algo(rithm), not js. So I just want to use a simple way, instead of introducing a global module named like Algo which we have to write like this:

Algo.Sorting.mergeSort();
Algo.Array.zip();
Algo.Array.clone();

Following this idea of simplification, I load the code of algorithm into the global variable in Node.js named global (see ./qunit/q.js):

window = global;

require('../src/t.js')
require('../src/x.array.js');
require('../src/sorting.js');

Look, we give the global an alias name at first, so that we do not need to change any codes of algorithm. Again, my idea of simplification is that:

It is not a good practice that we change the object in global directly. But the most important part in Algo.js is Algo(rithm), not js.


By the way, I did try to exposure module using module.exports, but I failed to figure out a way, in Node.js, to exposure ONLY one module named Sorting from three files: sorting.js, sorting.mergeSort.js, and sorting.quickSort.js as they are something like partial class.

node-qunit

After loading objects of algorithm into global, we are going to find out how to run previous codes of unit test in Node.js without modifying test scripts.

We use the project node-qunit, which allow us to run unit test like this:

$ cd algo-js
$ npm install node-qunit
$ node # or nodejs in ubuntu
> require('./qunit/q.js'); /*loading algorithm code into global*/
> var qunit = require('qunit');
> qunit.run({
>>>>> code: './qunit/q.js',
>>>>> tests: ['./qunit/q-sorting.js']},
>>>>> function (err, report) {
>>>>> 	console.log(err ? err : report);
>>>>> });

Grunt

Grunt, as it says, is a JavaScript task runner. If you configure your project, you will run unit test using command below which helps us use Continuous Integration: $ grunt test.

We use grunt-node-qunit plugin for grunt task, which is Grunt task running node-qunit.

Here is the list of How to:

  1. configure project’s package.json file

    $ npm init
    
  2. install grunt-cli

    $ npm i -g grunt-cli
    
  3. add grunt dependencies into project (see official docs)
  4. install grunt

    $ npm i grunt --save-dev
    
  5. add Gruntfile.js to resister task

    module.exports = function (grunt) {
       grunt.initConfig({task-name: {}});
       grunt.loadNpmTasks('grunt-node-qunit');
       grunt.registerTask('default', ['task-name']);
    };
    
  6. add test script into package.json, which allow us to run $ npm test
  7. run $ grunt to test the configuration
  8. run $ grunt --stack to debug grunt task script
  9. run $ npm test to test package.json configuration


A little attention we should pay on is we may face an error on ubuntu says:

/usr/bin/env: node: No such file or directory

See here to fix it.

Drone.io

Build Status

The web drone.io is an online CI service. There are other options of online CI. Some advantages of drone.io are:

The CI command for Algo.js is:

npm -d install
npm install -g grunt-cli
npm test

Next

I am going to fix issue #18.