angular2
Version:
Angular 2 - a web framework for modern web apps
200 lines (176 loc) • 5.84 kB
text/typescript
import {ReflectiveInjector, Provider, PLATFORM_INITIALIZER} from 'angular2/core';
import {BaseException, ExceptionHandler} from 'angular2/src/facade/exceptions';
import {ListWrapper} from 'angular2/src/facade/collection';
import {FunctionWrapper, isPresent, Type} from 'angular2/src/facade/lang';
import {async} from './async';
import {AsyncTestCompleter} from './async_test_completer';
export {async} from './async';
export class TestInjector {
private _instantiated: boolean = false;
private _injector: ReflectiveInjector = null;
private _providers: Array<Type | Provider | any[]> = [];
reset() {
this._injector = null;
this._providers = [];
this._instantiated = false;
}
platformProviders: Array<Type | Provider | any[]> = [];
applicationProviders: Array<Type | Provider | any[]> = [];
addProviders(providers: Array<Type | Provider | any[]>) {
if (this._instantiated) {
throw new BaseException('Cannot add providers after test injector is instantiated');
}
this._providers = ListWrapper.concat(this._providers, providers);
}
createInjector() {
var rootInjector = ReflectiveInjector.resolveAndCreate(this.platformProviders);
this._injector = rootInjector.resolveAndCreateChild(
ListWrapper.concat(this.applicationProviders, this._providers));
this._instantiated = true;
return this._injector;
}
get(token: any) {
if (!this._instantiated) {
this.createInjector();
}
return this._injector.get(token);
}
execute(tokens: any[], fn: Function): any {
if (!this._instantiated) {
this.createInjector();
}
var params = tokens.map(t => this._injector.get(t));
return FunctionWrapper.apply(fn, params);
}
}
var _testInjector: TestInjector = null;
export function getTestInjector() {
if (_testInjector == null) {
_testInjector = new TestInjector();
}
return _testInjector;
}
/**
* Set the providers that the test injector should use. These should be providers
* common to every test in the suite.
*
* This may only be called once, to set up the common providers for the current test
* suite on teh current platform. If you absolutely need to change the providers,
* first use `resetBaseTestProviders`.
*
* Test Providers for individual platforms are available from
* 'angular2/platform/testing/<platform_name>'.
*/
export function setBaseTestProviders(platformProviders: Array<Type | Provider | any[]>,
applicationProviders: Array<Type | Provider | any[]>) {
var testInjector = getTestInjector();
if (testInjector.platformProviders.length > 0 || testInjector.applicationProviders.length > 0) {
throw new BaseException('Cannot set base providers because it has already been called');
}
testInjector.platformProviders = platformProviders;
testInjector.applicationProviders = applicationProviders;
var injector = testInjector.createInjector();
let inits: Function[] = injector.get(PLATFORM_INITIALIZER, null);
if (isPresent(inits)) {
inits.forEach(init => init());
}
testInjector.reset();
}
/**
* Reset the providers for the test injector.
*/
export function resetBaseTestProviders() {
var testInjector = getTestInjector();
testInjector.platformProviders = [];
testInjector.applicationProviders = [];
testInjector.reset();
}
/**
* Allows injecting dependencies in `beforeEach()` and `it()`.
*
* Example:
*
* ```
* beforeEach(inject([Dependency, AClass], (dep, object) => {
* // some code that uses `dep` and `object`
* // ...
* }));
*
* it('...', inject([AClass], (object) => {
* object.doSomething();
* expect(...);
* })
* ```
*
* Notes:
* - inject is currently a function because of some Traceur limitation the syntax should
* eventually
* becomes `it('...', @Inject (object: AClass, async: AsyncTestCompleter) => { ... });`
*
* @param {Array} tokens
* @param {Function} fn
* @return {Function}
*/
export function inject(tokens: any[], fn: Function): Function {
let testInjector = getTestInjector();
if (tokens.indexOf(AsyncTestCompleter) >= 0) {
// Return an async test method that returns a Promise if AsyncTestCompleter is one of the
// injected tokens.
return () => {
let completer: AsyncTestCompleter = testInjector.get(AsyncTestCompleter);
testInjector.execute(tokens, fn);
return completer.promise;
}
} else {
// Return a synchronous test method with the injected tokens.
return () => { return getTestInjector().execute(tokens, fn); };
}
}
export class InjectSetupWrapper {
constructor(private _providers: () => any) {}
private _addProviders() {
var additionalProviders = this._providers();
if (additionalProviders.length > 0) {
getTestInjector().addProviders(additionalProviders);
}
}
inject(tokens: any[], fn: Function): Function {
return () => {
this._addProviders();
return inject(tokens, fn)();
}
}
/** @Deprecated {use async(withProviders().inject())} */
injectAsync(tokens: any[], fn: Function): Function {
return () => {
this._addProviders();
return injectAsync(tokens, fn)();
}
}
}
export function withProviders(providers: () => any) {
return new InjectSetupWrapper(providers);
}
/**
* @Deprecated {use async(inject())}
*
* Allows injecting dependencies in `beforeEach()` and `it()`. The test must return
* a promise which will resolve when all asynchronous activity is complete.
*
* Example:
*
* ```
* it('...', injectAsync([AClass], (object) => {
* return object.doSomething().then(() => {
* expect(...);
* });
* })
* ```
*
* @param {Array} tokens
* @param {Function} fn
* @return {Function}
*/
export function injectAsync(tokens: any[], fn: Function): Function {
return async(inject(tokens, fn));
}