I am currently experimenting with https://github.com/felixge/node-sandboxed-module to be able to inject dependency mocks in unit tests. Turns out this module kills should.js for the objects that are created in the sandboxed module:
myModule.js:
module.exports = {
func1: function () {
return {
'THIS': {
'IS': {
'SPARTA': {
'DONT': 'TRUST ME'
}
}
}
};
}
};
myModule-test.js:
var should = require('should');
var sandboxedModule = require('sandboxed-module');
var myModule1 = require('./myModule');
var myModule2 = sandboxedModule.require('./myModule');
describe('myModule', function () {
it('should return the object', function () {
myModule1.func1().should.be.instanceOf(Object);
});
describe('returned object', function () {
it('should have the correct properties', function () {
myModule1.func1().THIS.should.have.property('IS');
});
});
});
describe('Sandboxed myModule', function () {
describe('returned object', function () {
it('should have the should property', function () {
should.exist(myModule2.func1().should);
});
describe('nested objects', function () {
it('should have the should property', function () {
should.exist(myModule2.func1().THIS.should);
should.exist(myModule2.func1().THIS.IS.should);
});
});
});
});
These tests about the sandboxed module fail:
1) Sandboxed myModule returned object should have the should property:
AssertionError: expected undefined to exist
2) Sandboxed myModule returned object nested objects should have the should property:
AssertionError: expected undefined to exist
I tried to serve the Object constructor to make sure should's hidden property in the prototype is available, but that didn't work either:
var myModule2 = sandboxedModule.require('./myModule', {
globals: {
Object: Object
}
});
The funny thing is the same issue occurs if I use similar sandbox-modules like https://github.com/nathanmacinnes/injectr. This confuses me about who is doing something wrong here: both node-sandboxed-module and injectr, node itself, should.js, or is it even me? :)
Thanks for any help.
Seems like it's a node/V8 issue. According to the node.js docs, Object.prototype cannot be served to the new context:
The key issue to be aware of is that V8 provides no way to directly control the global object used within a context. As a result, while properties of your sandbox object will be available in the context, any properties from the prototypes of the sandbox may not be available.
So I have to find a workaround. I can avoid to use the .should property and do things like (object.prop1 === value).should.equal(true); instead of object.prop1.should.equal(value); or simply use an asserting lib that doesn't extend Object.prototype.
An alternative solution is to create objects within the test module, so Object.prototype modified by should would be used. For example:
var clone = function(obj){
return JSON.parse(JSON.stringify(obj));
}
var orig_objForTest = sandboxedModule.func(); //does not have .should property
var objForTest = clone(orig_objForTest); //has .should property
keep in mind that this cloning technique loses object's member functions