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
exports
object.
And then, exports
is returned by require
:
module.exports
is the object that's actually returned as the result of arequire
call.
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 thevar
keyword, 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 require
s your math file.