feat(injector): initial implementaion of dynamic injector
This commit is contained in:
76
modules/di/test/di/async_spec.js
Normal file
76
modules/di/test/di/async_spec.js
Normal file
@ -0,0 +1,76 @@
|
||||
import {ddescribe, describe, it, iit, xit, expect, beforeEach} from 'test_lib/test_lib';
|
||||
import {Injector, Inject, bind, Key} from 'di/di';
|
||||
import {Future, FutureWrapper} from 'facade/async';
|
||||
|
||||
class UserList {}
|
||||
|
||||
function fetchUsers() {
|
||||
return FutureWrapper.value(new UserList());
|
||||
}
|
||||
|
||||
class SynchronousUserList {}
|
||||
|
||||
|
||||
class UserController {
|
||||
constructor(list:UserList) {
|
||||
this.list = list;
|
||||
}
|
||||
}
|
||||
|
||||
export function main () {
|
||||
describe("async injection", function () {
|
||||
it('should return a future', function() {
|
||||
var injector = new Injector([
|
||||
bind(UserList).toAsyncFactory([], fetchUsers)
|
||||
]);
|
||||
var p = injector.asyncGet(UserList);
|
||||
expect(p).toBeFuture();
|
||||
});
|
||||
|
||||
it('should throw when instantiating async provider synchronously', function() {
|
||||
var injector = new Injector([
|
||||
bind(UserList).toAsyncFactory([], fetchUsers)
|
||||
]);
|
||||
|
||||
expect(() => injector.get(UserList))
|
||||
.toThrowError('Cannot instantiate UserList synchronously. It is provided as a future!');
|
||||
});
|
||||
|
||||
it('should return a future even if the provider is sync', function() {
|
||||
var injector = new Injector([
|
||||
SynchronousUserList
|
||||
]);
|
||||
var p = injector.asyncGet(SynchronousUserList);
|
||||
expect(p).toBeFuture();
|
||||
});
|
||||
|
||||
it('should provide itself', function() {
|
||||
var injector = new Injector([]);
|
||||
var p = injector.asyncGet(Injector);
|
||||
expect(p).toBeFuture();
|
||||
});
|
||||
|
||||
it('should return a future when a dependency is async', function(done) {
|
||||
var injector = new Injector([
|
||||
bind(UserList).toAsyncFactory([], fetchUsers),
|
||||
UserController
|
||||
]);
|
||||
|
||||
injector.asyncGet(UserController).then(function(userController) {
|
||||
expect(userController).toBeAnInstanceOf(UserController);
|
||||
expect(userController.list).toBeAnInstanceOf(UserList);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should throw when a dependency is async', function() {
|
||||
var injector = new Injector([
|
||||
bind(UserList).toAsyncFactory([], fetchUsers),
|
||||
UserController
|
||||
]);
|
||||
|
||||
expect(() => injector.get(UserController))
|
||||
.toThrowError('Cannot instantiate UserList synchronously. It is provided as a future! (UserController -> UserList)');
|
||||
});
|
||||
});
|
||||
}
|
144
modules/di/test/di/injector_spec.js
Normal file
144
modules/di/test/di/injector_spec.js
Normal file
@ -0,0 +1,144 @@
|
||||
import {describe, it, expect, beforeEach} from 'test_lib/test_lib';
|
||||
import {Injector, Inject, bind} from 'di/di';
|
||||
|
||||
class Engine {}
|
||||
class Dashboard {}
|
||||
class TurboEngine extends Engine{}
|
||||
|
||||
class Car {
|
||||
constructor(engine:Engine) {
|
||||
this.engine = engine;
|
||||
}
|
||||
}
|
||||
|
||||
class CarWithDashboard {
|
||||
constructor(engine:Engine, dashboard:Dashboard) {
|
||||
this.engine = engine;
|
||||
this.dashboard = dashboard;
|
||||
}
|
||||
}
|
||||
|
||||
class SportsCar extends Car {
|
||||
constructor(engine:Engine) {
|
||||
super(engine);
|
||||
}
|
||||
}
|
||||
|
||||
class CarWithInject {
|
||||
constructor(@Inject(TurboEngine) engine:Engine) {
|
||||
this.engine = engine;
|
||||
}
|
||||
}
|
||||
|
||||
export function main() {
|
||||
describe('injector', function() {
|
||||
it('should instantiate a class without dependencies', function() {
|
||||
var injector = new Injector([Engine]);
|
||||
var engine = injector.get(Engine);
|
||||
|
||||
expect(engine).toBeAnInstanceOf(Engine);
|
||||
});
|
||||
|
||||
it('should resolve dependencies based on type information', function() {
|
||||
var injector = new Injector([Engine, Car]);
|
||||
var car = injector.get(Car);
|
||||
|
||||
expect(car).toBeAnInstanceOf(Car);
|
||||
expect(car.engine).toBeAnInstanceOf(Engine);
|
||||
});
|
||||
|
||||
it('should resolve dependencies based on @Inject annotation', function() {
|
||||
var injector = new Injector([TurboEngine, Engine, CarWithInject]);
|
||||
var car = injector.get(CarWithInject);
|
||||
|
||||
expect(car).toBeAnInstanceOf(CarWithInject);
|
||||
expect(car.engine).toBeAnInstanceOf(TurboEngine);
|
||||
});
|
||||
|
||||
it('should cache instances', function() {
|
||||
var injector = new Injector([Engine]);
|
||||
|
||||
var e1 = injector.get(Engine);
|
||||
var e2 = injector.get(Engine);
|
||||
|
||||
expect(e1).toBe(e2);
|
||||
});
|
||||
|
||||
it('should bind to a value', function() {
|
||||
var injector = new Injector([
|
||||
bind(Engine).toValue("fake engine")
|
||||
]);
|
||||
|
||||
var engine = injector.get(Engine);
|
||||
expect(engine).toEqual("fake engine");
|
||||
});
|
||||
|
||||
it('should bind to a factory', function() {
|
||||
var injector = new Injector([
|
||||
Engine,
|
||||
bind(Car).toFactory([Engine], (e) => new SportsCar(e))
|
||||
]);
|
||||
|
||||
var car = injector.get(Car);
|
||||
expect(car).toBeAnInstanceOf(SportsCar);
|
||||
expect(car.engine).toBeAnInstanceOf(Engine);
|
||||
});
|
||||
|
||||
it('should use non-type tokens', function() {
|
||||
var injector = new Injector([
|
||||
bind('token').toValue('value')
|
||||
]);
|
||||
|
||||
expect(injector.get('token')).toEqual('value');
|
||||
});
|
||||
|
||||
it('should throw when given invalid bindings', function() {
|
||||
expect(() => new Injector(["blah"])).toThrowError('Invalid binding blah');
|
||||
expect(() => new Injector([bind("blah")])).toThrowError('Invalid binding blah');
|
||||
});
|
||||
|
||||
describe("child", function () {
|
||||
it('should load instances from parent injector', function() {
|
||||
var parent = new Injector([Engine]);
|
||||
var child = parent.createChild([]);
|
||||
|
||||
var engineFromParent = parent.get(Engine);
|
||||
var engineFromChild = child.get(Engine);
|
||||
|
||||
expect(engineFromChild).toBe(engineFromParent);
|
||||
});
|
||||
|
||||
it('should create new instance in a child injector', function() {
|
||||
var parent = new Injector([Engine]);
|
||||
var child = parent.createChild([
|
||||
bind(Engine).toClass(TurboEngine)
|
||||
]);
|
||||
|
||||
var engineFromParent = parent.get(Engine);
|
||||
var engineFromChild = child.get(Engine);
|
||||
|
||||
expect(engineFromParent).not.toBe(engineFromChild);
|
||||
expect(engineFromChild).toBeAnInstanceOf(TurboEngine);
|
||||
});
|
||||
});
|
||||
|
||||
it('should provide itself', function() {
|
||||
var parent = new Injector([]);
|
||||
var child = parent.createChild([]);
|
||||
|
||||
expect(child.get(Injector)).toBe(child);
|
||||
});
|
||||
|
||||
it('should throw when no provider defined', function() {
|
||||
var injector = new Injector([]);
|
||||
expect(() => injector.get('NonExisting')).toThrowError('No provider for NonExisting!');
|
||||
});
|
||||
|
||||
it('should show the full path when no provider', function() {
|
||||
var injector = new Injector([CarWithDashboard, Engine]);
|
||||
|
||||
expect(() => injector.get(CarWithDashboard)).
|
||||
toThrowError('No provider for Dashboard! (CarWithDashboard -> Dashboard)');
|
||||
});
|
||||
});
|
||||
}
|
14
modules/di/test/di/key_spec.js
Normal file
14
modules/di/test/di/key_spec.js
Normal file
@ -0,0 +1,14 @@
|
||||
import {describe, it, expect} from 'test_lib/test_lib';
|
||||
import {Key} from 'di/di';
|
||||
|
||||
export function main () {
|
||||
describe("key", function () {
|
||||
it('should be equal to another key if type is the same', function () {
|
||||
expect(Key.get('car')).toBe(Key.get('car'));
|
||||
});
|
||||
|
||||
it('should not be equal to another key if types are different', function () {
|
||||
expect(Key.get('car')).not.toBe(Key.get('porsche'));
|
||||
});
|
||||
});
|
||||
}
|
Reference in New Issue
Block a user