Skip to content

Commit 44a991e

Browse files
committed
refactor(test_lib): do not execute jasmine test as async if not required
fixes angular#3893
1 parent 46f751b commit 44a991e

File tree

2 files changed

+73
-52
lines changed

2 files changed

+73
-52
lines changed

modules/angular2/src/test_lib/test_injector.ts

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -195,13 +195,7 @@ export function inject(tokens: any[], fn: Function): FunctionWithParamTokens {
195195
}
196196

197197
export class FunctionWithParamTokens {
198-
_tokens: any[];
199-
_fn: Function;
200-
201-
constructor(tokens: any[], fn: Function) {
202-
this._tokens = tokens;
203-
this._fn = fn;
204-
}
198+
constructor(private _tokens: any[], private _fn: Function) {}
205199

206200
/**
207201
* Returns the value of the executed function.
@@ -210,4 +204,6 @@ export class FunctionWithParamTokens {
210204
var params = ListWrapper.map(this._tokens, (t) => injector.get(t));
211205
return FunctionWrapper.apply(this._fn, params);
212206
}
207+
208+
hasToken(token: any): boolean { return this._tokens.indexOf(token) > -1; }
213209
}

modules/angular2/src/test_lib/test_lib.ts

Lines changed: 70 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import {DOM} from 'angular2/src/core/dom/dom_adapter';
44
import {StringMapWrapper} from 'angular2/src/core/facade/collection';
5-
import {global} from 'angular2/src/core/facade/lang';
5+
import {global, isFunction} from 'angular2/src/core/facade/lang';
66
import {NgZoneZone} from 'angular2/src/core/zone/ng_zone';
77

88
import {bind} from 'angular2/di';
@@ -18,6 +18,10 @@ var _global: jasmine.GlobalPolluter = <any>(typeof window === 'undefined' ? glob
1818

1919
export var afterEach = _global.afterEach;
2020

21+
type SyncTestFn = () => void;
22+
type AsyncTestFn = (done: () => void) => void;
23+
type AnyTestFn = SyncTestFn | AsyncTestFn;
24+
2125
export interface NgMatchers extends jasmine.Matchers {
2226
toBe(expected: any): boolean;
2327
toEqual(expected: any): boolean;
@@ -34,11 +38,9 @@ export interface NgMatchers extends jasmine.Matchers {
3438
export var expect: (actual: any) => NgMatchers = <any>_global.expect;
3539

3640
export class AsyncTestCompleter {
37-
_done: Function;
38-
39-
constructor(done: Function) { this._done = done; }
41+
constructor(private _done: Function) {}
4042

41-
done() { this._done(); }
43+
done(): void { this._done(); }
4244
}
4345

4446
var jsmBeforeEach = _global.beforeEach;
@@ -54,19 +56,23 @@ var inIt = false;
5456

5557
var testBindings;
5658

59+
/**
60+
* Mechanism to run `beforeEach()` functions of Angular tests.
61+
*
62+
* Note: Jasmine own `beforeEach` is used by this library to handle DI bindings.
63+
*/
5764
class BeforeEachRunner {
58-
_fns: FunctionWithParamTokens[];
59-
_parent: BeforeEachRunner;
60-
constructor(parent: BeforeEachRunner) {
61-
this._fns = [];
62-
this._parent = parent;
63-
}
65+
private _fns: Array<FunctionWithParamTokens | SyncTestFn> = [];
6466

65-
beforeEach(fn: FunctionWithParamTokens) { this._fns.push(fn); }
67+
constructor(private _parent: BeforeEachRunner) {}
6668

67-
run(injector) {
69+
beforeEach(fn: FunctionWithParamTokens | SyncTestFn): void { this._fns.push(fn); }
70+
71+
run(injector): void {
6872
if (this._parent) this._parent.run(injector);
69-
this._fns.forEach((fn) => fn.execute(injector));
73+
this._fns.forEach((fn) => {
74+
return isFunction(fn) ? (<SyncTestFn>fn)() : (<FunctionWithParamTokens>fn).execute(injector);
75+
});
7076
}
7177
}
7278

@@ -94,17 +100,13 @@ export function xdescribe(...args) {
94100
return _describe(jsmXDescribe, ...args);
95101
}
96102

97-
export function beforeEach(fn) {
103+
export function beforeEach(fn: FunctionWithParamTokens | SyncTestFn) {
98104
if (runnerStack.length > 0) {
99105
// Inside a describe block, beforeEach() uses a BeforeEachRunner
100-
var runner = runnerStack[runnerStack.length - 1];
101-
if (!(fn instanceof FunctionWithParamTokens)) {
102-
fn = inject([], fn);
103-
}
104-
runner.beforeEach(fn);
106+
runnerStack[runnerStack.length - 1].beforeEach(fn);
105107
} else {
106108
// Top level beforeEach() are delegated to jasmine
107-
jsmBeforeEach(fn);
109+
jsmBeforeEach(<SyncTestFn>fn);
108110
}
109111
}
110112

@@ -128,34 +130,57 @@ export function beforeEachBindings(fn) {
128130
});
129131
}
130132

131-
function _it(jsmFn, name, fn, timeOut) {
133+
function _it(jsmFn: Function, name: string, testFn: FunctionWithParamTokens | AnyTestFn,
134+
timeOut: number) {
132135
var runner = runnerStack[runnerStack.length - 1];
133136

134-
jsmFn(name, function(done) {
135-
var async = false;
136-
137-
var completerBinding =
138-
bind(AsyncTestCompleter)
139-
.toFactory(() => {
140-
// Mark the test as async when an AsyncTestCompleter is injected in an it()
141-
if (!inIt) throw new Error('AsyncTestCompleter can only be injected in an "it()"');
142-
async = true;
143-
return new AsyncTestCompleter(done);
144-
});
145-
146-
var injector = createTestInjector([...testBindings, completerBinding]);
147-
runner.run(injector);
148-
149-
if (!(fn instanceof FunctionWithParamTokens)) {
150-
fn = inject([], fn);
137+
if (testFn instanceof FunctionWithParamTokens) {
138+
// The test case uses inject(). ie `it('test', inject([AsyncTestCompleter], (async) => { ...
139+
// }));`
140+
141+
if (testFn.hasToken(AsyncTestCompleter)) {
142+
jsmFn(name, (done) => {
143+
var completerBinding =
144+
bind(AsyncTestCompleter)
145+
.toFactory(() => {
146+
// Mark the test as async when an AsyncTestCompleter is injected in an it()
147+
if (!inIt)
148+
throw new Error('AsyncTestCompleter can only be injected in an "it()"');
149+
return new AsyncTestCompleter(done);
150+
});
151+
152+
var injector = createTestInjector([...testBindings, completerBinding]);
153+
runner.run(injector);
154+
155+
inIt = true;
156+
testFn.execute(injector);
157+
inIt = false;
158+
}, timeOut);
159+
} else {
160+
jsmFn(name, () => {
161+
var injector = createTestInjector(testBindings);
162+
runner.run(injector);
163+
testFn.execute(injector);
164+
}, timeOut);
151165
}
152166

153-
inIt = true;
154-
fn.execute(injector);
155-
inIt = false;
156-
157-
if (!async) done();
158-
}, timeOut);
167+
} else {
168+
// The test case doesn't use inject(). ie `it('test', (done) => { ... }));`
169+
170+
if ((<any>testFn).length === 0) {
171+
jsmFn(name, () => {
172+
var injector = createTestInjector(testBindings);
173+
runner.run(injector);
174+
(<SyncTestFn>testFn)();
175+
}, timeOut);
176+
} else {
177+
jsmFn(name, (done) => {
178+
var injector = createTestInjector(testBindings);
179+
runner.run(injector);
180+
(<AsyncTestFn>testFn)(done);
181+
}, timeOut);
182+
}
183+
}
159184
}
160185

161186
export function it(name, fn, timeOut = null) {

0 commit comments

Comments
 (0)