Im writing a series of coffeescript files for doing math operations and I need to write some tests. I figure that mocha and chai are the way to go. At the moment, Im using the namespace method to group all my separate functions together in order to keep things tidy:
namespace = (target, name, block) ->
[target, name, block] = [(if typeof exports isnt 'undefined' then exports else window), arguments...] if arguments.length < 3
top = target
target = target[item] or= {} for item in name.split '.'
block target, top
exports? exports.namespace = namespace
The thing I'd like to test at the moment is my matrix class, which looks a little like this:
namespace "CoffeeMath", (exports) ->
class exports.Matrix4
for name in ['add', 'subtract', 'multiply', 'divide', 'addScalar', 'subtractScalar', 'multiplyScalar', 'divideScalar', 'translate']
do (name) ->
Matrix4[name] = (a,b) ->
a.copy()[name](b)
Matrix4.DIM = 4
# Take a list in column major format
constructor: (@a=[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1]) ->
# etc etc ...
Now compiling all this up with the lovely coffeescript compiler is all well. I have a test like this:
chai = require 'chai'
chai.should()
{namespace} = require '../src/aname'
{Matrix4} = require '../src/math'
describe 'Matrix4 tests', ->
m = null
it 'should be the identity matrix', ->
m = new exports.Matrix4()
m.a.should.equal '[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1]'
The problem is, I get the following error:
node.js:201
throw e; // process.nextTick error, or 'error' event on first tick
^
ReferenceError: namespace is not defined
at Object.<anonymous> (/Users/oni/Projects/Saito.js/src/math.coffee:3:3)
at Object.<anonymous> (/Users/oni/Projects/Saito.js/src/math.coffee:631:4)
at Module._compile (module.js:441:26)
aname should be included I believe and that exports the namespace function so I cant see why namespace is not defined. Any thoughts?
From the fine manual:
To export an object, add to the special
exportsobject.
And then, exports is returned by require:
module.exportsis the object that's actually returned as the result of arequirecall.
So, when you say this:
namespace = require '../src/aname'
you have namespace.namespace available inside your test.
CoffeeScript wraps each file in a function wrapper to avoid polluting the global namespace:
all CoffeeScript output is wrapped in an anonymous function:
(function(){ ... })();This safety wrapper, combined with the automatic generation of thevarkeyword, make it exceedingly difficult to pollute the global namespace by accident.
This means that you have something like this in the compiled JavaScript:
(function() {
exports.namespace = ...
})();
(function() {
# Matrix4 definition which uses the 'namespace' function
})();
(function() {
var namespace = ...
})();
The result is that namespace is not visible where you define Matrix4 since the test and Matrix4 exist in separate functions and thus separate scopes.
If you want to use namespace inside your math file, then you'll have to require it there rather in the code that requires your math file.