2015-05-22 18:39:28 -04:00
|
|
|
import {isBlank, BaseException, stringify} from 'angular2/src/facade/lang';
|
2015-07-06 13:38:12 -04:00
|
|
|
import {
|
|
|
|
describe,
|
|
|
|
ddescribe,
|
|
|
|
it,
|
|
|
|
iit,
|
|
|
|
expect,
|
|
|
|
beforeEach,
|
|
|
|
SpyDependencyProvider
|
|
|
|
} from 'angular2/test_lib';
|
2015-05-22 18:39:28 -04:00
|
|
|
import {
|
|
|
|
Injector,
|
2015-07-13 18:57:06 -04:00
|
|
|
ProtoInjector,
|
2015-05-22 18:39:28 -04:00
|
|
|
bind,
|
|
|
|
ResolvedBinding,
|
|
|
|
Key,
|
|
|
|
forwardRef,
|
2015-07-08 15:04:24 -04:00
|
|
|
DependencyMetadata,
|
|
|
|
Injectable,
|
2015-07-13 18:57:06 -04:00
|
|
|
InjectMetadata,
|
|
|
|
SelfMetadata,
|
2015-07-29 14:26:09 -04:00
|
|
|
HostMetadata,
|
|
|
|
SkipSelfMetadata,
|
2015-07-13 18:57:06 -04:00
|
|
|
Optional,
|
|
|
|
Inject,
|
|
|
|
BindingWithVisibility,
|
|
|
|
PUBLIC,
|
|
|
|
PRIVATE,
|
|
|
|
PUBLIC_AND_PRIVATE
|
2015-05-22 18:39:28 -04:00
|
|
|
} from 'angular2/di';
|
2015-07-01 19:06:15 -04:00
|
|
|
|
|
|
|
import {InjectorInlineStrategy, InjectorDynamicStrategy} from 'angular2/src/di/injector';
|
|
|
|
|
2015-07-08 15:04:24 -04:00
|
|
|
class CustomDependencyMetadata extends DependencyMetadata {}
|
2015-05-22 18:39:28 -04:00
|
|
|
|
|
|
|
class Engine {}
|
2014-10-07 10:34:07 -04:00
|
|
|
|
2014-10-06 10:13:33 -04:00
|
|
|
class BrokenEngine {
|
2015-05-22 18:39:28 -04:00
|
|
|
constructor() { throw new BaseException("Broken Engine"); }
|
2014-10-06 10:13:33 -04:00
|
|
|
}
|
2014-10-07 10:34:07 -04:00
|
|
|
|
2015-05-22 18:39:28 -04:00
|
|
|
class DashboardSoftware {}
|
2014-10-07 10:34:07 -04:00
|
|
|
|
2015-05-22 18:39:28 -04:00
|
|
|
@Injectable()
|
2014-10-03 17:26:49 -04:00
|
|
|
class Dashboard {
|
2014-10-07 10:34:07 -04:00
|
|
|
constructor(software: DashboardSoftware) {}
|
|
|
|
}
|
|
|
|
|
2015-05-22 18:39:28 -04:00
|
|
|
class TurboEngine extends Engine {}
|
2014-09-30 14:56:33 -04:00
|
|
|
|
2015-05-22 18:39:28 -04:00
|
|
|
@Injectable()
|
2014-09-30 14:56:33 -04:00
|
|
|
class Car {
|
2015-05-22 18:39:28 -04:00
|
|
|
engine: Engine;
|
|
|
|
constructor(engine: Engine) { this.engine = engine; }
|
2014-09-30 14:56:33 -04:00
|
|
|
}
|
|
|
|
|
2015-05-22 18:39:28 -04:00
|
|
|
@Injectable()
|
2015-02-27 10:42:51 -05:00
|
|
|
class CarWithOptionalEngine {
|
|
|
|
engine;
|
2015-05-22 18:39:28 -04:00
|
|
|
constructor(@Optional() engine: Engine) { this.engine = engine; }
|
2015-02-27 10:42:51 -05:00
|
|
|
}
|
|
|
|
|
2015-05-22 18:39:28 -04:00
|
|
|
@Injectable()
|
2014-09-30 14:56:33 -04:00
|
|
|
class CarWithDashboard {
|
2015-05-22 18:39:28 -04:00
|
|
|
engine: Engine;
|
|
|
|
dashboard: Dashboard;
|
|
|
|
constructor(engine: Engine, dashboard: Dashboard) {
|
2014-09-30 14:56:33 -04:00
|
|
|
this.engine = engine;
|
|
|
|
this.dashboard = dashboard;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-05-22 18:39:28 -04:00
|
|
|
@Injectable()
|
2014-09-30 14:56:33 -04:00
|
|
|
class SportsCar extends Car {
|
2015-05-22 18:39:28 -04:00
|
|
|
engine: Engine;
|
|
|
|
constructor(engine: Engine) { super(engine); }
|
2014-09-30 14:56:33 -04:00
|
|
|
}
|
|
|
|
|
2015-05-22 18:39:28 -04:00
|
|
|
@Injectable()
|
2014-09-30 14:56:33 -04:00
|
|
|
class CarWithInject {
|
2015-05-22 18:39:28 -04:00
|
|
|
engine: Engine;
|
|
|
|
constructor(@Inject(TurboEngine) engine: Engine) { this.engine = engine; }
|
2014-09-30 14:56:33 -04:00
|
|
|
}
|
|
|
|
|
2015-05-22 18:39:28 -04:00
|
|
|
@Injectable()
|
2014-10-06 10:13:33 -04:00
|
|
|
class CyclicEngine {
|
2015-05-22 18:39:28 -04:00
|
|
|
constructor(car: Car) {}
|
2014-10-06 10:13:33 -04:00
|
|
|
}
|
|
|
|
|
2014-10-05 16:25:42 -04:00
|
|
|
class NoAnnotations {
|
2014-10-07 10:34:07 -04:00
|
|
|
constructor(secretDependency) {}
|
2014-10-05 16:25:42 -04:00
|
|
|
}
|
|
|
|
|
2014-09-30 14:56:33 -04:00
|
|
|
export function main() {
|
2015-07-01 19:06:15 -04:00
|
|
|
var dynamicBindings = [
|
|
|
|
bind('binding0')
|
|
|
|
.toValue(1),
|
|
|
|
bind('binding1').toValue(1),
|
|
|
|
bind('binding2').toValue(1),
|
|
|
|
bind('binding3').toValue(1),
|
|
|
|
bind('binding4').toValue(1),
|
|
|
|
bind('binding5').toValue(1),
|
|
|
|
bind('binding6').toValue(1),
|
|
|
|
bind('binding7').toValue(1),
|
|
|
|
bind('binding8').toValue(1),
|
|
|
|
bind('binding9').toValue(1),
|
|
|
|
bind('binding10').toValue(1)
|
|
|
|
];
|
|
|
|
|
|
|
|
[{strategy: 'inline', bindings: [], strategyClass: InjectorInlineStrategy},
|
|
|
|
{
|
|
|
|
strategy: 'dynamic',
|
|
|
|
bindings: dynamicBindings,
|
|
|
|
strategyClass: InjectorDynamicStrategy
|
|
|
|
}].forEach((context) => {
|
|
|
|
|
2015-07-06 13:38:12 -04:00
|
|
|
function createInjector(bindings: any[], dependencyProvider = null) {
|
|
|
|
return Injector.resolveAndCreate(bindings.concat(context['bindings']), dependencyProvider);
|
2015-07-01 19:06:15 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
describe(`injector ${context['strategy']}`, () => {
|
|
|
|
it("should use the right strategy", () => {
|
|
|
|
var injector = createInjector([]);
|
|
|
|
expect(injector.internalStrategy).toBeAnInstanceOf(context['strategyClass']);
|
|
|
|
});
|
2015-04-24 18:19:11 -04:00
|
|
|
|
2015-07-01 19:06:15 -04:00
|
|
|
it('should instantiate a class without dependencies', () => {
|
|
|
|
var injector = createInjector([Engine]);
|
|
|
|
var engine = injector.get(Engine);
|
2014-09-30 14:56:33 -04:00
|
|
|
|
2015-07-01 19:06:15 -04:00
|
|
|
expect(engine).toBeAnInstanceOf(Engine);
|
|
|
|
});
|
2014-09-30 14:56:33 -04:00
|
|
|
|
2015-07-01 19:06:15 -04:00
|
|
|
it('should resolve dependencies based on type information', () => {
|
|
|
|
var injector = createInjector([Engine, Car]);
|
|
|
|
var car = injector.get(Car);
|
2014-09-30 14:56:33 -04:00
|
|
|
|
2015-07-01 19:06:15 -04:00
|
|
|
expect(car).toBeAnInstanceOf(Car);
|
|
|
|
expect(car.engine).toBeAnInstanceOf(Engine);
|
|
|
|
});
|
2014-09-30 14:56:33 -04:00
|
|
|
|
2015-07-01 19:06:15 -04:00
|
|
|
it('should resolve dependencies based on @Inject annotation', () => {
|
|
|
|
var injector = createInjector([TurboEngine, Engine, CarWithInject]);
|
|
|
|
var car = injector.get(CarWithInject);
|
2014-09-30 14:56:33 -04:00
|
|
|
|
2015-07-01 19:06:15 -04:00
|
|
|
expect(car).toBeAnInstanceOf(CarWithInject);
|
|
|
|
expect(car.engine).toBeAnInstanceOf(TurboEngine);
|
|
|
|
});
|
2014-09-30 14:56:33 -04:00
|
|
|
|
2015-07-01 19:06:15 -04:00
|
|
|
it('should throw when no type and not @Inject', () => {
|
|
|
|
expect(() => createInjector([NoAnnotations]))
|
|
|
|
.toThrowError('Cannot resolve all parameters for NoAnnotations(?). ' +
|
|
|
|
'Make sure they all have valid type or annotations.');
|
|
|
|
});
|
2014-10-05 16:25:42 -04:00
|
|
|
|
2015-07-01 19:06:15 -04:00
|
|
|
it('should cache instances', () => {
|
|
|
|
var injector = createInjector([Engine]);
|
2014-09-30 14:56:33 -04:00
|
|
|
|
2015-07-01 19:06:15 -04:00
|
|
|
var e1 = injector.get(Engine);
|
|
|
|
var e2 = injector.get(Engine);
|
2014-09-30 14:56:33 -04:00
|
|
|
|
2015-07-01 19:06:15 -04:00
|
|
|
expect(e1).toBe(e2);
|
|
|
|
});
|
2014-09-30 14:56:33 -04:00
|
|
|
|
2015-07-01 19:06:15 -04:00
|
|
|
it('should bind to a value', () => {
|
|
|
|
var injector = createInjector([bind(Engine).toValue("fake engine")]);
|
2014-09-30 14:56:33 -04:00
|
|
|
|
2015-07-01 19:06:15 -04:00
|
|
|
var engine = injector.get(Engine);
|
|
|
|
expect(engine).toEqual("fake engine");
|
|
|
|
});
|
2014-09-30 14:56:33 -04:00
|
|
|
|
2015-07-01 19:06:15 -04:00
|
|
|
it('should bind to a factory', () => {
|
|
|
|
function sportsCarFactory(e) { return new SportsCar(e); }
|
2014-10-09 11:35:13 -04:00
|
|
|
|
2015-07-01 19:06:15 -04:00
|
|
|
var injector = createInjector([Engine, bind(Car).toFactory(sportsCarFactory, [Engine])]);
|
2014-10-09 11:35:13 -04:00
|
|
|
|
2015-07-01 19:06:15 -04:00
|
|
|
var car = injector.get(Car);
|
|
|
|
expect(car).toBeAnInstanceOf(SportsCar);
|
|
|
|
expect(car.engine).toBeAnInstanceOf(Engine);
|
|
|
|
});
|
2014-10-09 11:35:13 -04:00
|
|
|
|
2015-07-01 19:06:15 -04:00
|
|
|
it('should supporting binding to null', () => {
|
|
|
|
var injector = createInjector([bind(Engine).toValue(null)]);
|
|
|
|
var engine = injector.get(Engine);
|
|
|
|
expect(engine).toBeNull();
|
|
|
|
});
|
2015-02-21 09:18:06 -05:00
|
|
|
|
2015-07-01 19:06:15 -04:00
|
|
|
it('should bind to an alias', () => {
|
|
|
|
var injector = createInjector(
|
|
|
|
[Engine, bind(SportsCar).toClass(SportsCar), bind(Car).toAlias(SportsCar)]);
|
2015-05-26 04:55:12 -04:00
|
|
|
|
2015-07-01 19:06:15 -04:00
|
|
|
var car = injector.get(Car);
|
|
|
|
var sportsCar = injector.get(SportsCar);
|
|
|
|
expect(car).toBeAnInstanceOf(SportsCar);
|
|
|
|
expect(car).toBe(sportsCar);
|
|
|
|
});
|
2015-05-20 16:46:55 -04:00
|
|
|
|
2015-07-01 19:06:15 -04:00
|
|
|
it('should throw when the aliased binding does not exist', () => {
|
|
|
|
var injector = createInjector([bind('car').toAlias(SportsCar)]);
|
|
|
|
var e = `No provider for ${stringify(SportsCar)}! (car -> ${stringify(SportsCar)})`;
|
|
|
|
expect(() => injector.get('car')).toThrowError(e);
|
|
|
|
});
|
2014-09-30 14:56:33 -04:00
|
|
|
|
2015-07-01 19:06:15 -04:00
|
|
|
it('should throw with a meaningful message when the aliased binding is blank', () => {
|
|
|
|
expect(() => bind('car').toAlias(null)).toThrowError('Can not alias car to a blank value!');
|
|
|
|
});
|
2014-09-30 14:56:33 -04:00
|
|
|
|
2015-07-01 19:06:15 -04:00
|
|
|
it('should handle forwardRef in toAlias', () => {
|
|
|
|
var injector = createInjector([
|
|
|
|
bind('originalEngine')
|
|
|
|
.toClass(forwardRef(() => Engine)),
|
2015-07-07 23:03:00 -04:00
|
|
|
bind('aliasedEngine').toAlias(<any>forwardRef(() => 'originalEngine'))
|
2015-07-01 19:06:15 -04:00
|
|
|
]);
|
|
|
|
expect(injector.get('aliasedEngine')).toBeAnInstanceOf(Engine);
|
|
|
|
});
|
2015-02-27 10:42:51 -05:00
|
|
|
|
2015-07-01 19:06:15 -04:00
|
|
|
it('should support overriding factory dependencies', () => {
|
|
|
|
var injector =
|
|
|
|
createInjector([Engine, bind(Car).toFactory((e) => new SportsCar(e), [Engine])]);
|
2015-02-27 10:42:51 -05:00
|
|
|
|
2015-07-01 19:06:15 -04:00
|
|
|
var car = injector.get(Car);
|
|
|
|
expect(car).toBeAnInstanceOf(SportsCar);
|
|
|
|
expect(car.engine).toBeAnInstanceOf(Engine);
|
|
|
|
});
|
2014-10-09 12:18:35 -04:00
|
|
|
|
2015-07-01 19:06:15 -04:00
|
|
|
it('should support optional dependencies', () => {
|
|
|
|
var injector = createInjector([CarWithOptionalEngine]);
|
2014-10-09 12:18:35 -04:00
|
|
|
|
2015-07-01 19:06:15 -04:00
|
|
|
var car = injector.get(CarWithOptionalEngine);
|
|
|
|
expect(car.engine).toEqual(null);
|
|
|
|
});
|
2015-01-08 12:11:33 -05:00
|
|
|
|
2015-07-01 19:06:15 -04:00
|
|
|
it("should flatten passed-in bindings", () => {
|
|
|
|
var injector = createInjector([[[Engine, Car]]]);
|
2015-01-08 12:11:33 -05:00
|
|
|
|
2015-07-01 19:06:15 -04:00
|
|
|
var car = injector.get(Car);
|
|
|
|
expect(car).toBeAnInstanceOf(Car);
|
|
|
|
});
|
2014-09-30 14:56:33 -04:00
|
|
|
|
2015-07-01 19:06:15 -04:00
|
|
|
it("should use the last binding when there are multiple bindings for same token", () => {
|
|
|
|
var injector =
|
|
|
|
createInjector([bind(Engine).toClass(Engine), bind(Engine).toClass(TurboEngine)]);
|
2014-09-30 14:56:33 -04:00
|
|
|
|
2015-07-01 19:06:15 -04:00
|
|
|
expect(injector.get(Engine)).toBeAnInstanceOf(TurboEngine);
|
|
|
|
});
|
2014-09-30 14:56:33 -04:00
|
|
|
|
2015-07-01 19:06:15 -04:00
|
|
|
it('should use non-type tokens', () => {
|
|
|
|
var injector = createInjector([bind('token').toValue('value')]);
|
2014-09-30 14:56:33 -04:00
|
|
|
|
2015-07-01 19:06:15 -04:00
|
|
|
expect(injector.get('token')).toEqual('value');
|
|
|
|
});
|
2014-09-30 14:56:33 -04:00
|
|
|
|
2015-07-01 19:06:15 -04:00
|
|
|
it('should throw when given invalid bindings', () => {
|
|
|
|
expect(() => createInjector(<any>["blah"]))
|
|
|
|
.toThrowError(
|
|
|
|
'Invalid binding - only instances of Binding and Type are allowed, got: blah');
|
|
|
|
expect(() => createInjector(<any>[bind("blah")]))
|
|
|
|
.toThrowError('Invalid binding - only instances of Binding and Type are allowed, ' +
|
|
|
|
'got: blah');
|
|
|
|
});
|
2014-09-30 14:56:33 -04:00
|
|
|
|
2015-07-01 19:06:15 -04:00
|
|
|
it('should provide itself', () => {
|
|
|
|
var parent = createInjector([]);
|
|
|
|
var child = parent.resolveAndCreateChild([]);
|
2014-10-06 10:13:33 -04:00
|
|
|
|
2015-07-01 19:06:15 -04:00
|
|
|
expect(child.get(Injector)).toBe(child);
|
|
|
|
});
|
2014-10-06 10:13:33 -04:00
|
|
|
|
2015-07-01 19:06:15 -04:00
|
|
|
it('should throw when no provider defined', () => {
|
|
|
|
var injector = createInjector([]);
|
|
|
|
expect(() => injector.get('NonExisting')).toThrowError('No provider for NonExisting!');
|
|
|
|
});
|
2014-10-06 10:13:33 -04:00
|
|
|
|
2015-07-01 19:06:15 -04:00
|
|
|
it('should show the full path when no provider', () => {
|
|
|
|
var injector = createInjector([CarWithDashboard, Engine, Dashboard]);
|
|
|
|
expect(() => injector.get(CarWithDashboard))
|
|
|
|
.toThrowError(
|
|
|
|
`No provider for DashboardSoftware! (${stringify(CarWithDashboard)} -> ${stringify(Dashboard)} -> DashboardSoftware)`);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should throw when trying to instantiate a cyclic dependency', () => {
|
|
|
|
var injector = createInjector([Car, bind(Engine).toClass(CyclicEngine)]);
|
|
|
|
|
|
|
|
expect(() => injector.get(Car))
|
|
|
|
.toThrowError(
|
|
|
|
`Cannot instantiate cyclic dependency! (${stringify(Car)} -> ${stringify(Engine)} -> ${stringify(Car)})`);
|
|
|
|
});
|
2014-10-06 13:45:24 -04:00
|
|
|
|
2015-07-01 19:06:15 -04:00
|
|
|
it('should show the full path when error happens in a constructor', () => {
|
2015-07-22 15:00:35 -04:00
|
|
|
var bindings = Injector.resolve([Car, bind(Engine).toClass(BrokenEngine)]);
|
|
|
|
var proto = new ProtoInjector([
|
|
|
|
new BindingWithVisibility(bindings[0], PUBLIC),
|
|
|
|
new BindingWithVisibility(bindings[1], PUBLIC)
|
|
|
|
]);
|
|
|
|
var injector = new Injector(proto, null, null);
|
2015-07-01 19:06:15 -04:00
|
|
|
|
|
|
|
try {
|
|
|
|
injector.get(Car);
|
|
|
|
throw "Must throw";
|
|
|
|
} catch (e) {
|
|
|
|
expect(e.message)
|
|
|
|
.toContain(`Error during instantiation of Engine! (${stringify(Car)} -> Engine)`);
|
|
|
|
expect(e.originalException instanceof BaseException).toBeTruthy();
|
|
|
|
expect(e.causeKey.token).toEqual(Engine);
|
|
|
|
}
|
|
|
|
});
|
2014-10-09 11:03:36 -04:00
|
|
|
|
2015-07-22 15:00:35 -04:00
|
|
|
it('should provide context when throwing an exception ', () => {
|
|
|
|
var engineBinding = Injector.resolve([bind(Engine).toClass(BrokenEngine)])[0];
|
|
|
|
var protoParent = new ProtoInjector([new BindingWithVisibility(engineBinding, PUBLIC)]);
|
|
|
|
|
|
|
|
var carBinding = Injector.resolve([Car])[0];
|
|
|
|
var protoChild = new ProtoInjector([new BindingWithVisibility(carBinding, PUBLIC)]);
|
|
|
|
|
|
|
|
var parent = new Injector(protoParent, null, null, () => "parentContext");
|
|
|
|
var child = new Injector(protoChild, parent, null, () => "childContext");
|
|
|
|
|
|
|
|
try {
|
|
|
|
child.get(Car);
|
|
|
|
throw "Must throw";
|
|
|
|
} catch (e) {
|
|
|
|
expect(e.context).toEqual("childContext");
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2015-07-01 19:06:15 -04:00
|
|
|
it('should instantiate an object after a failed attempt', () => {
|
|
|
|
var isBroken = true;
|
2014-10-09 11:03:36 -04:00
|
|
|
|
2015-07-01 19:06:15 -04:00
|
|
|
var injector = createInjector(
|
|
|
|
[Car, bind(Engine).toFactory(() => isBroken ? new BrokenEngine() : new Engine())]);
|
2014-10-09 11:03:36 -04:00
|
|
|
|
2015-07-01 19:06:15 -04:00
|
|
|
expect(() => injector.get(Car)).toThrowError(new RegExp("Error"));
|
2014-10-09 11:03:36 -04:00
|
|
|
|
2015-07-01 19:06:15 -04:00
|
|
|
isBroken = false;
|
2014-10-09 11:03:36 -04:00
|
|
|
|
2015-07-01 19:06:15 -04:00
|
|
|
expect(injector.get(Car)).toBeAnInstanceOf(Car);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should support null values', () => {
|
|
|
|
var injector = createInjector([bind('null').toValue(null)]);
|
|
|
|
expect(injector.get('null')).toBe(null);
|
|
|
|
});
|
2015-07-06 13:38:12 -04:00
|
|
|
|
|
|
|
it('should use custom dependency provider', () => {
|
|
|
|
var e = new Engine();
|
|
|
|
|
|
|
|
var depProvider = <any>new SpyDependencyProvider();
|
|
|
|
depProvider.spy("getDependency").andReturn(e);
|
|
|
|
|
|
|
|
var bindings = Injector.resolve([Car]);
|
|
|
|
var injector = Injector.fromResolvedBindings(bindings, depProvider);
|
|
|
|
|
|
|
|
expect(injector.get(Car).engine).toEqual(e);
|
|
|
|
expect(depProvider.spy("getDependency"))
|
|
|
|
.toHaveBeenCalledWith(injector, bindings[0], bindings[0].dependencies[0]);
|
|
|
|
});
|
2015-03-11 10:14:16 -04:00
|
|
|
});
|
|
|
|
|
2015-07-01 19:06:15 -04:00
|
|
|
|
2015-05-26 04:55:12 -04:00
|
|
|
describe("child", () => {
|
|
|
|
it('should load instances from parent injector', () => {
|
2015-04-10 20:05:31 -04:00
|
|
|
var parent = Injector.resolveAndCreate([Engine]);
|
|
|
|
var child = parent.resolveAndCreateChild([]);
|
2014-10-06 13:45:24 -04:00
|
|
|
|
|
|
|
var engineFromParent = parent.get(Engine);
|
|
|
|
var engineFromChild = child.get(Engine);
|
|
|
|
|
|
|
|
expect(engineFromChild).toBe(engineFromParent);
|
|
|
|
});
|
|
|
|
|
2015-05-22 18:39:28 -04:00
|
|
|
it("should not use the child bindings when resolving the dependencies of a parent binding",
|
2015-05-26 04:55:12 -04:00
|
|
|
() => {
|
2015-05-22 18:39:28 -04:00
|
|
|
var parent = Injector.resolveAndCreate([Car, Engine]);
|
|
|
|
var child = parent.resolveAndCreateChild([bind(Engine).toClass(TurboEngine)]);
|
2015-02-05 12:44:50 -05:00
|
|
|
|
2015-05-22 18:39:28 -04:00
|
|
|
var carFromChild = child.get(Car);
|
|
|
|
expect(carFromChild.engine).toBeAnInstanceOf(Engine);
|
|
|
|
});
|
2015-02-05 12:44:50 -05:00
|
|
|
|
2015-05-26 04:55:12 -04:00
|
|
|
it('should create new instance in a child injector', () => {
|
2015-04-10 20:05:31 -04:00
|
|
|
var parent = Injector.resolveAndCreate([Engine]);
|
2015-05-22 18:39:28 -04:00
|
|
|
var child = parent.resolveAndCreateChild([bind(Engine).toClass(TurboEngine)]);
|
2014-10-06 13:45:24 -04:00
|
|
|
|
|
|
|
var engineFromParent = parent.get(Engine);
|
|
|
|
var engineFromChild = child.get(Engine);
|
|
|
|
|
|
|
|
expect(engineFromParent).not.toBe(engineFromChild);
|
|
|
|
expect(engineFromChild).toBeAnInstanceOf(TurboEngine);
|
|
|
|
});
|
2014-10-10 11:36:06 -04:00
|
|
|
|
2015-07-13 18:57:06 -04:00
|
|
|
it("should give access to parent", () => {
|
2015-05-08 19:24:17 -04:00
|
|
|
var parent = Injector.resolveAndCreate([]);
|
|
|
|
var child = parent.resolveAndCreateChild([]);
|
|
|
|
expect(child.parent).toBe(parent);
|
|
|
|
});
|
2014-10-06 13:45:24 -04:00
|
|
|
});
|
|
|
|
|
2015-08-06 13:33:46 -04:00
|
|
|
describe('resolveAndInstantiate', () => {
|
|
|
|
it('should instantiate an object in the context of the injector', () => {
|
|
|
|
var inj = Injector.resolveAndCreate([Engine]);
|
|
|
|
var car = inj.resolveAndInstantiate(Car);
|
|
|
|
expect(car).toBeAnInstanceOf(Car);
|
|
|
|
expect(car.engine).toBe(inj.get(Engine));
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should not store the instantiated object in the injector', () => {
|
|
|
|
var inj = Injector.resolveAndCreate([Engine]);
|
|
|
|
inj.resolveAndInstantiate(Car);
|
|
|
|
expect(() => inj.get(Car)).toThrowError();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
describe('instantiate', () => {
|
|
|
|
it('should instantiate an object in the context of the injector', () => {
|
|
|
|
var inj = Injector.resolveAndCreate([Engine]);
|
|
|
|
var car = inj.instantiateResolved(Injector.resolve([Car])[0]);
|
|
|
|
expect(car).toBeAnInstanceOf(Car);
|
|
|
|
expect(car.engine).toBe(inj.get(Engine));
|
|
|
|
});
|
|
|
|
});
|
2015-07-13 18:57:06 -04:00
|
|
|
|
|
|
|
describe("depedency resolution", () => {
|
|
|
|
describe("@Self()", () => {
|
|
|
|
it("should return a dependency from self", () => {
|
|
|
|
var inj = Injector.resolveAndCreate(
|
|
|
|
[Engine, bind(Car).toFactory((e) => new Car(e), [[Engine, new SelfMetadata()]])]);
|
|
|
|
|
|
|
|
expect(inj.get(Car)).toBeAnInstanceOf(Car);
|
|
|
|
});
|
|
|
|
|
|
|
|
it("should throw when not requested binding on self", () => {
|
|
|
|
var parent = Injector.resolveAndCreate([Engine]);
|
|
|
|
var child = parent.resolveAndCreateChild(
|
|
|
|
[bind(Car).toFactory((e) => new Car(e), [[Engine, new SelfMetadata()]])]);
|
|
|
|
|
|
|
|
expect(() => child.get(Car))
|
|
|
|
.toThrowError(`No provider for Engine! (${stringify(Car)} -> ${stringify(Engine)})`);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2015-07-29 14:26:09 -04:00
|
|
|
describe("@Host()", () => {
|
|
|
|
it("should return a dependency from same host", () => {
|
2015-07-13 18:57:06 -04:00
|
|
|
var parent = Injector.resolveAndCreate([Engine]);
|
|
|
|
var child = parent.resolveAndCreateChild(
|
2015-07-29 14:26:09 -04:00
|
|
|
[bind(Car).toFactory((e) => new Car(e), [[Engine, new HostMetadata()]])]);
|
2015-07-13 18:57:06 -04:00
|
|
|
|
|
|
|
expect(child.get(Car)).toBeAnInstanceOf(Car);
|
|
|
|
});
|
|
|
|
|
2015-07-29 14:26:09 -04:00
|
|
|
it("should return a private dependency declared at the host", () => {
|
2015-07-13 18:57:06 -04:00
|
|
|
var engine = Injector.resolve([Engine])[0];
|
|
|
|
var protoParent = new ProtoInjector([new BindingWithVisibility(engine, PRIVATE)]);
|
|
|
|
var parent = new Injector(protoParent);
|
|
|
|
|
|
|
|
var child = Injector.resolveAndCreate(
|
2015-07-29 14:26:09 -04:00
|
|
|
[bind(Car).toFactory((e) => new Car(e), [[Engine, new HostMetadata()]])]);
|
2015-07-13 18:57:06 -04:00
|
|
|
|
2015-07-29 14:26:09 -04:00
|
|
|
child.internalStrategy.attach(parent, true); // host
|
2015-07-13 18:57:06 -04:00
|
|
|
|
|
|
|
expect(child.get(Car)).toBeAnInstanceOf(Car);
|
|
|
|
});
|
|
|
|
|
2015-07-29 14:26:09 -04:00
|
|
|
it("should not return a public dependency declared at the host", () => {
|
2015-07-13 18:57:06 -04:00
|
|
|
var engine = Injector.resolve([Engine])[0];
|
|
|
|
var protoParent = new ProtoInjector([new BindingWithVisibility(engine, PUBLIC)]);
|
|
|
|
var parent = new Injector(protoParent);
|
|
|
|
|
|
|
|
var child = Injector.resolveAndCreate(
|
2015-07-29 14:26:09 -04:00
|
|
|
[bind(Car).toFactory((e) => new Car(e), [[Engine, new HostMetadata()]])]);
|
2015-07-13 18:57:06 -04:00
|
|
|
|
2015-07-29 14:26:09 -04:00
|
|
|
child.internalStrategy.attach(parent, true); // host
|
2015-07-13 18:57:06 -04:00
|
|
|
|
|
|
|
expect(() => child.get(Car))
|
|
|
|
.toThrowError(`No provider for Engine! (${stringify(Car)} -> ${stringify(Engine)})`);
|
|
|
|
});
|
|
|
|
|
2015-07-29 14:26:09 -04:00
|
|
|
it("should not skip self", () => {
|
2015-07-13 18:57:06 -04:00
|
|
|
var parent = Injector.resolveAndCreate([Engine]);
|
|
|
|
var child = parent.resolveAndCreateChild([
|
|
|
|
bind(Engine)
|
|
|
|
.toClass(TurboEngine),
|
2015-07-29 14:26:09 -04:00
|
|
|
bind(Car).toFactory((e) => new Car(e), [[Engine, new HostMetadata()]])
|
2015-07-13 18:57:06 -04:00
|
|
|
]);
|
|
|
|
|
|
|
|
expect(child.get(Car).engine).toBeAnInstanceOf(TurboEngine);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2015-07-29 14:26:09 -04:00
|
|
|
describe("default", () => {
|
|
|
|
it("should return a private dependency declared at the host", () => {
|
2015-07-13 18:57:06 -04:00
|
|
|
var engine = Injector.resolve([Engine])[0];
|
|
|
|
var protoParent = new ProtoInjector([new BindingWithVisibility(engine, PRIVATE)]);
|
|
|
|
var parent = new Injector(protoParent);
|
|
|
|
|
|
|
|
var child = Injector.resolveAndCreate([
|
|
|
|
bind(Engine)
|
|
|
|
.toClass(BrokenEngine),
|
2015-07-29 14:26:09 -04:00
|
|
|
bind(Car).toFactory((e) => new Car(e), [[Engine, new SkipSelfMetadata()]])
|
2015-07-13 18:57:06 -04:00
|
|
|
]);
|
|
|
|
child.internalStrategy.attach(parent, true); // boundary
|
|
|
|
|
|
|
|
expect(child.get(Car)).toBeAnInstanceOf(Car);
|
|
|
|
});
|
|
|
|
|
2015-07-29 14:26:09 -04:00
|
|
|
it("should return a public dependency declared at the host", () => {
|
2015-07-13 18:57:06 -04:00
|
|
|
var engine = Injector.resolve([Engine])[0];
|
|
|
|
var protoParent = new ProtoInjector([new BindingWithVisibility(engine, PUBLIC)]);
|
|
|
|
var parent = new Injector(protoParent);
|
|
|
|
|
|
|
|
var child = Injector.resolveAndCreate([
|
|
|
|
bind(Engine)
|
|
|
|
.toClass(BrokenEngine),
|
2015-07-29 14:26:09 -04:00
|
|
|
bind(Car).toFactory((e) => new Car(e), [[Engine, new SkipSelfMetadata()]])
|
2015-07-13 18:57:06 -04:00
|
|
|
]);
|
|
|
|
child.internalStrategy.attach(parent, true); // boundary
|
|
|
|
|
|
|
|
expect(child.get(Car)).toBeAnInstanceOf(Car);
|
|
|
|
});
|
|
|
|
|
2015-07-29 14:26:09 -04:00
|
|
|
it("should not return a private dependency declared NOT at the host", () => {
|
2015-07-13 18:57:06 -04:00
|
|
|
var engine = Injector.resolve([Engine])[0];
|
|
|
|
var protoParent = new ProtoInjector([new BindingWithVisibility(engine, PRIVATE)]);
|
|
|
|
var parent = new Injector(protoParent);
|
|
|
|
|
|
|
|
var child = Injector.resolveAndCreate([
|
|
|
|
bind(Engine)
|
|
|
|
.toClass(BrokenEngine),
|
2015-07-29 14:26:09 -04:00
|
|
|
bind(Car).toFactory((e) => new Car(e), [[Engine, new SkipSelfMetadata()]])
|
2015-07-13 18:57:06 -04:00
|
|
|
]);
|
|
|
|
child.internalStrategy.attach(parent, false);
|
|
|
|
|
|
|
|
expect(() => child.get(Car))
|
|
|
|
.toThrowError(`No provider for Engine! (${stringify(Car)} -> ${stringify(Engine)})`);
|
|
|
|
});
|
|
|
|
|
2015-07-29 14:26:09 -04:00
|
|
|
it("should not skip self", () => {
|
2015-07-13 18:57:06 -04:00
|
|
|
var parent = Injector.resolveAndCreate([Engine]);
|
|
|
|
var child = parent.resolveAndCreateChild([
|
|
|
|
bind(Engine)
|
|
|
|
.toClass(TurboEngine),
|
2015-07-29 14:26:09 -04:00
|
|
|
bind(Car).toFactory((e) => new Car(e), [Engine])
|
2015-07-13 18:57:06 -04:00
|
|
|
]);
|
|
|
|
|
|
|
|
expect(child.get(Car).engine).toBeAnInstanceOf(TurboEngine);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
|
2015-05-26 04:55:12 -04:00
|
|
|
describe('resolve', () => {
|
2015-05-13 18:54:46 -04:00
|
|
|
it('should resolve and flatten', () => {
|
2015-04-11 19:57:42 -04:00
|
|
|
var bindings = Injector.resolve([Engine, [BrokenEngine]]);
|
|
|
|
bindings.forEach(function(b) {
|
|
|
|
if (isBlank(b)) return; // the result is a sparse array
|
|
|
|
expect(b instanceof ResolvedBinding).toBe(true);
|
|
|
|
});
|
|
|
|
});
|
2015-05-13 18:54:46 -04:00
|
|
|
|
|
|
|
it('should resolve forward references', () => {
|
|
|
|
var bindings = Injector.resolve([
|
|
|
|
forwardRef(() => Engine),
|
2015-05-22 18:39:28 -04:00
|
|
|
[bind(forwardRef(() => BrokenEngine)).toClass(forwardRef(() => Engine))],
|
2015-06-26 18:59:18 -04:00
|
|
|
bind(forwardRef(() => String)).toFactory(() => 'OK', [forwardRef(() => Engine)])
|
2015-05-13 18:54:46 -04:00
|
|
|
]);
|
|
|
|
|
2015-06-26 18:59:18 -04:00
|
|
|
var engineBinding = bindings[0];
|
|
|
|
var brokenEngineBinding = bindings[1];
|
|
|
|
var stringBinding = bindings[2];
|
2015-05-13 18:54:46 -04:00
|
|
|
|
|
|
|
expect(engineBinding.factory() instanceof Engine).toBe(true);
|
|
|
|
expect(brokenEngineBinding.factory() instanceof Engine).toBe(true);
|
|
|
|
expect(stringBinding.dependencies[0].key).toEqual(Key.get(Engine));
|
|
|
|
});
|
2015-05-21 11:34:48 -04:00
|
|
|
|
2015-05-26 04:55:12 -04:00
|
|
|
it('should support overriding factory dependencies with dependency annotations', () => {
|
2015-06-03 16:42:57 -04:00
|
|
|
var bindings = Injector.resolve([
|
|
|
|
bind("token")
|
|
|
|
.toFactory((e) => "result",
|
2015-07-08 15:04:24 -04:00
|
|
|
[[new InjectMetadata("dep"), new CustomDependencyMetadata()]])
|
2015-06-03 16:42:57 -04:00
|
|
|
]);
|
2015-06-26 18:59:18 -04:00
|
|
|
var binding = bindings[0];
|
2015-05-21 11:34:48 -04:00
|
|
|
|
2015-05-22 18:39:28 -04:00
|
|
|
expect(binding.dependencies[0].key.token).toEqual("dep");
|
2015-07-08 15:04:24 -04:00
|
|
|
expect(binding.dependencies[0].properties).toEqual([new CustomDependencyMetadata()]);
|
2015-05-21 11:34:48 -04:00
|
|
|
});
|
2015-04-11 19:57:42 -04:00
|
|
|
});
|
2015-07-22 15:00:35 -04:00
|
|
|
|
|
|
|
describe("displayName", () => {
|
|
|
|
it("should work", () => {
|
|
|
|
expect(Injector.resolveAndCreate([Engine, BrokenEngine]).displayName)
|
|
|
|
.toEqual('Injector(bindings: [ "Engine" , "BrokenEngine" ])');
|
|
|
|
});
|
|
|
|
});
|
2014-09-30 14:56:33 -04:00
|
|
|
});
|
2015-02-21 09:18:06 -05:00
|
|
|
}
|