X Tutup
Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 7 additions & 5 deletions modules/angular2/src/testing/test_injector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,9 @@ export function createTestInjector(providers: Array<Type | Provider | any[]>): I
}

/**
* Allows injecting dependencies in `beforeEach()` and `it()`.
* Allows injecting dependencies in `beforeEach()` and `it()`. When using with the
* `angular2/testing` library, the test function will be run within a zone and will
* automatically complete when all asynchronous tests have finished.
*
* Example:
*
Expand All @@ -133,17 +135,14 @@ export function createTestInjector(providers: Array<Type | Provider | any[]>): I
* // ...
* }));
*
* it('...', inject([AClass, AsyncTestCompleter], (object, async) => {
* it('...', inject([AClass], (object) => {
* object.doSomething().then(() => {
* expect(...);
* async.done();
* });
* })
* ```
*
* Notes:
* - injecting an `AsyncTestCompleter` allow completing async tests - this is the equivalent of
* adding a `done` parameter in Jasmine,
* - inject is currently a function because of some Traceur limitation the syntax should eventually
* becomes `it('...', @Inject (object: AClass, async: AsyncTestCompleter) => { ... });`
*
Expand All @@ -155,6 +154,9 @@ export function inject(tokens: any[], fn: Function): FunctionWithParamTokens {
return new FunctionWithParamTokens(tokens, fn, false);
}

/**
* @deprecated Use inject instead, which now supports both synchronous and asynchronous tests.
*/
export function injectAsync(tokens: any[], fn: Function): FunctionWithParamTokens {
return new FunctionWithParamTokens(tokens, fn, true);
}
Expand Down
188 changes: 135 additions & 53 deletions modules/angular2/src/testing/testing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* Jasmine framework.
*/
import {global} from 'angular2/src/facade/lang';

import {ListWrapper} from 'angular2/src/facade/collection';
import {bind} from 'angular2/src/core/di';

import {createTestInjector, FunctionWithParamTokens, inject, injectAsync} from './test_injector';
Expand All @@ -14,10 +14,29 @@ export {expect, NgMatchers} from './matchers';

var _global: jasmine.GlobalPolluter = <any>(typeof window === 'undefined' ? global : window);

/**
* See http://jasmine.github.io/
*/
export var afterEach: Function = _global.afterEach;

/**
* See http://jasmine.github.io/
*/
export var describe: Function = _global.describe;

/**
* See http://jasmine.github.io/
*/
export var ddescribe: Function = _global.fdescribe;

/**
* See http://jasmine.github.io/
*/
export var fdescribe: Function = _global.fdescribe;

/**
* See http://jasmine.github.io/
*/
export var xdescribe: Function = _global.xdescribe;

