@@ -72,47 +72,44 @@ function wrapInControlFlow(globalFn, fnName) {
7272 var driverError = new Error ( ) ;
7373 driverError . stack = driverError . stack . replace ( / + a t .+ j a s m i n e w d .+ \n / , '' ) ;
7474
75- function asyncTestFn ( fn , desc ) {
75+ function asyncTestFn ( fn ) {
7676 return function ( done ) {
77- var desc_ = 'Asynchronous test function: ' + fnName + '(' ;
78- if ( desc ) {
79- desc_ += '"' + desc + '"' ;
80- }
81- desc_ += ')' ;
82-
8377 // deferred object for signaling completion of asychronous function within globalFn
84- var asyncFnDone = webdriver . promise . defer ( ) ;
78+ var asyncFnDone = webdriver . promise . defer ( ) ,
79+ originalFail = jasmine . getEnv ( ) . fail ;
8580
8681 if ( fn . length === 0 ) {
8782 // function with globalFn not asychronous
8883 asyncFnDone . fulfill ( ) ;
8984 } else if ( fn . length > 1 ) {
9085 throw Error ( 'Invalid # arguments (' + fn . length + ') within function "' + fnName + '"' ) ;
86+ } else {
87+ // Add fail method to async done callback and override env fail to
88+ // reject async done promise
89+ jasmine . getEnv ( ) . fail = asyncFnDone . fulfill . fail = function ( userError ) {
90+ asyncFnDone . reject ( new Error ( userError ) ) ;
91+ } ;
9192 }
9293
9394 var flowFinished = flow . execute ( function ( ) {
94- fn . call ( jasmine . getEnv ( ) . currentSpec , function ( userError ) {
95- if ( userError ) {
96- asyncFnDone . reject ( new Error ( userError ) ) ;
97- } else {
98- asyncFnDone . fulfill ( ) ;
99- }
100- } ) ;
101- } , desc_ ) ;
95+ fn . call ( jasmine . getEnv ( ) , asyncFnDone . fulfill ) ;
96+ } ) ;
10297
10398 webdriver . promise . all ( [ asyncFnDone , flowFinished ] ) . then ( function ( ) {
99+ jasmine . getEnv ( ) . fail = originalFail ;
104100 seal ( done ) ( ) ;
105101 } , function ( e ) {
106- e . stack = e . stack + '==== async task ====\n' + driverError . stack ;
107- done ( e ) ;
102+ jasmine . getEnv ( ) . fail = originalFail ;
103+ e . stack = e . stack + '\n==== async task ====\n' + driverError . stack ;
104+ done . fail ( e ) ;
108105 } ) ;
109106 } ;
110107 }
111108
112109 var description , func , timeout ;
113110 switch ( fnName ) {
114111 case 'it' :
115- case 'iit ' :
112+ case 'fit ' :
116113 description = validateString ( arguments [ 0 ] ) ;
117114 func = validateFunction ( arguments [ 1 ] ) ;
118115 if ( ! arguments [ 2 ] ) {
@@ -124,6 +121,8 @@ function wrapInControlFlow(globalFn, fnName) {
124121 break ;
125122 case 'beforeEach' :
126123 case 'afterEach' :
124+ case 'beforeAll' :
125+ case 'afterAll' :
127126 func = validateFunction ( arguments [ 0 ] ) ;
128127 if ( ! arguments [ 1 ] ) {
129128 globalFn ( asyncTestFn ( func ) ) ;
@@ -139,117 +138,99 @@ function wrapInControlFlow(globalFn, fnName) {
139138}
140139
141140global . it = wrapInControlFlow ( global . it , 'it' ) ;
142- global . iit = wrapInControlFlow ( global . iit , 'iit ' ) ;
141+ global . fit = wrapInControlFlow ( global . fit , 'fit ' ) ;
143142global . beforeEach = wrapInControlFlow ( global . beforeEach , 'beforeEach' ) ;
144143global . afterEach = wrapInControlFlow ( global . afterEach , 'afterEach' ) ;
144+ global . beforeAll = wrapInControlFlow ( global . beforeAll , 'beforeAll' ) ;
145+ global . afterAll = wrapInControlFlow ( global . afterAll , 'afterAll' ) ;
145146
147+ var originalExpect = global . expect ;
148+ global . expect = function ( actual ) {
149+ if ( actual instanceof webdriver . WebElement ) {
150+ throw 'expect called with WebElement argument, expected a Promise. ' +
151+ 'Did you mean to use .getText()?' ;
152+ }
153+ return originalExpect ( actual ) ;
154+ } ;
146155
147156/**
148- * Wrap a Jasmine matcher function so that it can take webdriverJS promises.
149- * @param {!Function } matcher The matcher function to wrap.
150- * @param {webdriver.promise.Promise } actualPromise The promise which will
151- * resolve to the actual value being tested.
152- * @param {boolean } not Whether this is being called with 'not' active.
157+ * Creates a matcher wrapper that resolves any promises given for actual and
158+ * expected values, as well as the `pass` property of the result.
153159 */
154- function wrapMatcher ( matcher , actualPromise , not ) {
160+ jasmine . Expectation . prototype . wrapCompare = function ( name , matcherFactory ) {
155161 return function ( ) {
156- var originalArgs = arguments ;
157- var matchError = new Error ( "Failed expectation" ) ;
158- matchError . stack = matchError . stack . replace ( / + a t .+ j a s m i n e w d .+ \n / , '' ) ;
159- actualPromise . then ( function ( actual ) {
160- var expected = originalArgs [ 0 ] ;
162+ var expected = Array . prototype . slice . call ( arguments , 0 ) ,
163+ expectation = this ,
164+ matchError = new Error ( "Failed expectation" ) ;
161165
162- var expectation = originalExpect ( actual ) ;
163- if ( not ) {
164- expectation = expectation . not ;
165- }
166- var originalAddMatcherResult = expectation . spec . addMatcherResult ;
167- var error = matchError ;
168- expectation . spec . addMatcherResult = function ( result ) {
169- result . trace = error ;
170- jasmine . Spec . prototype . addMatcherResult . call ( this , result ) ;
171- } ;
166+ matchError . stack = matchError . stack . replace ( / + a t .+ j a s m i n e w d .+ \n / , '' ) ;
172167
173- if ( webdriver . promise . isPromise ( expected ) ) {
174- if ( originalArgs . length > 1 ) {
175- throw error ( 'Multi-argument matchers with promises are not ' +
176- 'supported.' ) ;
177- }
178- expected . then ( function ( exp ) {
179- expectation [ matcher ] . apply ( expectation , [ exp ] ) ;
180- expectation . spec . addMatcherResult = originalAddMatcherResult ;
168+ flow . execute ( function ( ) {
169+ return webdriver . promise . when ( expectation . actual ) . then ( function ( actual ) {
170+ return webdriver . promise . all ( expected ) . then ( function ( expected ) {
171+ return compare ( actual , expected ) ;
181172 } ) ;
182- } else {
183- expectation . spec . addMatcherResult = function ( result ) {
184- result . trace = error ;
185- originalAddMatcherResult . call ( this , result ) ;
186- } ;
187- expectation [ matcher ] . apply ( expectation , originalArgs ) ;
188- expectation . spec . addMatcherResult = originalAddMatcherResult ;
189- }
173+ } ) ;
190174 } ) ;
191- } ;
192- }
193175
194- /**
195- * Return a chained set of matcher functions which will be evaluated
196- * after actualPromise is resolved.
197- * @param {webdriver.promise.Promise } actualPromise The promise which will
198- * resolve to the actual value being tested.
199- */
200- function promiseMatchers ( actualPromise ) {
201- var promises = { not : { } } ;
202- var env = jasmine . getEnv ( ) ;
203- var matchersClass = env . currentSpec . matchersClass || env . matchersClass ;
176+ function compare ( actual , expected ) {
177+ var args = expected . slice ( 0 ) ;
178+ args . unshift ( actual ) ;
204179
205- for ( var matcher in matchersClass . prototype ) {
206- promises [ matcher ] = wrapMatcher ( matcher , actualPromise , false ) ;
207- promises . not [ matcher ] = wrapMatcher ( matcher , actualPromise , true ) ;
208- }
180+ var matcher = matcherFactory ( expectation . util , expectation . customEqualityTesters ) ;
181+ var matcherCompare = matcher . compare ;
209182
210- return promises ;
211- }
183+ if ( expectation . isNot ) {
184+ matcherCompare = matcher . negativeCompare || defaultNegativeCompare ;
185+ }
212186
213- var originalExpect = global . expect ;
187+ var result = matcherCompare . apply ( null , args ) ;
214188
215- global . expect = function ( actual ) {
216- if ( actual instanceof webdriver . WebElement ) {
217- throw 'expect called with WebElement argument, expected a Promise. ' +
218- 'Did you mean to use .getText()?' ;
219- }
220- if ( webdriver . promise . isPromise ( actual ) ) {
221- return promiseMatchers ( actual ) ;
222- } else {
223- return originalExpect ( actual ) ;
224- }
225- } ;
189+ return webdriver . promise . when ( result . pass ) . then ( function ( pass ) {
190+ var message = "" ;
226191
227- // Wrap internal Jasmine function to allow custom matchers
228- // to return promises that resolve to truthy or falsy values
229- var originalMatcherFn = jasmine . Matchers . matcherFn_ ;
230- jasmine . Matchers . matcherFn_ = function ( matcherName , matcherFunction ) {
231- var matcherFnThis = this ;
232- var matcherFnArgs = jasmine . util . argsToArray ( arguments ) ;
233- return function ( ) {
234- var matcherThis = this ;
235- var matcherArgs = jasmine . util . argsToArray ( arguments ) ;
236- var result = matcherFunction . apply ( this , arguments ) ;
192+ if ( ! pass ) {
193+ if ( ! result . message ) {
194+ args . unshift ( expectation . isNot ) ;
195+ args . unshift ( name ) ;
196+ message = expectation . util . buildFailureMessage . apply ( null , args ) ;
197+ } else {
198+ message = result . message ;
199+ }
200+ }
237201
238- if ( webdriver . promise . isPromise ( result ) ) {
239- result . then ( function ( resolution ) {
240- matcherFnArgs [ 1 ] = function ( ) {
241- return resolution ;
202+ if ( expected . length == 1 ) {
203+ expected = expected [ 0 ] ;
204+ }
205+ var res = {
206+ matcherName : name ,
207+ passed : pass ,
208+ message : message ,
209+ actual : actual ,
210+ expected : expected ,
211+ error : matchError
242212 } ;
243- originalMatcherFn . apply ( matcherFnThis , matcherFnArgs ) .
244- apply ( matcherThis , matcherArgs ) ;
213+ expectation . addExpectationResult ( pass , res ) ;
245214 } ) ;
246- } else {
247- originalMatcherFn . apply ( matcherFnThis , matcherFnArgs ) .
248- apply ( matcherThis , matcherArgs ) ;
215+
216+ function defaultNegativeCompare ( ) {
217+ var result = matcher . compare . apply ( null , args ) ;
218+ if ( webdriver . promise . isPromise ( result . pass ) ) {
219+ result . pass = result . pass . then ( function ( pass ) {
220+ return ! pass ;
221+ } ) ;
222+ } else {
223+ result . pass = ! result . pass ;
224+ }
225+ return result ;
226+ }
249227 }
250228 } ;
251229} ;
252230
231+ // Re-add core matchers so they are wrapped.
232+ jasmine . Expectation . addCoreMatchers ( jasmine . matchers ) ;
233+
253234/**
254235 * A Jasmine reporter which does nothing but execute the input function
255236 * on a timeout failure.
@@ -258,30 +239,17 @@ var OnTimeoutReporter = function(fn) {
258239 this . callback = fn ;
259240} ;
260241
261- OnTimeoutReporter . prototype . reportRunnerStarting = function ( ) { } ;
262- OnTimeoutReporter . prototype . reportRunnerResults = function ( ) { } ;
263- OnTimeoutReporter . prototype . reportSuiteResults = function ( ) { } ;
264- OnTimeoutReporter . prototype . reportSpecStarting = function ( ) { } ;
265- OnTimeoutReporter . prototype . reportSpecResults = function ( spec ) {
266- if ( ! spec . results ( ) . passed ( ) ) {
267- var result = spec . results ( ) ;
268- var failureItem = null ;
242+ OnTimeoutReporter . prototype . specDone = function ( result ) {
243+ if ( result . status === 'failed' ) {
244+ for ( var i = 0 ; i < result . failedExpectations . length ; i ++ ) {
245+ var failureMessage = result . failedExpectations [ i ] . message ;
269246
270- var items_length = result . getItems ( ) . length ;
271- for ( var i = 0 ; i < items_length ; i ++ ) {
272- if ( result . getItems ( ) [ i ] . passed_ === false ) {
273- failureItem = result . getItems ( ) [ i ] ;
274-
275- var jasmineTimeoutRegexp =
276- / t i m e d o u t a f t e r \d + m s e c w a i t i n g f o r s p e c t o c o m p l e t e / ;
277- if ( failureItem . toString ( ) . match ( jasmineTimeoutRegexp ) ) {
278- this . callback ( ) ;
279- }
247+ if ( failureMessage . match ( / T i m e o u t / ) ) {
248+ this . callback ( ) ;
280249 }
281250 }
282251 }
283252} ;
284- OnTimeoutReporter . prototype . log = function ( ) { } ;
285253
286254// On timeout, the flow should be reset. This will prevent webdriver tasks
287255// from overflowing into the next test and causing it to fail or timeout
@@ -292,7 +260,7 @@ jasmine.getEnv().addReporter(new OnTimeoutReporter(function() {
292260 console . warn ( 'A Jasmine spec timed out. Resetting the WebDriver Control Flow.' ) ;
293261 console . warn ( 'The last active task was: ' ) ;
294262 console . warn (
295- ( flow . activeFrame_ && flow . activeFrame_ . getPendingTask ( ) ?
263+ ( flow . activeFrame_ && flow . activeFrame_ . getPendingTask ( ) ?
296264 flow . activeFrame_ . getPendingTask ( ) . toString ( ) :
297265 'unknown' ) ) ;
298266 flow . reset ( ) ;
0 commit comments