I am currently setting up some mocha tests using Node and in general they work. I now came across a problem I am not able to resolve.
I have a JS file containing the following: MyClass.js
(General CoffeeScript output for class MyClass
+ constructor: ->
)
EDIT: This is browser code, I just want to use Node to test it. (Is that even desirable?)
(function() {
window.MyClass = (function() {
function MyClass() {
// Do something cool here
}
return MyClass;
})();
}).call(this);
I now require MyClass.js in my test file. Once I run it, it directly throws an error
Testfile:
var myclass = require('MyClass.js');
...
describe('MyClass', function() { ... });
Error:
ReferenceError: window is not defined.
So far, I understand why this is happening, window does not exist in Node. But I cannot e up with a solution. I actually do not need the real window
object specifically, so I thought mocking it would be enough. But it is not...
var window = {},
myclass = require('myclass.js');
...
describe('MyClass', function() { ... });
This mand is also not helping: $ mocha --globals window
I still end up with the same error. Any idea is much appreciated!
I am currently setting up some mocha tests using Node and in general they work. I now came across a problem I am not able to resolve.
I have a JS file containing the following: MyClass.js
(General CoffeeScript output for class MyClass
+ constructor: ->
)
EDIT: This is browser code, I just want to use Node to test it. (Is that even desirable?)
(function() {
window.MyClass = (function() {
function MyClass() {
// Do something cool here
}
return MyClass;
})();
}).call(this);
I now require MyClass.js in my test file. Once I run it, it directly throws an error
Testfile:
var myclass = require('MyClass.js');
...
describe('MyClass', function() { ... });
Error:
ReferenceError: window is not defined.
So far, I understand why this is happening, window does not exist in Node. But I cannot e up with a solution. I actually do not need the real window
object specifically, so I thought mocking it would be enough. But it is not...
var window = {},
myclass = require('myclass.js');
...
describe('MyClass', function() { ... });
This mand is also not helping: $ mocha --globals window
I still end up with the same error. Any idea is much appreciated!
Share Improve this question edited Dec 19, 2013 at 13:41 pabera asked Dec 19, 2013 at 13:22 paberapabera 1,0421 gold badge13 silver badges22 bronze badges 3- Why exactly do you need the window object? – Seimen Commented Dec 19, 2013 at 13:25
- Otherwise I would not be able to call it from somewhere else since it is wrapped. MyClass itself is created for the browser though, I was just thinking about using Node to test it (I also tried to use jsdom or something similar but I also did not succeed) – pabera Commented Dec 19, 2013 at 13:36
-
by using
var window
, you make window a local variable. What we want is a global variable. I've triedwindow = {}
and it looks like it could work this way. – Torsten Robitzki Commented Jan 10, 2014 at 16:28
5 Answers
Reset to default 3 +50You don't actually want the window object, what you want is the global object. Here is some code that can get it in the browser (in which case it will be the same as 'window') or in node (in which case it will be the same as 'global').
var global = Function('return this')();
Then set things on that rather than on 'window'.
Note: there are other ways of getting the global object, but this has the benefit that it will work inside strict mode code too.
With following code you can use your class-like object in web-browser environment and Node.js without modification. (Sorry, I don't know how to translate that to CoffeeScript)
(function (exports) {
var MyClass = (function() {
function MyClass() {
// Do something cool here
}
return MyClass;
})();
exports(MyClass);
})(function (exported) {
if (typeof module !== 'undefined' && module.exports) {
module.exports = exported;
} else if (typeof window !== 'undefined') {
window.MyClass = exported;
} else {
throw new Error('unknown environment');
}
});
As you already have a scope which doesn't pollute global name-space, you could reduce it to:
(function (exports) {
function MyClass() {
// Do something cool here
}
exports(MyClass);
})(function (exported) {
// see above
});
I'm not an expert in AMD, require.js and other module loaders, but I think it should be easy to extend this pattern to support other environments as well.
Edit
In a ment you said that the above solution is not working when translated back to CoffeeScript. Therefore, I suggest another solution. I haven't tried it but maybe this could be a way to solve your problem:
global.window = {}; // <-- should be visible in your myclass.js
require('myclass.js');
var MyClass = global.window.MyClass;
describe('MyClass', function() {
var my = new MyClass();
...
});
It's a horrible piece of code, but if it works, maybe for testing purposes it's sufficient.
Due to the module loading behaviour of node.js this only works if your require('myclass.js')
is the first require of this file in the node process. But in case of testing with Mocha this should be true.
1) What you are looking for is the module.exports
to expose things in Node:
http://openmymind/2012/2/3/Node-Require-and-Exports/
2) Also you don't need IIFE in Node, you can drop the (function() {...
3) You can alway look at some popular Node repo on Github to see examples, look at the Mocha code since you're using it, you'll learn a thing or two.
Something like jsdom is lighter than PhantomJS and yet provides quite a few things you need to test code that expects to be running with a proper window
. I've used it with great success to test code that navigates up and down the DOM tree.
You ask:
This is browser code, I just want to use Node to test it. (Is that even desirable?)
It is very desirable. There's a point at which a solution like jsdom won't cut it but as long as your code is within the limit of what jsdom handles, might as well use it and keep the cost of launching a test environment to the minimum needed.
@hgoebl: As I'm not the OP, I can not add his original CoffeeScript code, but here is my example:
pubsub.coffee:
window.PubSub = window.PubSub || {}
PubSub.subscribe = ( subject, callback )->
now the test:
assert = require "assert"
pubsub = require './pubsub.coffee'
describe "pubsub.http interface", ->
it "should perform a http request", ->
PubSub.subscribe 1, 2
what works for me up to now is:
window.PubSub = window.PubSub || {}
window.PubSub.subscribe = ( subject, callback )->
and the test:
`window = {}`
assert = require "assert"
pubsub = require './pubsub.coffee'
describe "pubsub.http interface", ->
it "should perform a http request", ->
window.PubSub.subscribe 1, 2
The main drawback of the solution, is that I have to explicitly mention the window object in the implementation and the test. User code executed in a browser should be able to omit it.
I now came up with an other solution:
window = window || exports
window.PubSub = window.PubSub || {}
PubSub = PubSub || window.PubSub
PubSub.subscribe = ( subject, callback )->
and then in the test, simply requiring the PubSub namespace:
PubSub = require( './pubsub.coffee' ).PubSub
And finally, the solution from kybernetikos applied looks like this:
global = `Function('return this')()`
global.PubSub = global.PubSub || {}
PubSub.subscribe = ( subject, callback )->
As now, the PubSub namespace is in the global namespace, just a simple require is needed in the file that contains the mocha tests:
require( './pubsub.coffee' )