chore(testing): Refactor test methods to have a uniform interface.
Remove FunctionWithParamTokens. All test wrappers async, fakeAsync and inject now return just a Function instead of FunctionWithParamTokens. This makes them directly consumable by the test framework. Also the test framework code does not have to handle a union of Function and FunctionWithParamTokens everywhere. The Function returned by the above methods are considered asynchronous by the test framework if they return a Promise, synchronous otherwise. Closes #8257
This commit is contained in:
parent
d2efac18ed
commit
35cd0ded22
|
@ -0,0 +1,4 @@
|
|||
// This symbol is not used on the Dart side. This exists just as a stub.
|
||||
async(Function fn) {
|
||||
throw 'async() test wrapper not available for Dart.';
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
/**
|
||||
* 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): Function {
|
||||
return () => {
|
||||
return new Promise<void>((finishCallback, failCallback) => {
|
||||
var AsyncTestZoneSpec = Zone['AsyncTestZoneSpec'];
|
||||
var testZoneSpec = new AsyncTestZoneSpec(finishCallback, failCallback, 'test');
|
||||
var testZone = Zone.current.fork(testZoneSpec);
|
||||
return testZone.run(fn);
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
import {PromiseCompleter} from 'angular2/src/facade/promise';
|
||||
|
||||
/**
|
||||
* Injectable completer that allows signaling completion of an asynchronous test. Used internally.
|
||||
*/
|
||||
export class AsyncTestCompleter {
|
||||
private _completer = new PromiseCompleter<any>();
|
||||
done(value?: any) { this._completer.resolve(value); }
|
||||
|
||||
fail(error?: any, stackTrace?: string) { this._completer.reject(error, stackTrace); }
|
||||
|
||||
get promise(): Promise<any> { return this._completer.promise; }
|
||||
}
|
|
@ -4,8 +4,6 @@ import 'dart:async' show runZoned, ZoneSpecification;
|
|||
import 'package:quiver/testing/async.dart' as quiver;
|
||||
import 'package:angular2/src/facade/exceptions.dart' show BaseException;
|
||||
|
||||
import 'test_injector.dart' show getTestInjector, FunctionWithParamTokens;
|
||||
|
||||
const _u = const Object();
|
||||
|
||||
quiver.FakeAsync _fakeAsync = null;
|
||||
|
@ -22,24 +20,11 @@ quiver.FakeAsync _fakeAsync = null;
|
|||
*
|
||||
* Returns a `Function` that wraps [fn].
|
||||
*/
|
||||
Function fakeAsync(dynamic /* Function | FunctionWithParamTokens */ fn) {
|
||||
Function fakeAsync(Function fn) {
|
||||
if (_fakeAsync != null) {
|
||||
throw 'fakeAsync() calls can not be nested';
|
||||
}
|
||||
|
||||
Function innerFn = null;
|
||||
if (fn is FunctionWithParamTokens) {
|
||||
if (fn.isAsync) {
|
||||
throw 'Cannot wrap async test with fakeAsync';
|
||||
}
|
||||
innerFn = () { getTestInjector().execute(fn); };
|
||||
} else if (fn is Function) {
|
||||
innerFn = fn;
|
||||
} else {
|
||||
throw 'fakeAsync can wrap only test functions but got object of type ' +
|
||||
fn.runtimeType.toString();
|
||||
}
|
||||
|
||||
return ([a0 = _u,
|
||||
a1 = _u,
|
||||
a2 = _u,
|
||||
|
@ -58,7 +43,7 @@ Function fakeAsync(dynamic /* Function | FunctionWithParamTokens */ fn) {
|
|||
List args = [a0, a1, a2, a3, a4, a5, a6, a7, a8, a9]
|
||||
.takeWhile((a) => a != _u)
|
||||
.toList();
|
||||
var res = Function.apply(innerFn, args);
|
||||
var res = Function.apply(fn, args);
|
||||
_fakeAsync.flushMicrotasks();
|
||||
|
||||
if (async.periodicTimerCount > 0) {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import {BaseException} from 'angular2/src/facade/exceptions';
|
||||
import {getTestInjector, FunctionWithParamTokens} from './test_injector';
|
||||
import {getTestInjector} from './test_injector';
|
||||
|
||||
let _FakeAsyncTestZoneSpecType = Zone['FakeAsyncTestZoneSpec'];
|
||||
|
||||
|
@ -19,7 +19,7 @@ let _FakeAsyncTestZoneSpecType = Zone['FakeAsyncTestZoneSpec'];
|
|||
* @param fn
|
||||
* @returns {Function} The function wrapped to be executed in the fakeAsync zone
|
||||
*/
|
||||
export function fakeAsync(fn: Function | FunctionWithParamTokens): Function {
|
||||
export function fakeAsync(fn: Function): Function {
|
||||
if (Zone.current.get('FakeAsyncTestZoneSpec') != null) {
|
||||
throw new BaseException('fakeAsync() calls can not be nested');
|
||||
}
|
||||
|
@ -27,20 +27,9 @@ export function fakeAsync(fn: Function | FunctionWithParamTokens): Function {
|
|||
let fakeAsyncTestZoneSpec = new _FakeAsyncTestZoneSpecType();
|
||||
let fakeAsyncZone = Zone.current.fork(fakeAsyncTestZoneSpec);
|
||||
|
||||
let innerTestFn: Function = null;
|
||||
|
||||
if (fn instanceof FunctionWithParamTokens) {
|
||||
if (fn.isAsync) {
|
||||
throw new BaseException('Cannot wrap async test with fakeAsync');
|
||||
}
|
||||
innerTestFn = () => { getTestInjector().execute(fn as FunctionWithParamTokens); };
|
||||
} else {
|
||||
innerTestFn = fn;
|
||||
}
|
||||
|
||||
return function(...args) {
|
||||
let res = fakeAsyncZone.run(() => {
|
||||
let res = innerTestFn(...args);
|
||||
let res = fn(...args);
|
||||
flushMicrotasks();
|
||||
return res;
|
||||
});
|
||||
|
|
|
@ -3,6 +3,11 @@ 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;
|
||||
|
||||
|
@ -35,15 +40,19 @@ export class TestInjector {
|
|||
return this._injector;
|
||||
}
|
||||
|
||||
execute(fn: FunctionWithParamTokens): any {
|
||||
var additionalProviders = fn.additionalProviders();
|
||||
if (additionalProviders.length > 0) {
|
||||
this.addProviders(additionalProviders);
|
||||
}
|
||||
get(token: any) {
|
||||
if (!this._instantiated) {
|
||||
this.createInjector();
|
||||
}
|
||||
return fn.execute(this._injector);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -117,22 +126,47 @@ export function resetBaseTestProviders() {
|
|||
*
|
||||
* @param {Array} tokens
|
||||
* @param {Function} fn
|
||||
* @return {FunctionWithParamTokens}
|
||||
* @return {Function}
|
||||
*/
|
||||
export function inject(tokens: any[], fn: Function): FunctionWithParamTokens {
|
||||
return new FunctionWithParamTokens(tokens, fn, false);
|
||||
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) {}
|
||||
|
||||
inject(tokens: any[], fn: Function): FunctionWithParamTokens {
|
||||
return new FunctionWithParamTokens(tokens, fn, false, this._providers);
|
||||
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): FunctionWithParamTokens {
|
||||
return new FunctionWithParamTokens(tokens, fn, true, this._providers);
|
||||
injectAsync(tokens: any[], fn: Function): Function {
|
||||
return () => {
|
||||
this._addProviders();
|
||||
return injectAsync(tokens, fn)();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -158,53 +192,8 @@ export function withProviders(providers: () => any) {
|
|||
*
|
||||
* @param {Array} tokens
|
||||
* @param {Function} fn
|
||||
* @return {FunctionWithParamTokens}
|
||||
* @return {Function}
|
||||
*/
|
||||
export function injectAsync(tokens: any[], fn: Function): FunctionWithParamTokens {
|
||||
return new FunctionWithParamTokens(tokens, fn, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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>)');
|
||||
}
|
||||
}
|
||||
|
||||
function emptyArray(): Array<any> {
|
||||
return [];
|
||||
}
|
||||
|
||||
export class FunctionWithParamTokens {
|
||||
constructor(private _tokens: any[], public fn: Function, public isAsync: boolean,
|
||||
public additionalProviders: () => any = emptyArray) {}
|
||||
|
||||
/**
|
||||
* Returns the value of the executed function.
|
||||
*/
|
||||
execute(injector: ReflectiveInjector): any {
|
||||
var params = this._tokens.map(t => injector.get(t));
|
||||
return FunctionWrapper.apply(this.fn, params);
|
||||
}
|
||||
|
||||
hasToken(token: any): boolean { return this._tokens.indexOf(token) > -1; }
|
||||
export function injectAsync(tokens: any[], fn: Function): Function {
|
||||
return async(inject(tokens, fn));
|
||||
}
|
||||
|
|
|
@ -2,18 +2,9 @@
|
|||
* Public Test Library for unit testing Angular2 Applications. Uses the
|
||||
* Jasmine framework.
|
||||
*/
|
||||
import {global} from 'angular2/src/facade/lang';
|
||||
import {ListWrapper} from 'angular2/src/facade/collection';
|
||||
import {bind} from 'angular2/core';
|
||||
import {global, isPromise} from 'angular2/src/facade/lang';
|
||||
|
||||
import {
|
||||
FunctionWithParamTokens,
|
||||
inject,
|
||||
async,
|
||||
injectAsync,
|
||||
TestInjector,
|
||||
getTestInjector
|
||||
} from './test_injector';
|
||||
import {inject, async, injectAsync, TestInjector, getTestInjector} from './test_injector';
|
||||
|
||||
export {inject, async, injectAsync} from './test_injector';
|
||||
|
||||
|
@ -73,22 +64,6 @@ export var fdescribe: Function = _global.fdescribe;
|
|||
*/
|
||||
export var xdescribe: Function = _global.xdescribe;
|
||||
|
||||
/**
|
||||
* Signature for a synchronous test function (no arguments).
|
||||
*/
|
||||
export type SyncTestFn = () => void;
|
||||
|
||||
/**
|
||||
* Signature for an asynchronous test function which takes a
|
||||
* `done` callback.
|
||||
*/
|
||||
export type AsyncTestFn = (done: () => void) => void;
|
||||
|
||||
/**
|
||||
* Signature for any simple testing function.
|
||||
*/
|
||||
export type AnyTestFn = SyncTestFn | AsyncTestFn | Function;
|
||||
|
||||
var jsmBeforeEach = _global.beforeEach;
|
||||
var jsmIt = _global.it;
|
||||
var jsmIIt = _global.fit;
|
||||
|
@ -123,35 +98,27 @@ export function beforeEachProviders(fn): void {
|
|||
});
|
||||
}
|
||||
|
||||
function runInAsyncTestZone(fnToExecute, finishCallback: Function, failCallback: Function,
|
||||
testName = ''): any {
|
||||
var AsyncTestZoneSpec = Zone['AsyncTestZoneSpec'];
|
||||
var testZoneSpec = new AsyncTestZoneSpec(finishCallback, failCallback, testName);
|
||||
var testZone = Zone.current.fork(testZoneSpec);
|
||||
return testZone.run(fnToExecute);
|
||||
}
|
||||
|
||||
function _isPromiseLike(input): boolean {
|
||||
return input && !!(input.then);
|
||||
}
|
||||
|
||||
function _it(jsmFn: Function, name: string, testFn: FunctionWithParamTokens | AnyTestFn,
|
||||
testTimeOut: number): void {
|
||||
var timeOut = testTimeOut;
|
||||
if (testFn instanceof FunctionWithParamTokens) {
|
||||
let testFnT = testFn;
|
||||
jsmFn(name, (done) => {
|
||||
if (testFnT.isAsync) {
|
||||
runInAsyncTestZone(() => testInjector.execute(testFnT), done, done.fail, name);
|
||||
function _wrapTestFn(fn: Function) {
|
||||
// Wraps a test or beforeEach function to handle synchronous and asynchronous execution.
|
||||
return (done: any) => {
|
||||
if (fn.length === 0) {
|
||||
let retVal = fn();
|
||||
if (isPromise(retVal)) {
|
||||
// Asynchronous test function - wait for completion.
|
||||
(<Promise<any>>retVal).then(done, done.fail);
|
||||
} else {
|
||||
testInjector.execute(testFnT);
|
||||
// Synchronous test function - complete immediately.
|
||||
done();
|
||||
}
|
||||
}, timeOut);
|
||||
} else {
|
||||
// The test case doesn't use inject(). ie `it('test', (done) => { ... }));`
|
||||
jsmFn(name, testFn, timeOut);
|
||||
}
|
||||
} else {
|
||||
// Asynchronous test function that takes "done" as parameter.
|
||||
fn(done);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function _it(jsmFn: Function, name: string, testFn: Function, testTimeOut: number): void {
|
||||
jsmFn(name, _wrapTestFn(testFn), testTimeOut);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -165,27 +132,8 @@ function _it(jsmFn: Function, name: string, testFn: FunctionWithParamTokens | An
|
|||
*
|
||||
* {@example testing/ts/testing.ts region='beforeEach'}
|
||||
*/
|
||||
export function beforeEach(fn: FunctionWithParamTokens | AnyTestFn): void {
|
||||
if (fn instanceof FunctionWithParamTokens) {
|
||||
// The test case uses inject(). ie `beforeEach(inject([ClassA], (a) => { ...
|
||||
// }));`
|
||||
let fnT = fn;
|
||||
jsmBeforeEach((done) => {
|
||||
if (fnT.isAsync) {
|
||||
runInAsyncTestZone(() => testInjector.execute(fnT), done, done.fail, 'beforeEach');
|
||||
} else {
|
||||
testInjector.execute(fnT);
|
||||
done();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// The test case doesn't use inject(). ie `beforeEach((done) => { ... }));`
|
||||
if ((<any>fn).length === 0) {
|
||||
jsmBeforeEach(() => { (<SyncTestFn>fn)(); });
|
||||
} else {
|
||||
jsmBeforeEach((done) => { (<AsyncTestFn>fn)(done); });
|
||||
}
|
||||
}
|
||||
export function beforeEach(fn: Function): void {
|
||||
jsmBeforeEach(_wrapTestFn(fn));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -200,8 +148,7 @@ export function beforeEach(fn: FunctionWithParamTokens | AnyTestFn): void {
|
|||
*
|
||||
* {@example testing/ts/testing.ts region='describeIt'}
|
||||
*/
|
||||
export function it(name: string, fn: FunctionWithParamTokens | AnyTestFn,
|
||||
timeOut: number = null): void {
|
||||
export function it(name: string, fn: Function, timeOut: number = null): void {
|
||||
return _it(jsmIt, name, fn, timeOut);
|
||||
}
|
||||
|
||||
|
@ -216,16 +163,14 @@ export function it(name: string, fn: FunctionWithParamTokens | AnyTestFn,
|
|||
*
|
||||
* {@example testing/ts/testing.ts region='xit'}
|
||||
*/
|
||||
export function xit(name: string, fn: FunctionWithParamTokens | AnyTestFn,
|
||||
timeOut: number = null): void {
|
||||
export function xit(name: string, fn: Function, timeOut: number = null): void {
|
||||
return _it(jsmXIt, name, fn, timeOut);
|
||||
}
|
||||
|
||||
/**
|
||||
* See {@link fit}.
|
||||
*/
|
||||
export function iit(name: string, fn: FunctionWithParamTokens | AnyTestFn,
|
||||
timeOut: number = null): void {
|
||||
export function iit(name: string, fn: Function, timeOut: number = null): void {
|
||||
return _it(jsmIIt, name, fn, timeOut);
|
||||
}
|
||||
|
||||
|
@ -239,7 +184,6 @@ export function iit(name: string, fn: FunctionWithParamTokens | AnyTestFn,
|
|||
*
|
||||
* {@example testing/ts/testing.ts region='fit'}
|
||||
*/
|
||||
export function fit(name: string, fn: FunctionWithParamTokens | AnyTestFn,
|
||||
timeOut: number = null): void {
|
||||
export function fit(name: string, fn: Function, timeOut: number = null): void {
|
||||
return _it(jsmIIt, name, fn, timeOut);
|
||||
}
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
import {StringMapWrapper} from 'angular2/src/facade/collection';
|
||||
import {global, isFunction, Math} from 'angular2/src/facade/lang';
|
||||
import {global, isPromise, Math} from 'angular2/src/facade/lang';
|
||||
|
||||
import {provide} from 'angular2/core';
|
||||
|
||||
import {getTestInjector, FunctionWithParamTokens, inject} from './test_injector';
|
||||
import {AsyncTestCompleter} from './async_test_completer';
|
||||
import {getTestInjector, inject} from './test_injector';
|
||||
import {browserDetection} from './utils';
|
||||
import {NgZone} from 'angular2/src/core/zone/ng_zone';
|
||||
|
||||
export {AsyncTestCompleter} from './async_test_completer';
|
||||
export {inject} from './test_injector';
|
||||
|
||||
export {expect, NgMatchers} from './matchers';
|
||||
|
@ -17,19 +18,6 @@ var _global = <any>(typeof window === 'undefined' ? global : window);
|
|||
|
||||
export var afterEach: Function = _global.afterEach;
|
||||
|
||||
export type SyncTestFn = () => void;
|
||||
type AsyncTestFn = (done: () => void) => void;
|
||||
type AnyTestFn = SyncTestFn | AsyncTestFn;
|
||||
|
||||
/**
|
||||
* Injectable completer that allows signaling completion of an asynchronous test. Used internally.
|
||||
*/
|
||||
export class AsyncTestCompleter {
|
||||
constructor(private _done: Function) {}
|
||||
|
||||
done(): void { this._done(); }
|
||||
}
|
||||
|
||||
var jsmBeforeEach = _global.beforeEach;
|
||||
var jsmDescribe = _global.describe;
|
||||
var jsmDDescribe = _global.fdescribe;
|
||||
|
@ -51,18 +39,15 @@ var testInjector = getTestInjector();
|
|||
* Note: Jasmine own `beforeEach` is used by this library to handle DI providers.
|
||||
*/
|
||||
class BeforeEachRunner {
|
||||
private _fns: Array<FunctionWithParamTokens | SyncTestFn> = [];
|
||||
private _fns: Array<Function> = [];
|
||||
|
||||
constructor(private _parent: BeforeEachRunner) {}
|
||||
|
||||
beforeEach(fn: FunctionWithParamTokens | SyncTestFn): void { this._fns.push(fn); }
|
||||
beforeEach(fn: Function): void { this._fns.push(fn); }
|
||||
|
||||
run(): void {
|
||||
if (this._parent) this._parent.run();
|
||||
this._fns.forEach((fn) => {
|
||||
return isFunction(fn) ? (<SyncTestFn>fn)() :
|
||||
(testInjector.execute(<FunctionWithParamTokens>fn));
|
||||
});
|
||||
this._fns.forEach((fn) => { fn(); });
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -90,13 +75,13 @@ export function xdescribe(...args): void {
|
|||
return _describe(jsmXDescribe, ...args);
|
||||
}
|
||||
|
||||
export function beforeEach(fn: FunctionWithParamTokens | SyncTestFn): void {
|
||||
export function beforeEach(fn: Function): void {
|
||||
if (runnerStack.length > 0) {
|
||||
// Inside a describe block, beforeEach() uses a BeforeEachRunner
|
||||
runnerStack[runnerStack.length - 1].beforeEach(fn);
|
||||
} else {
|
||||
// Top level beforeEach() are delegated to jasmine
|
||||
jsmBeforeEach(<SyncTestFn>fn);
|
||||
jsmBeforeEach(fn);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -127,55 +112,37 @@ export function beforeEachBindings(fn): void {
|
|||
beforeEachProviders(fn);
|
||||
}
|
||||
|
||||
function _it(jsmFn: Function, name: string, testFn: FunctionWithParamTokens | AnyTestFn,
|
||||
testTimeOut: number): void {
|
||||
function _it(jsmFn: Function, name: string, testFn: Function, testTimeOut: number): void {
|
||||
var runner = runnerStack[runnerStack.length - 1];
|
||||
var timeOut = Math.max(globalTimeOut, testTimeOut);
|
||||
|
||||
if (testFn instanceof FunctionWithParamTokens) {
|
||||
// The test case uses inject(). ie `it('test', inject([AsyncTestCompleter], (async) => { ...
|
||||
// }));`
|
||||
let testFnT = testFn;
|
||||
jsmFn(name, (done) => {
|
||||
var completerProvider = provide(AsyncTestCompleter, {
|
||||
useFactory: () => {
|
||||
// Mark the test as async when an AsyncTestCompleter is injected in an it()
|
||||
if (!inIt) throw new Error('AsyncTestCompleter can only be injected in an "it()"');
|
||||
return new AsyncTestCompleter();
|
||||
}
|
||||
});
|
||||
testInjector.addProviders([completerProvider]);
|
||||
runner.run();
|
||||
|
||||
if (testFn.hasToken(AsyncTestCompleter)) {
|
||||
jsmFn(name, (done) => {
|
||||
var completerProvider = provide(AsyncTestCompleter, {
|
||||
useFactory: () => {
|
||||
// Mark the test as async when an AsyncTestCompleter is injected in an it()
|
||||
if (!inIt) throw new Error('AsyncTestCompleter can only be injected in an "it()"');
|
||||
return new AsyncTestCompleter(done);
|
||||
}
|
||||
});
|
||||
|
||||
testInjector.addProviders([completerProvider]);
|
||||
runner.run();
|
||||
|
||||
inIt = true;
|
||||
testInjector.execute(testFnT);
|
||||
inIt = false;
|
||||
}, timeOut);
|
||||
inIt = true;
|
||||
if (testFn.length == 0) {
|
||||
let retVal = testFn();
|
||||
if (isPromise(retVal)) {
|
||||
// Asynchronous test function that returns a Promise - wait for completion.
|
||||
(<Promise<any>>retVal).then(done, done.fail);
|
||||
} else {
|
||||
// Synchronous test function - complete immediately.
|
||||
done();
|
||||
}
|
||||
} else {
|
||||
jsmFn(name, () => {
|
||||
runner.run();
|
||||
testInjector.execute(testFnT);
|
||||
}, timeOut);
|
||||
// Asynchronous test function that takes in 'done' parameter.
|
||||
testFn(done);
|
||||
}
|
||||
|
||||
} else {
|
||||
// The test case doesn't use inject(). ie `it('test', (done) => { ... }));`
|
||||
|
||||
if ((<any>testFn).length === 0) {
|
||||
jsmFn(name, () => {
|
||||
runner.run();
|
||||
(<SyncTestFn>testFn)();
|
||||
}, timeOut);
|
||||
} else {
|
||||
jsmFn(name, (done) => {
|
||||
runner.run();
|
||||
(<AsyncTestFn>testFn)(done);
|
||||
}, timeOut);
|
||||
}
|
||||
}
|
||||
inIt = false;
|
||||
}, timeOut);
|
||||
}
|
||||
|
||||
export function it(name, fn, timeOut = null): void {
|
||||
|
@ -190,7 +157,6 @@ export function iit(name, fn, timeOut = null): void {
|
|||
return _it(jsmIIt, name, fn, timeOut);
|
||||
}
|
||||
|
||||
|
||||
export interface GuinessCompatibleSpy extends jasmine.Spy {
|
||||
/** By chaining the spy with and.returnValue, all calls to the function will return a specific
|
||||
* value. */
|
||||
|
|
|
@ -26,31 +26,18 @@ import 'package:angular2/src/core/reflection/reflection_capabilities.dart';
|
|||
import 'package:angular2/src/core/di/provider.dart' show bind;
|
||||
import 'package:angular2/src/facade/collection.dart' show StringMapWrapper;
|
||||
|
||||
import 'async_test_completer.dart';
|
||||
export 'async_test_completer.dart' show AsyncTestCompleter;
|
||||
|
||||
import 'test_injector.dart';
|
||||
export 'test_injector.dart' show inject;
|
||||
|
||||
TestInjector _testInjector = getTestInjector();
|
||||
bool _isCurrentTestAsync;
|
||||
Future _currentTestFuture;
|
||||
bool _inIt = false;
|
||||
bool _initialized = false;
|
||||
List<dynamic> _platformProviders = [];
|
||||
List<dynamic> _applicationProviders = [];
|
||||
|
||||
class AsyncTestCompleter {
|
||||
final _completer = new Completer();
|
||||
|
||||
AsyncTestCompleter() {
|
||||
_currentTestFuture = this.future;
|
||||
}
|
||||
|
||||
void done() {
|
||||
_completer.complete();
|
||||
}
|
||||
|
||||
Future get future => _completer.future;
|
||||
}
|
||||
|
||||
void setDartBaseTestProviders(List<dynamic> platform, List<dynamic> application) {
|
||||
_platformProviders = platform;
|
||||
_applicationProviders = application;
|
||||
|
@ -70,18 +57,15 @@ void testSetup() {
|
|||
|
||||
gns.beforeEach(() {
|
||||
_testInjector.reset();
|
||||
_currentTestFuture = null;
|
||||
});
|
||||
|
||||
var completerProvider = bind(AsyncTestCompleter).toFactory(() {
|
||||
// Mark the test as async when an AsyncTestCompleter is injected in an it(),
|
||||
if (!_inIt) throw 'AsyncTestCompleter can only be injected in an "it()"';
|
||||
_isCurrentTestAsync = true;
|
||||
return new AsyncTestCompleter();
|
||||
});
|
||||
|
||||
gns.beforeEach(() {
|
||||
_isCurrentTestAsync = false;
|
||||
_testInjector.addProviders([completerProvider]);
|
||||
});
|
||||
}
|
||||
|
@ -113,22 +97,16 @@ void beforeEachBindings(Function fn) {
|
|||
|
||||
void beforeEach(fn) {
|
||||
testSetup();
|
||||
if (fn is! FunctionWithParamTokens) fn =
|
||||
new FunctionWithParamTokens([], fn, false);
|
||||
gns.beforeEach(() {
|
||||
_testInjector.execute(fn);
|
||||
});
|
||||
gns.beforeEach(fn);
|
||||
}
|
||||
|
||||
void _it(gnsFn, name, fn) {
|
||||
testSetup();
|
||||
if (fn is! FunctionWithParamTokens) fn =
|
||||
new FunctionWithParamTokens([], fn, false);
|
||||
gnsFn(name, () {
|
||||
_inIt = true;
|
||||
_testInjector.execute(fn);
|
||||
var retVal = fn();
|
||||
_inIt = false;
|
||||
if (_isCurrentTestAsync) return _currentTestFuture;
|
||||
return retVal;
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -150,6 +150,19 @@ export function main() {
|
|||
expect(value).toEqual('async value');
|
||||
})));
|
||||
|
||||
it('should allow use of "done"', (done) => {
|
||||
inject([FancyService], (service) => {
|
||||
let count = 0;
|
||||
let id = setInterval(() => {
|
||||
count++;
|
||||
if (count > 2) {
|
||||
clearInterval(id);
|
||||
done();
|
||||
}
|
||||
}, 5);
|
||||
})(); // inject needs to be invoked explicitly with ().
|
||||
});
|
||||
|
||||
describe('using beforeEach', () => {
|
||||
beforeEach(inject([FancyService],
|
||||
(service) => { service.value = 'value modified in beforeEach'; }));
|
||||
|
@ -174,6 +187,15 @@ export function main() {
|
|||
withProviders(() => [bind(FancyService).toValue(new FancyService())])
|
||||
.inject([FancyService],
|
||||
(service) => { expect(service.value).toEqual('real value'); }));
|
||||
|
||||
it('should return value from inject', () => {
|
||||
let retval = withProviders(() => [bind(FancyService).toValue(new FancyService())])
|
||||
.inject([FancyService], (service) => {
|
||||
expect(service.value).toEqual('real value');
|
||||
return 10;
|
||||
})();
|
||||
expect(retval).toBe(10);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -79,8 +79,7 @@ dynamic _runInjectableFunction(Function fn) {
|
|||
tokens.add(token);
|
||||
}
|
||||
|
||||
var injectFn = new FunctionWithParamTokens(tokens, fn, false);
|
||||
return _testInjector.execute(injectFn);
|
||||
return _testInjector.execute(tokens, fn);
|
||||
}
|
||||
|
||||
/// Use the test injector to get bindings and run a function.
|
||||
|
|
Loading…
Reference in New Issue