injectr
Version:
Finally, a solution to node.js dependency injection
196 lines (192 loc) • 8.37 kB
JavaScript
"use strict";
var expect = require("expect.js"),
injectr = require("../lib/injectr"),
pretendr = require("pretendr");
describe("injectr", function () {
beforeEach(function () {
this.mockFs = pretendr({
readFileSync : function () {}
});
this.mockPath = pretendr({
join : function () {},
dirname : function () {}
});
this.mockPath.join.returnValue('dir/filename');
this.mockVm = pretendr({
createScript : function () {}
});
this.mockVm.createScript.template({
runInNewContext : function () {},
runInThisContext : function () {}
});
this.mockCoffeeScript = pretendr({
compile : function () {}
});
// this.injectr is the injectr under test
// the injectr var is being used to test it
this.injectr = injectr('../lib/injectr.js', {
fs : this.mockFs.mock,
path : this.mockPath.mock,
vm : this.mockVm.mock,
'coffee-script' : this.mockCoffeeScript.mock
}, {
module : {
parent : module
}
});
});
it("should attempt to resolve the selected file", function () {
this.mockPath.dirname.returnValue('dirname');
this.injectr('./filename');
expect(this.mockPath.dirname.calls).to.have.length(1);
expect(this.mockPath.dirname.calls[0].args)
.to.have.property(0, __filename);
expect(this.mockPath.join.calls).to.have.length(1);
expect(this.mockPath.join.calls[0].args)
.to.have.property(0, 'dirname')
.and.to.have.property(1, './filename');
});
it("should read in the selected file", function () {
this.injectr('filename');
expect(this.mockFs.readFileSync.calls).to.have.length(1);
expect(this.mockFs.readFileSync.calls[0].args)
.to.have.property(0, 'dir/filename')
.and.to.have.property(1, 'utf8');
});
it("should only read the file once per file", function () {
this.mockFs.readFileSync.returnValue('dummy');
this.injectr('filename');
this.injectr('filename');
expect(this.mockFs.readFileSync.calls).to.have.length(1);
this.mockPath.join.returnValue('dir/filename2');
this.injectr('filename2');
this.injectr('filename2');
expect(this.mockFs.readFileSync.calls).to.have.length(2);
});
it("should create a script from the file", function () {
var call;
this.mockFs.readFileSync.returnValue('dummy script');
this.injectr('filename');
expect(this.mockVm.createScript.calls).to.have.length(1);
call = this.mockVm.createScript.calls[0];
expect(call.args[0]).to.equal('dummy script');
expect(call.args[1]).to.equal('dir/filename');
});
it("should run the script in a new context", function () {
var mockScript;
this.injectr('filename');
mockScript = this.mockVm.createScript.calls[0].pretendr;
expect(mockScript.runInNewContext.calls).to.have.length(1);
});
it("should have a predefined module.exports", function () {
var context,
mockScript;
this.injectr('filename');
mockScript = this.mockVm.createScript.calls[0].pretendr;
context = mockScript.runInNewContext.calls[0].args[0];
expect(context).to.have.property('module');
expect(context.module).to.have.property('exports');
expect(context.module.exports).to.be.an('object');
});
it("should have an exports property equal to module.exports", function () {
var context,
mockScript;
this.injectr('filename');
mockScript = this.mockVm.createScript.calls[0].pretendr;
context = mockScript.runInNewContext.calls[0].args[0];
expect(context).to.have.property('exports', context.module.exports);
});
it("should return module.exports", function () {
var context,
mockScript,
l;
l = this.injectr('filename');
mockScript = this.mockVm.createScript.calls[0].pretendr;
context = mockScript.runInNewContext.calls[0].args[0];
expect(l).to.equal(context.module.exports);
});
it("should allow an onload callback", function () {
var mockCb = pretendr(function () {});
this.mockFs.readFileSync.returnValue('before');
mockCb.returnValue('after');
this.injectr.onload = mockCb.mock;
this.injectr('filename');
expect(mockCb.calls).to.have.length(1);
expect(mockCb.calls[0].args).to.have.property(0, 'dir/filename')
.and.to.have.property(1, 'before');
expect(this.mockVm.createScript.calls[0].args[0]).to.equal('after');
});
it("should only run the callback once per file", function () {
var mockCb = pretendr(function () {});
mockCb.returnValue('dummy');
this.injectr.onload = mockCb.mock;
this.injectr('filename');
this.injectr('filename');
expect(mockCb.calls).to.have.length(1);
});
it("should use the provided context to run the script", function () {
var context = {},
mockScript;
this.injectr('filename', null, context);
mockScript = this.mockVm.createScript.calls[0].pretendr;
expect(mockScript.runInNewContext.calls[0].args[0])
.to.equal(context);
});
it("should still have module and require objects", function () {
var context = {};
this.injectr('filename', null, context);
expect(context).to.have.property('module')
.and.to.have.property('require');
});
describe("#require", function () {
it("should get mock libraries if provided", function () {
var context,
customLib = {},
mockScript;
this.injectr('filename', {
customLib : customLib
});
mockScript = this.mockVm.createScript.calls[0].pretendr;
context = mockScript.runInNewContext.calls[0].args[0];
expect(context.require('customLib')).to.equal(customLib);
});
it("should require libraries otherwise", function () {
var context,
mockScript;
this.injectr('filename', {});
mockScript = this.mockVm.createScript.calls[0].pretendr;
context = mockScript.runInNewContext.calls[0].args[0];
expect(JSON.stringify(context.require('fs')))
.to.eql(JSON.stringify(require('fs')));
});
it("should resolve directories to the injectr'd file", function () {
var args,
l,
mockScript,
req;
l = this.injectr('filename');
mockScript = this.mockVm.createScript.calls[0].pretendr;
req = mockScript.runInNewContext.calls[0].args[0].require;
this.mockPath.dirname.returnValue('/directory/');
this.mockPath.join.returnValue('fs');
req('./a-local-module');
args = this.mockPath.dirname.calls[1].args;
expect(args).to.have.property(0, 'dir/filename');
args = this.mockPath.join.calls[1].args;
expect(args[0]).to.equal('/directory/');
expect(args[1]).to.equal('./a-local-module');
expect(JSON.stringify(l)).to.equal(JSON.stringify(require('fs')));
});
it("should compile coffee-script files before running", function () {
var out;
this.mockCoffeeScript.compile.returnValue('compiled');
out = this.injectr.onload('file.coffee', 'uncompiled');
expect(out).to.equal('compiled');
this.mockCoffeeScript.compile.returnValue('another compiled');
out = this.injectr.onload('another.coffee', '');
expect(out).to.equal('another compiled');
out = this.injectr.onload('non-coffee', 'javascript');
expect(out).to.equal('javascript');
});
});
});