2016-04-14 15:35:24 -04:00
|
|
|
import {ReflectiveInjector, Provider, PLATFORM_INITIALIZER} from 'angular2/core';
|
2015-12-08 22:03:21 -05:00
|
|
|
import {BaseException, ExceptionHandler} from 'angular2/src/facade/exceptions';
|
2015-11-06 20:34:07 -05:00
|
|
|
import {ListWrapper} from 'angular2/src/facade/collection';
|
2015-12-15 19:38:27 -05:00
|
|
|
import {FunctionWrapper, isPresent, Type} from 'angular2/src/facade/lang';
|
2015-12-03 16:31:11 -05:00
|
|
|
|
2015-12-08 22:03:21 -05:00
|
|
|
export class TestInjector {
|
|
|
|
private _instantiated: boolean = false;
|
|
|
|
|
2016-04-14 15:35:24 -04:00
|
|
|
private _injector: ReflectiveInjector = null;
|
2015-12-08 22:03:21 -05:00
|
|
|
|
2016-04-12 12:40:37 -04:00
|
|
|
private _providers: Array<Type | Provider | any[]> = [];
|
2015-12-08 22:03:21 -05:00
|
|
|
|
|
|
|
reset() {
|
|
|
|
this._injector = null;
|
|
|
|
this._providers = [];
|
|
|
|
this._instantiated = false;
|
|
|
|
}
|
|
|
|
|
2016-04-12 12:40:37 -04:00
|
|
|
platformProviders: Array<Type | Provider | any[]> = [];
|
2015-12-15 19:38:27 -05:00
|
|
|
|
2016-04-12 12:40:37 -04:00
|
|
|
applicationProviders: Array<Type | Provider | any[]> = [];
|
2015-12-15 19:38:27 -05:00
|
|
|
|
2016-04-12 12:40:37 -04:00
|
|
|
addProviders(providers: Array<Type | Provider | any[]>) {
|
2015-12-08 22:03:21 -05:00
|
|
|
if (this._instantiated) {
|
|
|
|
throw new BaseException('Cannot add providers after test injector is instantiated');
|
|
|
|
}
|
|
|
|
this._providers = ListWrapper.concat(this._providers, providers);
|
|
|
|
}
|
|
|
|
|
|
|
|
createInjector() {
|
2016-04-14 15:35:24 -04:00
|
|
|
var rootInjector = ReflectiveInjector.resolveAndCreate(this.platformProviders);
|
2015-12-15 19:38:27 -05:00
|
|
|
this._injector = rootInjector.resolveAndCreateChild(
|
|
|
|
ListWrapper.concat(this.applicationProviders, this._providers));
|
2015-12-08 22:03:21 -05:00
|
|
|
this._instantiated = true;
|
|
|
|
return this._injector;
|
|
|
|
}
|
|
|
|
|
|
|
|
execute(fn: FunctionWithParamTokens): any {
|
2015-12-10 15:00:48 -05:00
|
|
|
var additionalProviders = fn.additionalProviders();
|
|
|
|
if (additionalProviders.length > 0) {
|
|
|
|
this.addProviders(additionalProviders);
|
|
|
|
}
|
2015-12-08 22:03:21 -05:00
|
|
|
if (!this._instantiated) {
|
|
|
|
this.createInjector();
|
|
|
|
}
|
|
|
|
return fn.execute(this._injector);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
var _testInjector: TestInjector = null;
|
|
|
|
|
|
|
|
export function getTestInjector() {
|
|
|
|
if (_testInjector == null) {
|
|
|
|
_testInjector = new TestInjector();
|
|
|
|
}
|
|
|
|
return _testInjector;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2015-12-15 19:38:27 -05:00
|
|
|
* 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>'.
|
2015-12-08 22:03:21 -05:00
|
|
|
*/
|
2016-04-12 12:40:37 -04:00
|
|
|
export function setBaseTestProviders(platformProviders: Array<Type | Provider | any[]>,
|
|
|
|
applicationProviders: Array<Type | Provider | any[]>) {
|
2015-12-15 19:38:27 -05:00
|
|
|
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();
|
2016-04-14 15:35:24 -04:00
|
|
|
let inits: Function[] = injector.get(PLATFORM_INITIALIZER, null);
|
2015-12-15 19:38:27 -05:00
|
|
|
if (isPresent(inits)) {
|
|
|
|
inits.forEach(init => init());
|
|
|
|
}
|
|
|
|
testInjector.reset();
|
2015-03-13 06:10:11 -04:00
|
|
|
}
|
|
|
|
|
2015-12-08 22:03:21 -05:00
|
|
|
/**
|
2015-12-15 19:38:27 -05:00
|
|
|
* Reset the providers for the test injector.
|
2015-12-08 22:03:21 -05:00
|
|
|
*/
|
2015-12-15 19:38:27 -05:00
|
|
|
export function resetBaseTestProviders() {
|
|
|
|
var testInjector = getTestInjector();
|
|
|
|
testInjector.platformProviders = [];
|
|
|
|
testInjector.applicationProviders = [];
|
|
|
|
testInjector.reset();
|
2015-12-03 16:31:11 -05:00
|
|
|
}
|
|
|
|
|
2015-03-13 16:52:59 -04:00
|
|
|
/**
|
2015-12-08 19:44:04 -05:00
|
|
|
* Allows injecting dependencies in `beforeEach()` and `it()`.
|
2015-03-13 06:10:11 -04:00
|
|
|
*
|
|
|
|
* Example:
|
|
|
|
*
|
2015-03-13 13:48:29 -04:00
|
|
|
* ```
|
|
|
|
* beforeEach(inject([Dependency, AClass], (dep, object) => {
|
|
|
|
* // some code that uses `dep` and `object`
|
|
|
|
* // ...
|
|
|
|
* }));
|
2015-03-13 06:10:11 -04:00
|
|
|
*
|
2015-11-18 21:46:24 -05:00
|
|
|
* it('...', inject([AClass], (object) => {
|
2015-12-08 19:44:04 -05:00
|
|
|
* object.doSomething();
|
|
|
|
* expect(...);
|
2015-03-13 13:48:29 -04:00
|
|
|
* })
|
|
|
|
* ```
|
2015-03-13 06:10:11 -04:00
|
|
|
*
|
|
|
|
* Notes:
|
2015-12-08 22:03:21 -05:00
|
|
|
* - inject is currently a function because of some Traceur limitation the syntax should
|
|
|
|
* eventually
|
2015-03-13 06:10:11 -04:00
|
|
|
* becomes `it('...', @Inject (object: AClass, async: AsyncTestCompleter) => { ... });`
|
|
|
|
*
|
|
|
|
* @param {Array} tokens
|
|
|
|
* @param {Function} fn
|
|
|
|
* @return {FunctionWithParamTokens}
|
|
|
|
*/
|
2015-08-28 14:29:19 -04:00
|
|
|
export function inject(tokens: any[], fn: Function): FunctionWithParamTokens {
|
2015-10-08 18:33:17 -04:00
|
|
|
return new FunctionWithParamTokens(tokens, fn, false);
|
|
|
|
}
|
|
|
|
|
2015-12-10 15:00:48 -05:00
|
|
|
export class InjectSetupWrapper {
|
|
|
|
constructor(private _providers: () => any) {}
|
|
|
|
|
|
|
|
inject(tokens: any[], fn: Function): FunctionWithParamTokens {
|
|
|
|
return new FunctionWithParamTokens(tokens, fn, false, this._providers);
|
|
|
|
}
|
|
|
|
|
feat(tests): manage asynchronous tests using zones
Instead of using injectAsync and returning a promise, use the `async` function
to wrap tests. This will run the test inside a zone which does not complete
the test until all asynchronous tasks have been completed.
`async` may be used with the `inject` function, or separately.
BREAKING CHANGE:
`injectAsync` is now deprecated. Instead, use the `async` function
to wrap any asynchronous tests.
Before:
```
it('should wait for returned promises', injectAsync([FancyService], (service) => {
return service.getAsyncValue().then((value) => { expect(value).toEqual('async value'); });
}));
it('should wait for returned promises', injectAsync([], () => {
return somePromise.then(() => { expect(true).toEqual(true); });
}));
```
After:
```
it('should wait for returned promises', async(inject([FancyService], (service) => {
service.getAsyncValue().then((value) => { expect(value).toEqual('async value'); });
})));
// Note that if there is no injection, we no longer need `inject` OR `injectAsync`.
it('should wait for returned promises', async(() => {
somePromise.then() => { expect(true).toEqual(true); });
}));
```
Closes #7735
2016-03-23 13:59:38 -04:00
|
|
|
/** @Deprecated {use async(withProviders().inject())} */
|
2015-12-10 15:00:48 -05:00
|
|
|
injectAsync(tokens: any[], fn: Function): FunctionWithParamTokens {
|
|
|
|
return new FunctionWithParamTokens(tokens, fn, true, this._providers);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
export function withProviders(providers: () => any) {
|
|
|
|
return new InjectSetupWrapper(providers);
|
|
|
|
}
|
|
|
|
|
2015-11-18 21:46:24 -05:00
|
|
|
/**
|
feat(tests): manage asynchronous tests using zones
Instead of using injectAsync and returning a promise, use the `async` function
to wrap tests. This will run the test inside a zone which does not complete
the test until all asynchronous tasks have been completed.
`async` may be used with the `inject` function, or separately.
BREAKING CHANGE:
`injectAsync` is now deprecated. Instead, use the `async` function
to wrap any asynchronous tests.
Before:
```
it('should wait for returned promises', injectAsync([FancyService], (service) => {
return service.getAsyncValue().then((value) => { expect(value).toEqual('async value'); });
}));
it('should wait for returned promises', injectAsync([], () => {
return somePromise.then(() => { expect(true).toEqual(true); });
}));
```
After:
```
it('should wait for returned promises', async(inject([FancyService], (service) => {
service.getAsyncValue().then((value) => { expect(value).toEqual('async value'); });
})));
// Note that if there is no injection, we no longer need `inject` OR `injectAsync`.
it('should wait for returned promises', async(() => {
somePromise.then() => { expect(true).toEqual(true); });
}));
```
Closes #7735
2016-03-23 13:59:38 -04:00
|
|
|
* @Deprecated {use async(inject())}
|
|
|
|
*
|
2015-12-08 19:44:04 -05:00
|
|
|
* 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 {FunctionWithParamTokens}
|
2015-11-18 21:46:24 -05:00
|
|
|
*/
|
2015-10-08 18:33:17 -04:00
|
|
|
export function injectAsync(tokens: any[], fn: Function): FunctionWithParamTokens {
|
|
|
|
return new FunctionWithParamTokens(tokens, fn, true);
|
2015-03-13 06:10:11 -04:00
|
|
|
}
|
|
|
|
|
feat(tests): manage asynchronous tests using zones
Instead of using injectAsync and returning a promise, use the `async` function
to wrap tests. This will run the test inside a zone which does not complete
the test until all asynchronous tasks have been completed.
`async` may be used with the `inject` function, or separately.
BREAKING CHANGE:
`injectAsync` is now deprecated. Instead, use the `async` function
to wrap any asynchronous tests.
Before:
```
it('should wait for returned promises', injectAsync([FancyService], (service) => {
return service.getAsyncValue().then((value) => { expect(value).toEqual('async value'); });
}));
it('should wait for returned promises', injectAsync([], () => {
return somePromise.then(() => { expect(true).toEqual(true); });
}));
```
After:
```
it('should wait for returned promises', async(inject([FancyService], (service) => {
service.getAsyncValue().then((value) => { expect(value).toEqual('async value'); });
})));
// Note that if there is no injection, we no longer need `inject` OR `injectAsync`.
it('should wait for returned promises', async(() => {
somePromise.then() => { expect(true).toEqual(true); });
}));
```
Closes #7735
2016-03-23 13:59:38 -04:00
|
|
|
/**
|
|
|
|
* Wraps a test function in an asynchronous test zone. The test will automatically
|
|
|
|
* complete when all asynchronous calls within this zone are done. Can be used
|
|
|
|
* to wrap an {@link inject} call.
|
|
|
|
*
|
|
|
|
* Example:
|
|
|
|
*
|
|
|
|
* ```
|
|
|
|
* it('...', async(inject([AClass], (object) => {
|
|
|
|
* object.doSomething.then(() => {
|
|
|
|
* expect(...);
|
|
|
|
* })
|
|
|
|
* });
|
|
|
|
* ```
|
|
|
|
*/
|
|
|
|
export function async(fn: Function | FunctionWithParamTokens): FunctionWithParamTokens {
|
|
|
|
if (fn instanceof FunctionWithParamTokens) {
|
|
|
|
fn.isAsync = true;
|
|
|
|
return fn;
|
|
|
|
} else if (fn instanceof Function) {
|
|
|
|
return new FunctionWithParamTokens([], fn, true);
|
|
|
|
} else {
|
|
|
|
throw new BaseException('argument to async must be a function or inject(<Function>)');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-12-10 15:00:48 -05:00
|
|
|
function emptyArray(): Array<any> {
|
|
|
|
return [];
|
|
|
|
}
|
|
|
|
|
2015-03-13 06:10:11 -04:00
|
|
|
export class FunctionWithParamTokens {
|
2016-04-18 19:04:35 -04:00
|
|
|
constructor(private _tokens: any[], public fn: Function, public isAsync: boolean,
|
2016-04-12 12:40:37 -04:00
|
|
|
public additionalProviders: () => any = emptyArray) {}
|
2015-03-13 06:10:11 -04:00
|
|
|
|
2015-07-17 18:00:52 -04:00
|
|
|
/**
|
|
|
|
* Returns the value of the executed function.
|
|
|
|
*/
|
2016-04-14 15:35:24 -04:00
|
|
|
execute(injector: ReflectiveInjector): any {
|
2015-10-06 21:00:42 -04:00
|
|
|
var params = this._tokens.map(t => injector.get(t));
|
2016-04-18 19:04:35 -04:00
|
|
|
return FunctionWrapper.apply(this.fn, params);
|
2015-03-13 06:10:11 -04:00
|
|
|
}
|
2015-08-28 19:23:28 -04:00
|
|
|
|
|
|
|
hasToken(token: any): boolean { return this._tokens.indexOf(token) > -1; }
|
2015-03-13 06:10:11 -04:00
|
|
|
}
|