Published: 05-07-2016
Get started with a bit of testing. Goes over setting up and using Mocha + Chai for some in-browser tests.
Overview
Before more features can be added it is important to put in place a method of testing. Really this should have be done already, but to gain some momentum it was put on the back-burner. There needs to be seperated ways of testing makeit-design, makeit-processor and makeit-workshop. We will first focus on testing makeit-processor.
Makeit-processor
Makeit-processor is probably the easiest to start testing straight away. It is nicely self contained. Some of the components such as the renderers require browser functionality, but apart from that all the geometry calculations can be tested raw. As the script simply attaches itself to the global object (window) it would require some modification to work in node. Using Mocha and chai we can run tests directly in the browser. Maybe not the best solution, but a nice simple one for now.
Mocha in the browser, with Chai
To get Mocha and Chai working in the browser a new test.html page is created. This page is kept outside of the public folder and loaded up in the browser directly off the disk (no webserver) to keep it separate from the app. A test directory is also created in the root folder.

<!DOCTYPE html>
<html>
  <head>
    <title>Makeit-processor Tests</title>
    <link rel="stylesheet" href="node_modules/mocha/mocha.css">
  </head>
  <body>
    <div id="mocha"></div>
    <script src="node_modules/mocha/mocha.js"></script>
    <script src="node_modules/chai/chai.js"></script>
    <script>mocha.setup('bdd')</script>

    <!-- Code to test -->
    <script src="public/app/makeit/makeit.js"></script>

    <!-- Test files -->
    <script src="test/arrayTest.js"></script>

    <script>
      mocha.run();
    </script>
  </body>
</html>

A small generic test is used to check that it runs:

var assert = chai.assert;

describe('Array', function() {
  it('should start empty', function() {
    var arr = [];

    assert.equal(arr.length, 0);
  });
});

And it seems to work:
Mocha and Chai working in browser
Tests will be written for each class exposed by makeit.js. Testing the DOM manipulation will be left for now and revisited later. There are plugins like chai-webdriver which can be used to help test the DOM. When writing Mocha tests the following structure is used:

var expect = chai.expect

describe('Top level', function () {
	it('Individual test 1', function () {
		// Testing code
	});
	it('Individual test 2', function () {
		// Testing code
	});
	
	describe('Sub level', function () {
		it('Individual test 3', function () {
			// testing code
		});
		it('Individual test 4', function () {
			// testing code
		});
	});
});

Writing a few tests
To get started a few tests will be written for the MCAD.Profile() class. They will check whether the code throws an error when constructor or method arguments are missing. Javascript doesn't force the use of arguments normally so so a function called without the correct arguments won't cause an error. The argument will instead be set to undefined which causes problems later on which are harder to debug. Essentially users should not be able to leave out arguments. We need to check whether own code will let them. We 'expect' an error if they are not present. Here is the test stub and the results.

var expect = chai.expect;

describe('CAD - Profile', function() {
	describe('Check arguments', function () {
		it('should throw error if missing constructor argument/s');
		it('should throw error if missing line argument/s');
	});
});

Test stubs
When no callback is given to the it() function it marks the test as pending. Now the test logic is entered. A new Profile() object is created without any constructor arguments. This has to be wrapped in a function so the error that is expected to be thrown is thrown inside the expect() and not before. The first test expects the new Profile() call to throw an error of type 'Error' and with the message MCAD.Profile() arguments not correct. The second test is similar but for the line() method. Argument checking hasn't been implement yet so the tests fail.

var expect = chai.expect;

describe('CAD - Profile', function() {
	describe('Check arguments', function () {
		it('should throw error if missing constructor argument/s', function () {
			var fn = function() {
				var profile = new MCAD.Profile();
			}
			expect(fn).to.throw(Error, 'MCAD.Profile() arguments not correct');
		});
		it('should throw error if missing line argument/s', function () {
			var fn = function () {
				var line = new MCAD.Profile(0,0).line();
			}
			expect(fn).to.throw(Error, 'MCAD.Profile.line() arguments not correct');
		});
	});
});

Failed test
To make the tests pass the Profile() constructor and line() method need to throw the appropriate error when the arguments are missing. This is done by throwing a standard Error object with a custom message as shown below.

constructor(x: number, y: number) {
	if (x===undefined || y===undefined) { 
		throw new Error('MCAD.Profile() arguments not correct'); 
	}
	this.last_end = {x: x, y: y};
}

public line(x: number, y: number) {
	if (x===undefined || y===undefined) { 
		throw new Error('MCAD.Profile.line() arguments not correct'); 
	}
	var dy: number = (y - this.last_end.y);
	var dx: number = (x - this.last_end.x);
	var length = Math.sqrt((dy * dy) + (dx * dx));
	var unit: [number, number] = [dx / length, dy / length];
	this.segments.push({
		type: 'line',
		start: { x: this.last_end.x, y: this.last_end.y },
		end: {x: x, y: y},
		unit: unit
	});
	this.last_end = { x: x, y: y };
	return this;
}

Passed tests
Now the tests pass and we know that should any arguments be missing an error will be encountered by the user. This could easily be expanded to checking types as well.
Side note: Running makeit-processor in node (a hacky way)
Currently makeit-processor is compiled to one file, 'makeit.js'. This file is loaded using a script tag and therefore doesn't export any modules. It therefore cannot be loaded using the commonJs 'require' loader in node. We have to create an exporting alias to modularise our tests. To get the object the script is eval'd and the objects extracted ('makeit-export.js'):

'use strict'
var fs = require('fs');
var filedata = fs.readFileSync('../public/app/makeit/makeit.js', 'utf8');
var getObjects = "\
	var g = {\
		MCAD: MCAD, \
		MCAM: MCAM, \
		Panel: Panel, \
		Render: Render \
	}; \
	g";

var e = eval(filedata + getObjects);

exports.MCAD = e.MCAD;
exports.MCAM = e.MCAM;
exports.Panel = e.Panel;
exports.Render = e.Render;


The objects have to be extracted this way because 'strict' mode is enabled and eval() will not add them the global object. The objects are then exported as normal. To check it works we 'require' 'makeit-export.js' and create a profile.

var MCAD = require('./makeit-export.js').MCAD;
var MCAM = require('./makeit-export.js').MCAM;
var Panel = require('./makeit-export.js').Panel;
var Render= require('./makeit-export.js').Render;

var profile = new MCAD.Profile(50,50);
profile.line(100,100);
console.log(profile.raw());

// [ { type: 'line',
//     start: { x: 50, y: 50 },
//     end: { x: 100, y: 100 },
//     unit: [ 0.7071067811865475, 0.7071067811865475 ] } ]


Now makeit-processor is accessible from inside node although any code that uses DOM manipulation will not work. *Edit, this was when I wasn't too familar with typescript. Now everything is written in modules and bundled together. Tests in the broswer and node are pretty much the same now.