syringejs
Version:
An ultra-lightweight dependency injection framework for JavaScript
980 lines (771 loc) • 23.7 kB
JavaScript
$(document).ready(function () {
module("New");
// Get the number of "own" properties in an object.
var getPropSize = function (obj) {
var size = 0,
key;
for (key in obj) {
if ({}.hasOwnProperty.call(obj, key)) size++;
}
return size;
};
test("new syringe", 2, function () {
var syr = Syringe.create();
equal('object', typeof syr, 'object should be returned.');
equal(getPropSize(syr.get()), 0, 'object should be empty.');
});
test("new syringe with props map", 2, function () {
var syr = Syringe.create({
'data': 'somedata'
});
equal(typeof syr, 'object', 'object should be returned.');
equal(getPropSize(syr.get()), 1, 'object should have one property.');
});
test("new syringe with verified props map", 1, function () {
var syr = Syringe.create({
'data': 'somedata'
});
equal(syr.get('data'), 'somedata', 'data should be set correctly.');
});
test("new syringe with verified deep props map", 1, function () {
var syr = Syringe.create({
'data': {
'first': {
'second': 'done'
}
}
});
equal(syr.get('data.first.second'), 'done', 'deep data should be set correctly.');
});
module("Add");
test("add a new shallow property", 1, function () {
var syr = Syringe.create();
syr.add('data', 'ok')
equal(syr.get('data'), 'ok', 'shallow data should be set correctly.');
});
test("add a new deep property", 1, function () {
var syr = Syringe.create();
syr.add('data.first.second', 'done')
equal(syr.get('data.first.second'), 'done', 'deep data should be set correctly.');
});
test("add a new property map with deep and shallow items", 2, function () {
var syr = Syringe.create();
syr.add({
'data': {
'first': {
'second': 'done'
}
},
'data2': {}
})
equal(syr.get('data.first.second'), 'done', 'deep data should be set correctly.');
equal(typeof syr.get('data2'), 'object', 'object should be returned.');
});
test("add a multiple property maps with deep and shallow items from an array", 4, function () {
var syr = Syringe.create();
syr.add([{
'data': {
'first': {
'second': 'done'
}
},
'data2': {}
}, {
'data3': {
'first': {
'second': 'done'
}
},
'data4': {}
}])
equal(syr.get('data.first.second'), 'done', 'deep data should be set correctly.');
equal(syr.get('data3.first.second'), 'done', 'deep data should be set correctly.');
equal(typeof syr.get('data2'), 'object', 'object should be returned.');
equal(typeof syr.get('data4'), 'object', 'object should be returned.');
});
test("add deep method with binding", 1, function () {
var syr = Syringe.create();
syr.add({
'first': {
'second': 'done'
}
});
syr.add('func', function (data, msg) {
return msg + ' - ' + data;
}, ['first.second']);
equal(syr.exec('func', ['hello world']), 'hello world - done', 'data from bound method should be returned.');
});
test("add constructor function with deep binding", 1, function () {
var syr = Syringe.create();
syr.add({
'first': {
'second': 'done'
}
});
var Func = function (data, msg) {
this.data = data;
this.msg = msg;
}
Func.prototype.say = function () {
return this.msg + ' - ' + this.data;
};
syr.add('Func', Func, ['first.second']);
var F = (syr.get('Func'));
var f = new F('hello world');
equal(f.say(), 'hello world - done', 'data from bound method should be returned.');
});
test("add multiple constructor functions with deep binding", 2, function () {
var syr = Syringe.create();
syr.add({
'first': {
'second': 'done'
},
'third': {
'fourth': 'done and done'
},
'fifth': {
'sixth': 'over and out'
}
});
var Func1 = function (data, msg1) {
this.data = data;
this.msg1 = msg1;
}
Func1.prototype.say = function () {
return this.msg1 + ' - ' + this.data;
};
var Func2 = function (data1, data2, msg1, msg2, msg3) {
this.data1 = data1;
this.data2 = data2;
this.msg1 = msg1;
this.msg2 = msg2;
this.msg3 = msg3;
}
Func2.prototype.say = function () {
return this.msg1 + ' ' + this.msg2 + ' ' + this.msg3 + ' - ' + this.data1 + ' - ' + this.data2;
};
syr.add('Func1', Func1, ['first.second']);
syr.add('Func2', Func2, ['third.fourth', 'fifth.sixth']);
var F1 = (syr.get('Func1'));
var f1 = new F1('hello world');
var F2 = (syr.get('Func2'));
var f2 = new F2('goodbye', 'cruel', 'world');
equal(f1.say(), 'hello world - done', 'data from first bound method should be returned.');
equal(f2.say(), 'goodbye cruel world - done and done - over and out', 'data from second bound method should be returned.');
});
module("Set");
test("set shallow props of non-existant item", 1, function () {
var syr = Syringe.create();
throws(function () {
syr.set('data', 'ok');
},
Error, "must throw error to pass.");
});
test("set deep props of non-existant item", 1, function () {
var syr = Syringe.create();
throws(function () {
syr.set('first.second.third', 'ok');
},
Error, "must throw error to pass.");
});
test("set shallow props of existing item", 1, function () {
var syr = Syringe.create();
syr.add('data', false);
syr.set('data', 'ok');
equal(syr.get('data'), 'ok', 'shallow data should be set correctly.');
});
test("set deep props of existing item", 1, function () {
var syr = Syringe.create({
'data': {
'first': {
'second': 'done'
}
}
});
syr.set('data.first.second', 'ok');
equal(syr.get('data.first.second'), 'ok', 'deep data should be set correctly.');
});
test("set shallow props of existing item where value is undefined", 1, function () {
var syr = Syringe.create();
syr.add('data');
syr.set('data', 'ok');
equal(syr.get('data'), 'ok', 'shallow data should be set correctly.');
});
test("set deep props of existing item where value is undefined", 1, function () {
var syr = Syringe.create();
syr.add('first.second.third');
syr.set('first.second.third', 'ok');
equal(syr.get('first.second.third'), 'ok', 'shallow data should be set correctly.');
});
test("add deep method with binding", 2, function () {
var syr = Syringe.create();
syr.add({
'first': {
'second': 'done'
},
'third': {
'fourth': 'done and done'
}
});
syr.add('func', function (data, msg) {
return msg + ' - ' + data;
}, ['first.second']);
equal(syr.exec('func', ['hello world']), 'hello world - done', 'data from bound method should be returned.');
syr.set('func', function (data, msg) {
return msg + ' - ' + data;
}, ['third.fourth']);
equal(syr.exec('func', ['hello world']), 'hello world - done and done', 'data from bound method should be returned.');
});
module("Remove");
test("remove shallow props", 2, function () {
var syr = Syringe.create({
'data': {
'first': {
'second': 'done'
},
'other': {}
},
'data2': {}
});
syr.remove('data');
strictEqual(syr.get('data'), false, 'targeted data should be removed.');
equal(typeof syr.get('data2'), 'object', 'siblings of targeted data should not be removed.');
});
test("remove deep props", 3, function () {
var syr = Syringe.create({
'data': {
'first': {
'second': 'done'
},
'other': {}
},
'data2': {}
});
syr.remove('data.first');
strictEqual(syr.get('data.first'), false, 'targeted deep data should be removed.');
equal(typeof syr.get('data.other'), 'object', 'siblings of targeted data should not be removed.');
equal(typeof syr.get('data2'), 'object', 'siblings of ancestor of targeted data should not be removed.');
});
test("remove multiple deep props", 4, function () {
var syr = Syringe.create({
'data': {
'first': {
'second': 'done'
},
'other': {}
},
'data2': {},
'data3': {
'third': {}
}
});
syr.remove(['data.first', 'data3.third']);
strictEqual(syr.get('data.first'), false, 'targeted deep data should be removed.');
strictEqual(syr.get('data3.third'), false, 'targeted deep data should be removed.');
equal(typeof syr.get('data.other'), 'object', 'siblings of targeted data should not be removed.');
equal(typeof syr.get('data2'), 'object', 'siblings of ancestor of targeted data should not be removed.');
});
module("Bind");
test("bind an anonymous method, no context", 1, function () {
var syr = Syringe.create({
'data': 'done'
});
var f = syr.bind(['data'], function (data, args) {
return 'process is ' + data;
});
equal(f(), 'process is done', 'bound function returns injected data.');
});
test("bind an anonymous method, with context", 1, function () {
var syr = Syringe.create({
'data': 'done'
});
var f = syr.bind(['data'], function (data, args) {
return this.example + ' process is ' + data;
}, {
'example': 'test'
});
equal(f(), 'test process is done', 'bound function returns injected data.');
});
test("bind a named method, with no context", 1, function () {
var syr = Syringe.create({
'data': 'done'
});
syr.bind('f', ['data'], function (data, args) {
return 'process is ' + data;
});
equal(f(), 'process is done', 'bound function returns injected data.');
});
test("bind a named method, with context", 1, function () {
var syr = Syringe.create({
'data': 'done'
});
var obj = {
'first': {'second': 'and done'}
};
syr.bind('x.f', ['data'], function (data, args) {
return 'process is ' + data + ' ' + this.second;
}, obj.first);
equal(x.f(), 'process is done and done', 'bound function returns injected data.');
});
test("bind a named method, with context, that contains the entire registry", 2, function () {
var syr = Syringe.create({
'data': 'done'
});
var obj = {
'first': {}
};
syr.bind('x.f', ['*', 'data'], function (map, data, args) {
return {
data: 'process is ' + data,
map: map
}
}, obj.first);
equal(x.f().data, 'process is done', 'bound function returns injected data.');
equal(x.f().map, syr.get(), 'bound function returns entire map.');
});
test("bind a named method, with context, that contains the current Syringe object", 2, function () {
var syr = Syringe.create({
'data': 'done'
});
var obj = {
'first': {}
};
syr.bind('x.f', ['data', 'this'], function (data, syr, args) {
return {
id: syr.id,
data: data
}
}, obj.first);
equal(x.f().id, syr.id, 'bound function returns injected data.');
equal(x.f().data, 'done', 'bound function returns registry object.');
});
test("bind a named method, with context, that contains an item from the global object", 1, function () {
var syr = Syringe.create();
var obj = {
'first': {}
};
window.obj2 = {
'data': 'done'
};
syr.bind('x.f', ['global:obj2.data'], function (data) {
return {
data: data
}
}, obj.first);
equal(x.f().data, 'done', 'bound function returns registry object.');
});
module("Exec");
test("directly execute a registry method", 1, function () {
var syr = Syringe.create({
'f': function (arg1, arg2) {
return this.example + ' ' + arg1 + ' is ' + arg2
}
});
equal(syr.exec('f', ['process', 'done'], {
'example': 'test'
}), 'test process is done', 'executed function returns data.');
});
test("directly execute a registry method with context but no arguments", 1, function () {
var syr = Syringe.create({
'f': function () {
return this.example
}
});
equal(syr.exec('f', [], {
'example': 'test'
}), 'test', 'executed function returns data.');
});
test("directly execute a registry with injected propeties", 1, function () {
var syr = Syringe.create({
'data': 'test'
});
syr.add('f', function (d, arg1, arg2) {
return d + ' ' + arg1 + ' is ' + arg2;
}, ['data']);
equal(syr.exec('f', ['process', 'done']), 'test process is done', 'executed function returns data.');
});
test("directly execute a registry with injected propeties and context", 1, function () {
var syr = Syringe.create({
'data': 'binding'
});
syr.add('f', function (d, arg1, arg2) {
return this.example + ' ' + arg1 + ' is ' + arg2 + ' with ' + d;
}, ['data']);
equal(syr.exec('f', ['process', 'done'], {
'example': 'test'
}), 'test process is done with binding', 'executed function returns data.');
});
module("Wrap");
test("wrap an existing method", 1, function () {
var syr = Syringe.create({
'data': 'foo',
'data2': 'bar'
});
var f = syr.bind(['data', 'data2'], function (d, d2, arg, arg2) {
return d + ' ' + d2 + ' ' + arg + ' ' + arg2;
});
var f2 = function (fn, arg) {
return fn(arg, this.example);
};
f2 = syr.wrap(f, f2, {
'example': 'test'
});
equal(f2('woo'), 'foo bar woo test', 'wrapped function returns injected data and expected arguments.');
});
module("Separator");
test("change the separator character to a valid alternative", 3, function () {
var syr = Syringe.create({
'first': {
'second': {
'third': 'done'
}
}
});
syr.separator('#');
equal(syr.get('first#second#third'), 'done', 'executed function returns data');
syr.separator('/');
equal(syr.get('first/second/third'), 'done', 'executed function returns data');
syr.separator('*');
equal(syr.get('first*second*third'), 'done', 'executed function returns data');
syr.separator('.');
});
test("change the separator character to an invalid alternative", 4, function () {
var syr = Syringe.create({
'first': {
'second': {
'third': 'done'
}
}
});
syr.separator(' ');
equal(syr.get('first second third'), false, 'executed function does not return data');
syr.separator('A');
equal(syr.get('firstAsecondAthird'), false, 'executed function does not return data');
syr.separator('1');
equal(syr.get('first1second1third'), false, 'executed function does not return data');
syr.separator('##');
equal(syr.get('first##second##third'), false, 'executed function does not return data');
syr.separator('.');
});
test("allow different separators between instances", 3, function () {
var syr1 = Syringe.create({
'first': {
'second': {
'third': 'done'
}
}
});
var syr2 = syr1.create({
'first': {
'second': {
'third': 'done'
}
}
});
syr1.separator('#');
syr2.separator('*');
equal(syr1.get('first#second#third'), 'done', 'executed function returns data');
equal(syr2.get('first*second*third'), 'done', 'executed function returns data');
syr2.separator('.');
equal(syr2.get('first.second.third'), 'done', 'executed function returns data');
});
module("Copy");
test("copy an existing method", 1, function () {
var syr = Syringe.create({
'data': 'foo',
'data2': 'bar'
});
var f = syr.bind(['data'], function (d) {
return d;
});
var f2 = function (d) {
return d;
};
f2 = syr.copy(['data2'], f);
equal(f2('woo'), 'bar', 'bound function returns injected data.');
});
module("Fetch", {
setup: function () {
this.server = sinon.fakeServer.create();
// Return an object
this.server.respondWith("GET", "/syringe/fetch1", [200, {
"Content-Type": "application/json"
},
JSON.stringify({
foo: 'bar'
})
]);
// Return an array
this.server.respondWith("GET", "/syringe/fetch1arr", [200, {
"Content-Type": "application/json"
},
JSON.stringify([{
foo: 'bar'
}])
]);
this.server.autoRespond = true;
},
teardown: function () {
this.server.restore();
}
});
asyncTest("fetch and bind an item", 1, function () {
var syr = Syringe.create();
syr.fetch([{
path: '/syringe/fetch2',
bind: 'data2'
}, {
path: '/syringe/fetch1',
bind: 'data1'
}], {
'success': function () {
ok((typeof this.get('data1') === 'object' && this.get('data1.foo') === 'bar'), "asynch data fetched and bound correctly");
start();
}
});
});
asyncTest("fetch and bind an item to an existing path", 1, function () {
var syr = Syringe.create({
data1: { 'woo': true },
data2: {}
});
syr.fetch([{
path: '/syringe/fetch2',
bind: 'data2'
}, {
path: '/syringe/fetch1',
bind: 'data1'
}], {
'success': function () {
ok((typeof this.get('data1') === 'object' && this.get('data1.foo') === 'bar' && this.get('data1.woo') === true), "asynch data fetched and bound correctly");
start();
}
});
});
asyncTest("fetch and bind an array item to an existing path", 1, function () {
var syr = Syringe.create({
data1: { 'woo': true }
});
syr.fetch([{
path: '/syringe/fetch1arr',
bind: 'data1'
}], {
'success': function () {
ok((typeof this.get('data1') === 'object' && this.get('data1.json').length && this.get('data1.woo') === true), "asynch data fetched and bound correctly");
start();
}
});
});
module("Mixin");
test("add a mixin to the prototype", 1, function () {
var syr = Syringe.create({
'data': 'foo',
'data2': 'bar'
});
var id = syr.id;
syr.mixin({
'func': function () {
return this.get('data');
}
});
equal(syr.func(), 'foo', 'mixin returns Syringe object');
});
module("Events");
test("Listen for any add event", 2, function () {
var syr = Syringe.create({
'data': 'foo'
});
syr.listen('add', function (type, name, value) {
equal(name, 'data2', 'Add event fires and returns correct name');
equal(value, 'bar', 'Add event fires and returns correct value');
});
syr.add('data2', 'bar');
});
test("Listen for any set event", 2, function () {
var syr = Syringe.create({
'first': {
'second': {
'third': 'done'
}
}
});
syr.listen('set', function (type, name, value) {
equal(name, 'first.second.third', 'Set event fires and returns correct name');
equal(value, 'done and done', 'Set event fires and returns correct value');
});
syr.set('first.second.third', 'done and done');
});
test("Listen for any get event", 1, function () {
var syr = Syringe.create({
'first': {
'second': {
'third': 'done'
}
}
});
syr.listen('get', function (type, name) {
equal(name, 'first.second.third', 'Set event fires and returns correct name');
});
syr.get('first.second.third');
});
test("Listen for any remove event", 1, function () {
var syr = Syringe.create({
'first': {
'second': {
'third': 'done'
}
}
});
syr.listen('remove', function (type, name) {
equal(name, 'first.second.third', 'Set event fires and returns correct name');
});
syr.remove('first.second.third');
});
test("Listen for a scoped add event", 2, function () {
var syr = Syringe.create({
'data': 'foo'
});
syr.listen('add:data2', function (type, name, value) {
equal(name, 'data2', 'Add event fires and returns correct name');
equal(value, 'bar', 'Add event fires and returns correct value');
});
syr.add('data2', 'bar');
});
test("Listen for a scoped set event", 4, function () {
var syr = Syringe.create({
'first': {
'second': {
'third': 'done'
}
}
});
syr.listen('set:first.second.third', function (type, name, value) {
equal(name, 'first.second.third', 'Set event fires and returns correct name');
equal(value, 'done and done', 'Set event fires and returns correct value');
});
syr.listen('set:third', function (type, name, value) {
equal(name, 'first.second.third', 'Set event fires and returns correct name');
equal(value, 'done and done', 'Set event fires and returns correct value');
});
syr.set('first.second.third', 'done and done');
});
test("Listen for any get event", 2, function () {
var syr = Syringe.create({
'first': {
'second': {
'third': 'done'
}
}
});
syr.listen('get:first.second.third', function (type, name) {
equal(name, 'first.second.third', 'Set event fires and returns correct name');
});
syr.listen('get:third', function (type, name) {
equal(name, 'first.second.third', 'Set event fires and returns correct name');
});
syr.get('first.second.third');
});
test("Listen for a scoped remove event", 2, function () {
var syr = Syringe.create({
'first': {
'second': {
'third': 'done'
}
}
});
syr.listen('remove:first.second.third', function (type, name) {
equal(name, 'first.second.third', 'Set event fires and returns correct name');
});
syr.listen('remove:third', function (type, name) {
equal(name, 'first.second.third', 'Set event fires and returns correct name');
});
syr.remove('first.second.third');
});
test("Listen for any event", 3, function () {
var syr = Syringe.create({
'first': {
'second': {
'third': 'done'
}
}
});
syr.listen('all', function (type, name, value) {
equal(type, 'set', 'Set event fires and returns correct name');
equal(name, 'first.second.third', 'Set event fires and returns correct name');
equal(value, 'done and done', 'Set event fires and returns correct value');
});
syr.set('first.second.third', 'done and done');
});
test("Listen for any event", 3, function () {
var syr = Syringe.create({
'first': {
'second': {
'third': 'done'
}
}
});
syr.listen('all:first.second.third', function (type, name, value) {
equal(type, 'remove', 'Set event fires and returns correct name');
equal(name, 'first.second.third', 'Set event fires and returns correct name');
equal(value, undefined, 'Set event fires and returns correct value');
});
syr.remove('first.second.third');
});
module("List Operations");
test("Process an array and return a result to the associated event", 3, function () {
var syr = Syringe.create({
'first': {
'second': {
'third': [1,2,3]
}
}
});
syr.listen('listops:first.second.third', function (type, name) {
equal(name, 'first.second.third', 'Listops event fires and returns correct name');
});
syr.listen('listops:third', function (type, name) {
equal(name, 'first.second.third', 'Listops event fires and returns correct name');
});
syr.listops('first.second.third', function (arr) {
arr.push(4,5,6);
});
var val = syr.get('first.second.third');
deepEqual(val, [1,2,3,4,5,6], 'List operation completed successfully')
});
test("Process an array and return an extended result to the associated event", 6, function () {
var syr = Syringe.create({
'first': {
'second': {
'third': [1,2,3]
}
}
});
syr.listen('listops:first.second.third', function (type, name, arr) {
equal(name, 'first.second.third', 'Listops event fires and returns correct name');
deepEqual(arr, [1,2], 'Listops event fires and returns processed list');
});
syr.listen('listops:third', function (type, name, arr, val) {
equal(name, 'first.second.third', 'Listops event fires and returns correct name');
deepEqual(arr, [1,2], 'Listops event fires and returns processed list');
equal(val, 3, 'Listops event fires and returns correct value');
});
syr.listops('first.second.third', function (arr) {
return arr.pop();
});
var val = syr.get('first.second.third');
deepEqual(val, [1,2], 'List operation completed successfully')
});
test("Process a non-array and throw an error", 1, function () {
var syr = Syringe.create({
'first': {
'second': {
'third': {'a': 1, 'b': 2, 'c': 3}
}
}
});
throws(function () {
syr.listops('first.second.third', function (arr) { arr.pop(); });
},
Error, "must throw error to pass.");
});
});