22
33import { DOM } from 'angular2/src/core/dom/dom_adapter' ;
44import { 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' ;
66import { NgZoneZone } from 'angular2/src/core/zone/ng_zone' ;
77
88import { bind } from 'angular2/di' ;
@@ -18,6 +18,10 @@ var _global: jasmine.GlobalPolluter = <any>(typeof window === 'undefined' ? glob
1818
1919export var afterEach = _global . afterEach ;
2020
21+ type SyncTestFn = ( ) => void ;
22+ type AsyncTestFn = ( done : ( ) => void ) => void ;
23+ type AnyTestFn = SyncTestFn | AsyncTestFn ;
24+
2125export 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 {
3438export var expect : ( actual : any ) => NgMatchers = < any > _global . expect ;
3539
3640export 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
4446var jsmBeforeEach = _global . beforeEach ;
@@ -54,19 +56,23 @@ var inIt = false;
5456
5557var 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+ */
5764class 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
161186export function it ( name , fn , timeOut = null ) {
0 commit comments