export type SyncTestFn = () => void;
Expand All @@ -40,16 +59,18 @@ jsmBeforeEach(() => {

/**
* Allows overriding default providers of the test injector,
* defined in test_injector.js.
* which are defined in test_injector.js.
*
* The given function must return a list of DI providers.
*
* Example:
*
* ```
* beforeEachProviders(() => [
* bind(Compiler).toClass(MockCompiler),
* bind(SomeToken).toValue(myValue),
* ]);
* ```
*/
export function beforeEachProviders(fn): void {
jsmBeforeEach(() => {
Expand All @@ -68,72 +89,101 @@ function _isPromiseLike(input): boolean {
return input && !!(input.then);
}

function runInTestZone(fnToExecute, finishCallback, failCallback): any {
var pendingMicrotasks = 0;
var pendingTimeouts = [];

var ngTestZone = (<Zone>global.zone)
.fork({
onError: function(e) { failCallback(e); },
'$run': function(parentRun) {
return function() {
try {
return parentRun.apply(this, arguments);
} finally {
if (pendingMicrotasks == 0 && pendingTimeouts.length == 0) {
finishCallback();
}
}
};
},
'$scheduleMicrotask': function(parentScheduleMicrotask) {
return function(fn) {
pendingMicrotasks++;
var microtask = function() {
try {
fn();
} finally {
pendingMicrotasks--;
}
};
parentScheduleMicrotask.call(this, microtask);
};
},
'$setTimeout': function(parentSetTimeout) {
return function(fn: Function, delay: number, ...args) {
var id;
var cb = function() {
fn();
ListWrapper.remove(pendingTimeouts, id);
};
id = parentSetTimeout(cb, delay, args);
pendingTimeouts.push(id);
return id;
};
},
'$clearTimeout': function(parentClearTimeout) {
return function(id: number) {
parentClearTimeout(id);
ListWrapper.remove(pendingTimeouts, id);
};
},
});

return ngTestZone.run(fnToExecute);
}

function _it(jsmFn: Function, name: string, testFn: FunctionWithParamTokens | AnyTestFn,
testTimeOut: number): void {
var timeOut = testTimeOut;

if (testFn instanceof FunctionWithParamTokens) {
// The test case uses inject(). ie `it('test', inject([ClassA], (a) => { ...
// }));`
if (testFn.isAsync) {
jsmFn(name, (done) => {
if (!injector) {
injector = createTestInjector(testProviders);
}
var returned = testFn.execute(injector);
if (_isPromiseLike(returned)) {
returned.then(done, done.fail);
} else {
done.fail('Error: injectAsync was expected to return a promise, but the ' +
' returned value was: ' + returned);
}
}, timeOut);
} else {
jsmFn(name, () => {
if (!injector) {
injector = createTestInjector(testProviders);
}
var returned = testFn.execute(injector);
if (_isPromiseLike(returned)) {
throw new Error('inject returned a promise. Did you mean to use injectAsync?');
};
});
}
jsmFn(name, (done) => {
if (!injector) {
injector = createTestInjector(testProviders);
}

var returnedTestValue = runInTestZone(() => testFn.execute(injector), done, done.fail);
if (_isPromiseLike(returnedTestValue)) {
(<Promise<any>>returnedTestValue).then(null, (err) => { done.fail(err); });
}
}, timeOut);
} else {
// The test case doesn't use inject(). ie `it('test', (done) => { ... }));`
jsmFn(name, testFn, timeOut);
}
}


/**
* Wrapper around Jasmine beforeEach function.
* See http://jasmine.github.io/
*
* beforeEach may be used with the `inject` function to fetch dependencies.
* The test will automatically wait for any asynchronous calls inside the
* injected test function to complete.
*/
export function beforeEach(fn: FunctionWithParamTokens | AnyTestFn): void {
if (fn instanceof FunctionWithParamTokens) {
// The test case uses inject(). ie `beforeEach(inject([ClassA], (a) => { ...
// }));`
if (fn.isAsync) {
jsmBeforeEach((done) => {
if (!injector) {
injector = createTestInjector(testProviders);
}
var returned = fn.execute(injector);
if (_isPromiseLike(returned)) {
returned.then(done, done.fail);
} else {
done.fail('Error: injectAsync was expected to return a promise, but the ' +
' returned value was: ' + returned);
}
});
} else {
jsmBeforeEach(() => {
if (!injector) {
injector = createTestInjector(testProviders);
}
var returned = fn.execute(injector);
if (_isPromiseLike(returned)) {
throw new Error('inject returned a promise. Did you mean to use injectAsync?');
};
});
}

jsmBeforeEach((done) => {
if (!injector) {
injector = createTestInjector(testProviders);
}

runInTestZone(() => fn.execute(injector), done, done.fail);
});
} else {
// The test case doesn't use inject(). ie `beforeEach((done) => { ... }));`
if ((<any>fn).length === 0) {
Expand All @@ -144,21 +194,53 @@ export function beforeEach(fn: FunctionWithParamTokens | AnyTestFn): void {
}
}

/**
* Wrapper around Jasmine it function.
* See http://jasmine.github.io/
*
* it may be used with the `inject` function to fetch dependencies.
* The test will automatically wait for any asynchronous calls inside the
* injected test function to complete.
*/
export function it(name: string, fn: FunctionWithParamTokens | AnyTestFn,
timeOut: number = null): void {
return _it(jsmIt, name, fn, timeOut);
}

/**
* Wrapper around Jasmine xit (skipped it) function.
* See http://jasmine.github.io/
*
* it may be used with the `inject` function to fetch dependencies.
* The test will automatically wait for any asynchronous calls inside the
* injected test function to complete.
*/
export function xit(name: string, fn: FunctionWithParamTokens | AnyTestFn,
timeOut: number = null): void {
return _it(jsmXIt, name, fn, timeOut);
}

/**
* Wrapper around Jasmine iit (focused it) function.
* See http://jasmine.github.io/
*
* it may be used with the `inject` function to fetch dependencies.
* The test will automatically wait for any asynchronous calls inside the
* injected test function to complete.
*/
export function iit(name: string, fn: FunctionWithParamTokens | AnyTestFn,
timeOut: number = null): void {
return _it(jsmIIt, name, fn, timeOut);
}

/**
* Wrapper around Jasmine fit (focused it) function.
* See http://jasmine.github.io/
*
* it may be used with the `inject` function to fetch dependencies.
* The test will automatically wait for any asynchronous calls inside the
* injected test function to complete.
*/
export function fit(name: string, fn: FunctionWithParamTokens | AnyTestFn,
timeOut: number = null): void {
return _it(jsmIIt, name, fn, timeOut);
Expand Down
Loading
X Tutup