angularjs-rails 1.2.14 → 1.2.15

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,13 +1,14 @@
1
1
  /**
2
- * @license AngularJS v1.1.5
3
- * (c) 2010-2012 Google, Inc. http://angularjs.org
2
+ * @license AngularJS v1.3.0-beta.3
3
+ * (c) 2010-2014 Google, Inc. http://angularjs.org
4
4
  * License: MIT
5
- *
6
- * TODO(vojta): wrap whole file into closure during build
7
5
  */
6
+ (function(window, angular, undefined) {
7
+
8
+ 'use strict';
8
9
 
9
10
  /**
10
- * @ngdoc overview
11
+ * @ngdoc object
11
12
  * @name angular.mock
12
13
  * @description
13
14
  *
@@ -18,7 +19,7 @@ angular.mock = {};
18
19
  /**
19
20
  * ! This is a private undocumented service !
20
21
  *
21
- * @name ngMock.$browser
22
+ * @name $browser
22
23
  *
23
24
  * @description
24
25
  * This service is a mock implementation of {@link ng.$browser}. It provides fake
@@ -29,7 +30,7 @@ angular.mock = {};
29
30
  * that there are several helper methods available which can be used in tests.
30
31
  */
31
32
  angular.mock.$BrowserProvider = function() {
32
- this.$get = function(){
33
+ this.$get = function() {
33
34
  return new angular.mock.$Browser();
34
35
  };
35
36
  };
@@ -75,6 +76,12 @@ angular.mock.$Browser = function() {
75
76
  };
76
77
 
77
78
 
79
+ /**
80
+ * @name $browser#defer.now
81
+ *
82
+ * @description
83
+ * Current milliseconds mock time.
84
+ */
78
85
  self.defer.now = 0;
79
86
 
80
87
 
@@ -95,8 +102,7 @@ angular.mock.$Browser = function() {
95
102
 
96
103
 
97
104
  /**
98
- * @name ngMock.$browser#defer.flush
99
- * @methodOf ngMock.$browser
105
+ * @name $browser#defer.flush
100
106
  *
101
107
  * @description
102
108
  * Flushes all pending requests and executes the defer callbacks.
@@ -110,7 +116,7 @@ angular.mock.$Browser = function() {
110
116
  if (self.deferredFns.length) {
111
117
  self.defer.now = self.deferredFns[self.deferredFns.length-1].time;
112
118
  } else {
113
- throw Error('No deferred tasks to be flushed');
119
+ throw new Error('No deferred tasks to be flushed');
114
120
  }
115
121
  }
116
122
 
@@ -118,13 +124,6 @@ angular.mock.$Browser = function() {
118
124
  self.deferredFns.shift().fn();
119
125
  }
120
126
  };
121
- /**
122
- * @name ngMock.$browser#defer.now
123
- * @propertyOf ngMock.$browser
124
- *
125
- * @description
126
- * Current milliseconds mock time.
127
- */
128
127
 
129
128
  self.$$baseHref = '';
130
129
  self.baseHref = function() {
@@ -134,8 +133,7 @@ angular.mock.$Browser = function() {
134
133
  angular.mock.$Browser.prototype = {
135
134
 
136
135
  /**
137
- * @name ngMock.$browser#poll
138
- * @methodOf ngMock.$browser
136
+ * @name $browser#poll
139
137
  *
140
138
  * @description
141
139
  * run all fns in pollFns
@@ -162,7 +160,7 @@ angular.mock.$Browser.prototype = {
162
160
 
163
161
  cookies: function(name, value) {
164
162
  if (name) {
165
- if (value == undefined) {
163
+ if (angular.isUndefined(value)) {
166
164
  delete this.cookieHash[name];
167
165
  } else {
168
166
  if (angular.isString(value) && //strings only
@@ -186,17 +184,17 @@ angular.mock.$Browser.prototype = {
186
184
 
187
185
 
188
186
  /**
189
- * @ngdoc object
190
- * @name ngMock.$exceptionHandlerProvider
187
+ * @ngdoc provider
188
+ * @name $exceptionHandlerProvider
191
189
  *
192
190
  * @description
193
- * Configures the mock implementation of {@link ng.$exceptionHandler} to rethrow or to log errors passed
194
- * into the `$exceptionHandler`.
191
+ * Configures the mock implementation of {@link ng.$exceptionHandler} to rethrow or to log errors
192
+ * passed into the `$exceptionHandler`.
195
193
  */
196
194
 
197
195
  /**
198
- * @ngdoc object
199
- * @name ngMock.$exceptionHandler
196
+ * @ngdoc service
197
+ * @name $exceptionHandler
200
198
  *
201
199
  * @description
202
200
  * Mock implementation of {@link ng.$exceptionHandler} that rethrows or logs errors passed
@@ -204,7 +202,7 @@ angular.mock.$Browser.prototype = {
204
202
  * information.
205
203
  *
206
204
  *
207
- * <pre>
205
+ * ```js
208
206
  * describe('$exceptionHandlerProvider', function() {
209
207
  *
210
208
  * it('should capture log messages and exceptions', function() {
@@ -225,7 +223,7 @@ angular.mock.$Browser.prototype = {
225
223
  * });
226
224
  * });
227
225
  * });
228
- * </pre>
226
+ * ```
229
227
  */
230
228
 
231
229
  angular.mock.$ExceptionHandlerProvider = function() {
@@ -233,8 +231,7 @@ angular.mock.$ExceptionHandlerProvider = function() {
233
231
 
234
232
  /**
235
233
  * @ngdoc method
236
- * @name ngMock.$exceptionHandlerProvider#mode
237
- * @methodOf ngMock.$exceptionHandlerProvider
234
+ * @name $exceptionHandlerProvider#mode
238
235
  *
239
236
  * @description
240
237
  * Sets the logging mode.
@@ -244,10 +241,10 @@ angular.mock.$ExceptionHandlerProvider = function() {
244
241
  * - `rethrow`: If any errors are passed into the handler in tests, it typically
245
242
  * means that there is a bug in the application or test, so this mock will
246
243
  * make these tests fail.
247
- * - `log`: Sometimes it is desirable to test that an error is thrown, for this case the `log` mode stores an
248
- * array of errors in `$exceptionHandler.errors`, to allow later assertion of them.
249
- * See {@link ngMock.$log#assertEmpty assertEmpty()} and
250
- * {@link ngMock.$log#reset reset()}
244
+ * - `log`: Sometimes it is desirable to test that an error is thrown, for this case the `log`
245
+ * mode stores an array of errors in `$exceptionHandler.errors`, to allow later
246
+ * assertion of them. See {@link ngMock.$log#assertEmpty assertEmpty()} and
247
+ * {@link ngMock.$log#reset reset()}
251
248
  */
252
249
  this.mode = function(mode) {
253
250
  switch(mode) {
@@ -270,7 +267,7 @@ angular.mock.$ExceptionHandlerProvider = function() {
270
267
  handler.errors = errors;
271
268
  break;
272
269
  default:
273
- throw Error("Unknown mode '" + mode + "', only 'log'/'rethrow' modes are allowed!");
270
+ throw new Error("Unknown mode '" + mode + "', only 'log'/'rethrow' modes are allowed!");
274
271
  }
275
272
  };
276
273
 
@@ -284,7 +281,7 @@ angular.mock.$ExceptionHandlerProvider = function() {
284
281
 
285
282
  /**
286
283
  * @ngdoc service
287
- * @name ngMock.$log
284
+ * @name $log
288
285
  *
289
286
  * @description
290
287
  * Mock implementation of {@link ng.$log} that gathers all logged messages in arrays
@@ -293,24 +290,37 @@ angular.mock.$ExceptionHandlerProvider = function() {
293
290
  *
294
291
  */
295
292
  angular.mock.$LogProvider = function() {
293
+ var debug = true;
296
294
 
297
295
  function concat(array1, array2, index) {
298
296
  return array1.concat(Array.prototype.slice.call(array2, index));
299
297
  }
300
298
 
299
+ this.debugEnabled = function(flag) {
300
+ if (angular.isDefined(flag)) {
301
+ debug = flag;
302
+ return this;
303
+ } else {
304
+ return debug;
305
+ }
306
+ };
301
307
 
302
308
  this.$get = function () {
303
309
  var $log = {
304
310
  log: function() { $log.log.logs.push(concat([], arguments, 0)); },
305
311
  warn: function() { $log.warn.logs.push(concat([], arguments, 0)); },
306
312
  info: function() { $log.info.logs.push(concat([], arguments, 0)); },
307
- error: function() { $log.error.logs.push(concat([], arguments, 0)); }
313
+ error: function() { $log.error.logs.push(concat([], arguments, 0)); },
314
+ debug: function() {
315
+ if (debug) {
316
+ $log.debug.logs.push(concat([], arguments, 0));
317
+ }
318
+ }
308
319
  };
309
320
 
310
321
  /**
311
322
  * @ngdoc method
312
- * @name ngMock.$log#reset
313
- * @methodOf ngMock.$log
323
+ * @name $log#reset
314
324
  *
315
325
  * @description
316
326
  * Reset all of the logging arrays to empty.
@@ -318,86 +328,97 @@ angular.mock.$LogProvider = function() {
318
328
  $log.reset = function () {
319
329
  /**
320
330
  * @ngdoc property
321
- * @name ngMock.$log#log.logs
322
- * @propertyOf ngMock.$log
331
+ * @name $log#log.logs
323
332
  *
324
333
  * @description
325
334
  * Array of messages logged using {@link ngMock.$log#log}.
326
335
  *
327
336
  * @example
328
- * <pre>
337
+ * ```js
329
338
  * $log.log('Some Log');
330
339
  * var first = $log.log.logs.unshift();
331
- * </pre>
340
+ * ```
332
341
  */
333
342
  $log.log.logs = [];
334
343
  /**
335
344
  * @ngdoc property
336
- * @name ngMock.$log#warn.logs
337
- * @propertyOf ngMock.$log
345
+ * @name $log#info.logs
338
346
  *
339
347
  * @description
340
- * Array of messages logged using {@link ngMock.$log#warn}.
348
+ * Array of messages logged using {@link ngMock.$log#info}.
341
349
  *
342
350
  * @example
343
- * <pre>
344
- * $log.warn('Some Warning');
345
- * var first = $log.warn.logs.unshift();
346
- * </pre>
351
+ * ```js
352
+ * $log.info('Some Info');
353
+ * var first = $log.info.logs.unshift();
354
+ * ```
347
355
  */
348
- $log.warn.logs = [];
356
+ $log.info.logs = [];
349
357
  /**
350
358
  * @ngdoc property
351
- * @name ngMock.$log#info.logs
352
- * @propertyOf ngMock.$log
359
+ * @name $log#warn.logs
353
360
  *
354
361
  * @description
355
- * Array of messages logged using {@link ngMock.$log#info}.
362
+ * Array of messages logged using {@link ngMock.$log#warn}.
356
363
  *
357
364
  * @example
358
- * <pre>
359
- * $log.info('Some Info');
360
- * var first = $log.info.logs.unshift();
361
- * </pre>
365
+ * ```js
366
+ * $log.warn('Some Warning');
367
+ * var first = $log.warn.logs.unshift();
368
+ * ```
362
369
  */
363
- $log.info.logs = [];
370
+ $log.warn.logs = [];
364
371
  /**
365
372
  * @ngdoc property
366
- * @name ngMock.$log#error.logs
367
- * @propertyOf ngMock.$log
373
+ * @name $log#error.logs
368
374
  *
369
375
  * @description
370
376
  * Array of messages logged using {@link ngMock.$log#error}.
371
377
  *
372
378
  * @example
373
- * <pre>
374
- * $log.log('Some Error');
379
+ * ```js
380
+ * $log.error('Some Error');
375
381
  * var first = $log.error.logs.unshift();
376
- * </pre>
382
+ * ```
377
383
  */
378
384
  $log.error.logs = [];
385
+ /**
386
+ * @ngdoc property
387
+ * @name $log#debug.logs
388
+ *
389
+ * @description
390
+ * Array of messages logged using {@link ngMock.$log#debug}.
391
+ *
392
+ * @example
393
+ * ```js
394
+ * $log.debug('Some Error');
395
+ * var first = $log.debug.logs.unshift();
396
+ * ```
397
+ */
398
+ $log.debug.logs = [];
379
399
  };
380
400
 
381
401
  /**
382
402
  * @ngdoc method
383
- * @name ngMock.$log#assertEmpty
384
- * @methodOf ngMock.$log
403
+ * @name $log#assertEmpty
385
404
  *
386
405
  * @description
387
- * Assert that the all of the logging methods have no logged messages. If messages present, an exception is thrown.
406
+ * Assert that the all of the logging methods have no logged messages. If messages present, an
407
+ * exception is thrown.
388
408
  */
389
409
  $log.assertEmpty = function() {
390
410
  var errors = [];
391
- angular.forEach(['error', 'warn', 'info', 'log'], function(logLevel) {
411
+ angular.forEach(['error', 'warn', 'info', 'log', 'debug'], function(logLevel) {
392
412
  angular.forEach($log[logLevel].logs, function(log) {
393
413
  angular.forEach(log, function (logItem) {
394
- errors.push('MOCK $log (' + logLevel + '): ' + String(logItem) + '\n' + (logItem.stack || ''));
414
+ errors.push('MOCK $log (' + logLevel + '): ' + String(logItem) + '\n' +
415
+ (logItem.stack || ''));
395
416
  });
396
417
  });
397
418
  });
398
419
  if (errors.length) {
399
- errors.unshift("Expected $log to be empty! Either a message was logged unexpectedly, or an expected " +
400
- "log message was not checked and removed:");
420
+ errors.unshift("Expected $log to be empty! Either a message was logged unexpectedly, or "+
421
+ "an expected log message was not checked and removed:");
401
422
  errors.push('');
402
423
  throw new Error(errors.join('\n---------\n'));
403
424
  }
@@ -409,261 +430,382 @@ angular.mock.$LogProvider = function() {
409
430
  };
410
431
 
411
432
 
412
- (function() {
413
- var R_ISO8061_STR = /^(\d{4})-?(\d\d)-?(\d\d)(?:T(\d\d)(?:\:?(\d\d)(?:\:?(\d\d)(?:\.(\d{3}))?)?)?(Z|([+-])(\d\d):?(\d\d)))?$/;
433
+ /**
434
+ * @ngdoc service
435
+ * @name $interval
436
+ *
437
+ * @description
438
+ * Mock implementation of the $interval service.
439
+ *
440
+ * Use {@link ngMock.$interval#flush `$interval.flush(millis)`} to
441
+ * move forward by `millis` milliseconds and trigger any functions scheduled to run in that
442
+ * time.
443
+ *
444
+ * @param {function()} fn A function that should be called repeatedly.
445
+ * @param {number} delay Number of milliseconds between each function call.
446
+ * @param {number=} [count=0] Number of times to repeat. If not set, or 0, will repeat
447
+ * indefinitely.
448
+ * @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise
449
+ * will invoke `fn` within the {@link ng.$rootScope.Scope#$apply $apply} block.
450
+ * @returns {promise} A promise which will be notified on each iteration.
451
+ */
452
+ angular.mock.$IntervalProvider = function() {
453
+ this.$get = ['$rootScope', '$q',
454
+ function($rootScope, $q) {
455
+ var repeatFns = [],
456
+ nextRepeatId = 0,
457
+ now = 0;
458
+
459
+ var $interval = function(fn, delay, count, invokeApply) {
460
+ var deferred = $q.defer(),
461
+ promise = deferred.promise,
462
+ iteration = 0,
463
+ skipApply = (angular.isDefined(invokeApply) && !invokeApply);
464
+
465
+ count = (angular.isDefined(count)) ? count : 0,
466
+ promise.then(null, null, fn);
414
467
 
415
- function jsonStringToDate(string){
416
- var match;
417
- if (match = string.match(R_ISO8061_STR)) {
418
- var date = new Date(0),
419
- tzHour = 0,
420
- tzMin = 0;
421
- if (match[9]) {
422
- tzHour = int(match[9] + match[10]);
423
- tzMin = int(match[9] + match[11]);
468
+ promise.$$intervalId = nextRepeatId;
469
+
470
+ function tick() {
471
+ deferred.notify(iteration++);
472
+
473
+ if (count > 0 && iteration >= count) {
474
+ var fnIndex;
475
+ deferred.resolve(iteration);
476
+
477
+ angular.forEach(repeatFns, function(fn, index) {
478
+ if (fn.id === promise.$$intervalId) fnIndex = index;
479
+ });
480
+
481
+ if (fnIndex !== undefined) {
482
+ repeatFns.splice(fnIndex, 1);
483
+ }
484
+ }
485
+
486
+ if (!skipApply) $rootScope.$apply();
424
487
  }
425
- date.setUTCFullYear(int(match[1]), int(match[2]) - 1, int(match[3]));
426
- date.setUTCHours(int(match[4]||0) - tzHour, int(match[5]||0) - tzMin, int(match[6]||0), int(match[7]||0));
427
- return date;
488
+
489
+ repeatFns.push({
490
+ nextTime:(now + delay),
491
+ delay: delay,
492
+ fn: tick,
493
+ id: nextRepeatId,
494
+ deferred: deferred
495
+ });
496
+ repeatFns.sort(function(a,b){ return a.nextTime - b.nextTime;});
497
+
498
+ nextRepeatId++;
499
+ return promise;
500
+ };
501
+ /**
502
+ * @ngdoc method
503
+ * @name $interval#cancel
504
+ *
505
+ * @description
506
+ * Cancels a task associated with the `promise`.
507
+ *
508
+ * @param {promise} promise A promise from calling the `$interval` function.
509
+ * @returns {boolean} Returns `true` if the task was successfully cancelled.
510
+ */
511
+ $interval.cancel = function(promise) {
512
+ if(!promise) return false;
513
+ var fnIndex;
514
+
515
+ angular.forEach(repeatFns, function(fn, index) {
516
+ if (fn.id === promise.$$intervalId) fnIndex = index;
517
+ });
518
+
519
+ if (fnIndex !== undefined) {
520
+ repeatFns[fnIndex].deferred.reject('canceled');
521
+ repeatFns.splice(fnIndex, 1);
522
+ return true;
523
+ }
524
+
525
+ return false;
526
+ };
527
+
528
+ /**
529
+ * @ngdoc method
530
+ * @name $interval#flush
531
+ * @description
532
+ *
533
+ * Runs interval tasks scheduled to be run in the next `millis` milliseconds.
534
+ *
535
+ * @param {number=} millis maximum timeout amount to flush up until.
536
+ *
537
+ * @return {number} The amount of time moved forward.
538
+ */
539
+ $interval.flush = function(millis) {
540
+ now += millis;
541
+ while (repeatFns.length && repeatFns[0].nextTime <= now) {
542
+ var task = repeatFns[0];
543
+ task.fn();
544
+ task.nextTime += task.delay;
545
+ repeatFns.sort(function(a,b){ return a.nextTime - b.nextTime;});
546
+ }
547
+ return millis;
548
+ };
549
+
550
+ return $interval;
551
+ }];
552
+ };
553
+
554
+
555
+ /* jshint -W101 */
556
+ /* The R_ISO8061_STR regex is never going to fit into the 100 char limit!
557
+ * This directive should go inside the anonymous function but a bug in JSHint means that it would
558
+ * not be enacted early enough to prevent the warning.
559
+ */
560
+ var R_ISO8061_STR = /^(\d{4})-?(\d\d)-?(\d\d)(?:T(\d\d)(?:\:?(\d\d)(?:\:?(\d\d)(?:\.(\d{3}))?)?)?(Z|([+-])(\d\d):?(\d\d)))?$/;
561
+
562
+ function jsonStringToDate(string) {
563
+ var match;
564
+ if (match = string.match(R_ISO8061_STR)) {
565
+ var date = new Date(0),
566
+ tzHour = 0,
567
+ tzMin = 0;
568
+ if (match[9]) {
569
+ tzHour = int(match[9] + match[10]);
570
+ tzMin = int(match[9] + match[11]);
428
571
  }
429
- return string;
572
+ date.setUTCFullYear(int(match[1]), int(match[2]) - 1, int(match[3]));
573
+ date.setUTCHours(int(match[4]||0) - tzHour,
574
+ int(match[5]||0) - tzMin,
575
+ int(match[6]||0),
576
+ int(match[7]||0));
577
+ return date;
430
578
  }
579
+ return string;
580
+ }
581
+
582
+ function int(str) {
583
+ return parseInt(str, 10);
584
+ }
431
585
 
432
- function int(str) {
433
- return parseInt(str, 10);
586
+ function padNumber(num, digits, trim) {
587
+ var neg = '';
588
+ if (num < 0) {
589
+ neg = '-';
590
+ num = -num;
434
591
  }
592
+ num = '' + num;
593
+ while(num.length < digits) num = '0' + num;
594
+ if (trim)
595
+ num = num.substr(num.length - digits);
596
+ return neg + num;
597
+ }
435
598
 
436
- function padNumber(num, digits, trim) {
437
- var neg = '';
438
- if (num < 0) {
439
- neg = '-';
440
- num = -num;
441
- }
442
- num = '' + num;
443
- while(num.length < digits) num = '0' + num;
444
- if (trim)
445
- num = num.substr(num.length - digits);
446
- return neg + num;
599
+
600
+ /**
601
+ * @ngdoc type
602
+ * @name angular.mock.TzDate
603
+ * @description
604
+ *
605
+ * *NOTE*: this is not an injectable instance, just a globally available mock class of `Date`.
606
+ *
607
+ * Mock of the Date type which has its timezone specified via constructor arg.
608
+ *
609
+ * The main purpose is to create Date-like instances with timezone fixed to the specified timezone
610
+ * offset, so that we can test code that depends on local timezone settings without dependency on
611
+ * the time zone settings of the machine where the code is running.
612
+ *
613
+ * @param {number} offset Offset of the *desired* timezone in hours (fractions will be honored)
614
+ * @param {(number|string)} timestamp Timestamp representing the desired time in *UTC*
615
+ *
616
+ * @example
617
+ * !!!! WARNING !!!!!
618
+ * This is not a complete Date object so only methods that were implemented can be called safely.
619
+ * To make matters worse, TzDate instances inherit stuff from Date via a prototype.
620
+ *
621
+ * We do our best to intercept calls to "unimplemented" methods, but since the list of methods is
622
+ * incomplete we might be missing some non-standard methods. This can result in errors like:
623
+ * "Date.prototype.foo called on incompatible Object".
624
+ *
625
+ * ```js
626
+ * var newYearInBratislava = new TzDate(-1, '2009-12-31T23:00:00Z');
627
+ * newYearInBratislava.getTimezoneOffset() => -60;
628
+ * newYearInBratislava.getFullYear() => 2010;
629
+ * newYearInBratislava.getMonth() => 0;
630
+ * newYearInBratislava.getDate() => 1;
631
+ * newYearInBratislava.getHours() => 0;
632
+ * newYearInBratislava.getMinutes() => 0;
633
+ * newYearInBratislava.getSeconds() => 0;
634
+ * ```
635
+ *
636
+ */
637
+ angular.mock.TzDate = function (offset, timestamp) {
638
+ var self = new Date(0);
639
+ if (angular.isString(timestamp)) {
640
+ var tsStr = timestamp;
641
+
642
+ self.origDate = jsonStringToDate(timestamp);
643
+
644
+ timestamp = self.origDate.getTime();
645
+ if (isNaN(timestamp))
646
+ throw {
647
+ name: "Illegal Argument",
648
+ message: "Arg '" + tsStr + "' passed into TzDate constructor is not a valid date string"
649
+ };
650
+ } else {
651
+ self.origDate = new Date(timestamp);
447
652
  }
448
653
 
654
+ var localOffset = new Date(timestamp).getTimezoneOffset();
655
+ self.offsetDiff = localOffset*60*1000 - offset*1000*60*60;
656
+ self.date = new Date(timestamp + self.offsetDiff);
449
657
 
450
- /**
451
- * @ngdoc object
452
- * @name angular.mock.TzDate
453
- * @description
454
- *
455
- * *NOTE*: this is not an injectable instance, just a globally available mock class of `Date`.
456
- *
457
- * Mock of the Date type which has its timezone specified via constructor arg.
458
- *
459
- * The main purpose is to create Date-like instances with timezone fixed to the specified timezone
460
- * offset, so that we can test code that depends on local timezone settings without dependency on
461
- * the time zone settings of the machine where the code is running.
462
- *
463
- * @param {number} offset Offset of the *desired* timezone in hours (fractions will be honored)
464
- * @param {(number|string)} timestamp Timestamp representing the desired time in *UTC*
465
- *
466
- * @example
467
- * !!!! WARNING !!!!!
468
- * This is not a complete Date object so only methods that were implemented can be called safely.
469
- * To make matters worse, TzDate instances inherit stuff from Date via a prototype.
470
- *
471
- * We do our best to intercept calls to "unimplemented" methods, but since the list of methods is
472
- * incomplete we might be missing some non-standard methods. This can result in errors like:
473
- * "Date.prototype.foo called on incompatible Object".
474
- *
475
- * <pre>
476
- * var newYearInBratislava = new TzDate(-1, '2009-12-31T23:00:00Z');
477
- * newYearInBratislava.getTimezoneOffset() => -60;
478
- * newYearInBratislava.getFullYear() => 2010;
479
- * newYearInBratislava.getMonth() => 0;
480
- * newYearInBratislava.getDate() => 1;
481
- * newYearInBratislava.getHours() => 0;
482
- * newYearInBratislava.getMinutes() => 0;
483
- * newYearInBratislava.getSeconds() => 0;
484
- * </pre>
485
- *
486
- */
487
- angular.mock.TzDate = function (offset, timestamp) {
488
- var self = new Date(0);
489
- if (angular.isString(timestamp)) {
490
- var tsStr = timestamp;
491
-
492
- self.origDate = jsonStringToDate(timestamp);
493
-
494
- timestamp = self.origDate.getTime();
495
- if (isNaN(timestamp))
496
- throw {
497
- name: "Illegal Argument",
498
- message: "Arg '" + tsStr + "' passed into TzDate constructor is not a valid date string"
499
- };
500
- } else {
501
- self.origDate = new Date(timestamp);
502
- }
658
+ self.getTime = function() {
659
+ return self.date.getTime() - self.offsetDiff;
660
+ };
503
661
 
504
- var localOffset = new Date(timestamp).getTimezoneOffset();
505
- self.offsetDiff = localOffset*60*1000 - offset*1000*60*60;
506
- self.date = new Date(timestamp + self.offsetDiff);
662
+ self.toLocaleDateString = function() {
663
+ return self.date.toLocaleDateString();
664
+ };
507
665
 
508
- self.getTime = function() {
509
- return self.date.getTime() - self.offsetDiff;
510
- };
666
+ self.getFullYear = function() {
667
+ return self.date.getFullYear();
668
+ };
511
669
 
512
- self.toLocaleDateString = function() {
513
- return self.date.toLocaleDateString();
514
- };
670
+ self.getMonth = function() {
671
+ return self.date.getMonth();
672
+ };
515
673
 
516
- self.getFullYear = function() {
517
- return self.date.getFullYear();
518
- };
674
+ self.getDate = function() {
675
+ return self.date.getDate();
676
+ };
519
677
 
520
- self.getMonth = function() {
521
- return self.date.getMonth();
522
- };
678
+ self.getHours = function() {
679
+ return self.date.getHours();
680
+ };
523
681
 
524
- self.getDate = function() {
525
- return self.date.getDate();
526
- };
682
+ self.getMinutes = function() {
683
+ return self.date.getMinutes();
684
+ };
527
685
 
528
- self.getHours = function() {
529
- return self.date.getHours();
530
- };
686
+ self.getSeconds = function() {
687
+ return self.date.getSeconds();
688
+ };
531
689
 
532
- self.getMinutes = function() {
533
- return self.date.getMinutes();
534
- };
690
+ self.getMilliseconds = function() {
691
+ return self.date.getMilliseconds();
692
+ };
535
693
 
536
- self.getSeconds = function() {
537
- return self.date.getSeconds();
538
- };
694
+ self.getTimezoneOffset = function() {
695
+ return offset * 60;
696
+ };
539
697
 
540
- self.getMilliseconds = function() {
541
- return self.date.getMilliseconds();
542
- };
698
+ self.getUTCFullYear = function() {
699
+ return self.origDate.getUTCFullYear();
700
+ };
543
701
 
544
- self.getTimezoneOffset = function() {
545
- return offset * 60;
546
- };
702
+ self.getUTCMonth = function() {
703
+ return self.origDate.getUTCMonth();
704
+ };
547
705
 
548
- self.getUTCFullYear = function() {
549
- return self.origDate.getUTCFullYear();
550
- };
706
+ self.getUTCDate = function() {
707
+ return self.origDate.getUTCDate();
708
+ };
551
709
 
552
- self.getUTCMonth = function() {
553
- return self.origDate.getUTCMonth();
554
- };
710
+ self.getUTCHours = function() {
711
+ return self.origDate.getUTCHours();
712
+ };
555
713
 
556
- self.getUTCDate = function() {
557
- return self.origDate.getUTCDate();
558
- };
714
+ self.getUTCMinutes = function() {
715
+ return self.origDate.getUTCMinutes();
716
+ };
559
717
 
560
- self.getUTCHours = function() {
561
- return self.origDate.getUTCHours();
562
- };
718
+ self.getUTCSeconds = function() {
719
+ return self.origDate.getUTCSeconds();
720
+ };
563
721
 
564
- self.getUTCMinutes = function() {
565
- return self.origDate.getUTCMinutes();
566
- };
722
+ self.getUTCMilliseconds = function() {
723
+ return self.origDate.getUTCMilliseconds();
724
+ };
567
725
 
568
- self.getUTCSeconds = function() {
569
- return self.origDate.getUTCSeconds();
570
- };
726
+ self.getDay = function() {
727
+ return self.date.getDay();
728
+ };
571
729
 
572
- self.getUTCMilliseconds = function() {
573
- return self.origDate.getUTCMilliseconds();
730
+ // provide this method only on browsers that already have it
731
+ if (self.toISOString) {
732
+ self.toISOString = function() {
733
+ return padNumber(self.origDate.getUTCFullYear(), 4) + '-' +
734
+ padNumber(self.origDate.getUTCMonth() + 1, 2) + '-' +
735
+ padNumber(self.origDate.getUTCDate(), 2) + 'T' +
736
+ padNumber(self.origDate.getUTCHours(), 2) + ':' +
737
+ padNumber(self.origDate.getUTCMinutes(), 2) + ':' +
738
+ padNumber(self.origDate.getUTCSeconds(), 2) + '.' +
739
+ padNumber(self.origDate.getUTCMilliseconds(), 3) + 'Z';
574
740
  };
741
+ }
575
742
 
576
- self.getDay = function() {
577
- return self.date.getDay();
743
+ //hide all methods not implemented in this mock that the Date prototype exposes
744
+ var unimplementedMethods = ['getUTCDay',
745
+ 'getYear', 'setDate', 'setFullYear', 'setHours', 'setMilliseconds',
746
+ 'setMinutes', 'setMonth', 'setSeconds', 'setTime', 'setUTCDate', 'setUTCFullYear',
747
+ 'setUTCHours', 'setUTCMilliseconds', 'setUTCMinutes', 'setUTCMonth', 'setUTCSeconds',
748
+ 'setYear', 'toDateString', 'toGMTString', 'toJSON', 'toLocaleFormat', 'toLocaleString',
749
+ 'toLocaleTimeString', 'toSource', 'toString', 'toTimeString', 'toUTCString', 'valueOf'];
750
+
751
+ angular.forEach(unimplementedMethods, function(methodName) {
752
+ self[methodName] = function() {
753
+ throw new Error("Method '" + methodName + "' is not implemented in the TzDate mock");
578
754
  };
755
+ });
579
756
 
580
- // provide this method only on browsers that already have it
581
- if (self.toISOString) {
582
- self.toISOString = function() {
583
- return padNumber(self.origDate.getUTCFullYear(), 4) + '-' +
584
- padNumber(self.origDate.getUTCMonth() + 1, 2) + '-' +
585
- padNumber(self.origDate.getUTCDate(), 2) + 'T' +
586
- padNumber(self.origDate.getUTCHours(), 2) + ':' +
587
- padNumber(self.origDate.getUTCMinutes(), 2) + ':' +
588
- padNumber(self.origDate.getUTCSeconds(), 2) + '.' +
589
- padNumber(self.origDate.getUTCMilliseconds(), 3) + 'Z'
590
- }
591
- }
757
+ return self;
758
+ };
592
759
 
593
- //hide all methods not implemented in this mock that the Date prototype exposes
594
- var unimplementedMethods = ['getUTCDay',
595
- 'getYear', 'setDate', 'setFullYear', 'setHours', 'setMilliseconds',
596
- 'setMinutes', 'setMonth', 'setSeconds', 'setTime', 'setUTCDate', 'setUTCFullYear',
597
- 'setUTCHours', 'setUTCMilliseconds', 'setUTCMinutes', 'setUTCMonth', 'setUTCSeconds',
598
- 'setYear', 'toDateString', 'toGMTString', 'toJSON', 'toLocaleFormat', 'toLocaleString',
599
- 'toLocaleTimeString', 'toSource', 'toString', 'toTimeString', 'toUTCString', 'valueOf'];
600
-
601
- angular.forEach(unimplementedMethods, function(methodName) {
602
- self[methodName] = function() {
603
- throw Error("Method '" + methodName + "' is not implemented in the TzDate mock");
604
- };
605
- });
760
+ //make "tzDateInstance instanceof Date" return true
761
+ angular.mock.TzDate.prototype = Date.prototype;
762
+ /* jshint +W101 */
606
763
 
607
- return self;
608
- };
764
+ angular.mock.animate = angular.module('ngAnimateMock', ['ng'])
609
765
 
610
- //make "tzDateInstance instanceof Date" return true
611
- angular.mock.TzDate.prototype = Date.prototype;
612
- })();
766
+ .config(['$provide', function($provide) {
613
767
 
614
- /**
615
- * @ngdoc function
616
- * @name angular.mock.createMockWindow
617
- * @description
618
- *
619
- * This function creates a mock window object useful for controlling access ot setTimeout, but mocking out
620
- * sufficient window's properties to allow Angular to execute.
621
- *
622
- * @example
623
- *
624
- * <pre>
625
- beforeEach(module(function($provide) {
626
- $provide.value('$window', window = angular.mock.createMockWindow());
627
- }));
628
-
629
- it('should do something', inject(function($window) {
630
- var val = null;
631
- $window.setTimeout(function() { val = 123; }, 10);
632
- expect(val).toEqual(null);
633
- window.setTimeout.expect(10).process();
634
- expect(val).toEqual(123);
768
+ var reflowQueue = [];
769
+ $provide.value('$$animateReflow', function(fn) {
770
+ var index = reflowQueue.length;
771
+ reflowQueue.push(fn);
772
+ return function cancel() {
773
+ reflowQueue.splice(index, 1);
774
+ };
635
775
  });
636
- * </pre>
637
- *
638
- */
639
- angular.mock.createMockWindow = function() {
640
- var mockWindow = {};
641
- var setTimeoutQueue = [];
642
-
643
- mockWindow.document = window.document;
644
- mockWindow.getComputedStyle = angular.bind(window, window.getComputedStyle);
645
- mockWindow.scrollTo = angular.bind(window, window.scrollTo);
646
- mockWindow.navigator = window.navigator;
647
- mockWindow.setTimeout = function(fn, delay) {
648
- setTimeoutQueue.push({fn: fn, delay: delay});
649
- };
650
- mockWindow.setTimeout.queue = setTimeoutQueue;
651
- mockWindow.setTimeout.expect = function(delay) {
652
- if (setTimeoutQueue.length > 0) {
653
- return {
654
- process: function() {
655
- var tick = setTimeoutQueue.shift();
656
- expect(tick.delay).toEqual(delay);
657
- tick.fn();
776
+
777
+ $provide.decorator('$animate', function($delegate, $$asyncCallback) {
778
+ var animate = {
779
+ queue : [],
780
+ enabled : $delegate.enabled,
781
+ triggerCallbacks : function() {
782
+ $$asyncCallback.flush();
783
+ },
784
+ triggerReflow : function() {
785
+ angular.forEach(reflowQueue, function(fn) {
786
+ fn();
787
+ });
788
+ reflowQueue = [];
658
789
  }
659
790
  };
660
- } else {
661
- expect('SetTimoutQueue empty. Expecting delay of ').toEqual(delay);
662
- }
663
- };
664
791
 
665
- return mockWindow;
666
- };
792
+ angular.forEach(
793
+ ['enter','leave','move','addClass','removeClass','setClass'], function(method) {
794
+ animate[method] = function() {
795
+ animate.queue.push({
796
+ event : method,
797
+ element : arguments[0],
798
+ args : arguments
799
+ });
800
+ $delegate[method].apply($delegate, arguments);
801
+ };
802
+ });
803
+
804
+ return animate;
805
+ });
806
+
807
+ }]);
808
+
667
809
 
668
810
  /**
669
811
  * @ngdoc function
@@ -672,9 +814,11 @@ angular.mock.createMockWindow = function() {
672
814
  *
673
815
  * *NOTE*: this is not an injectable instance, just a globally available function.
674
816
  *
675
- * Method for serializing common angular objects (scope, elements, etc..) into strings, useful for debugging.
817
+ * Method for serializing common angular objects (scope, elements, etc..) into strings, useful for
818
+ * debugging.
676
819
  *
677
- * This method is also available on window, where it can be used to display objects on debug console.
820
+ * This method is also available on window, where it can be used to display objects on debug
821
+ * console.
678
822
  *
679
823
  * @param {*} object - any object to turn into string.
680
824
  * @return {string} a serialized string of the argument
@@ -704,6 +848,8 @@ angular.mock.dump = function(object) {
704
848
  } else if (object instanceof Error) {
705
849
  out = object.stack || ('' + object.name + ': ' + object.message);
706
850
  } else {
851
+ // TODO(i): this prevents methods being logged,
852
+ // we should have a better way to serialize objects
707
853
  out = angular.toJson(object, true);
708
854
  }
709
855
  } else {
@@ -717,7 +863,7 @@ angular.mock.dump = function(object) {
717
863
  offset = offset || ' ';
718
864
  var log = [offset + 'Scope(' + scope.$id + '): {'];
719
865
  for ( var key in scope ) {
720
- if (scope.hasOwnProperty(key) && !key.match(/^(\$|this)/)) {
866
+ if (Object.prototype.hasOwnProperty.call(scope, key) && !key.match(/^(\$|this)/)) {
721
867
  log.push(' ' + key + ': ' + angular.toJson(scope[key]));
722
868
  }
723
869
  }
@@ -732,8 +878,8 @@ angular.mock.dump = function(object) {
732
878
  };
733
879
 
734
880
  /**
735
- * @ngdoc object
736
- * @name ngMock.$httpBackend
881
+ * @ngdoc service
882
+ * @name $httpBackend
737
883
  * @description
738
884
  * Fake HTTP backend implementation suitable for unit testing applications that use the
739
885
  * {@link ng.$http $http service}.
@@ -742,8 +888,8 @@ angular.mock.dump = function(object) {
742
888
  * development please see {@link ngMockE2E.$httpBackend e2e $httpBackend mock}.
743
889
  *
744
890
  * During unit testing, we want our unit tests to run quickly and have no external dependencies so
745
- * we don’t want to send {@link https://developer.mozilla.org/en/xmlhttprequest XHR} or
746
- * {@link http://en.wikipedia.org/wiki/JSONP JSONP} requests to a real server. All we really need is
891
+ * we don’t want to send [XHR](https://developer.mozilla.org/en/xmlhttprequest) or
892
+ * [JSONP](http://en.wikipedia.org/wiki/JSONP) requests to a real server. All we really need is
747
893
  * to verify whether a certain request has been sent or not, or alternatively just let the
748
894
  * application make requests, respond with pre-trained responses and assert that the end result is
749
895
  * what we expect it to be.
@@ -821,86 +967,110 @@ angular.mock.dump = function(object) {
821
967
  *
822
968
  * # Flushing HTTP requests
823
969
  *
824
- * The $httpBackend used in production, always responds to requests with responses asynchronously.
825
- * If we preserved this behavior in unit testing, we'd have to create async unit tests, which are
826
- * hard to write, follow and maintain. At the same time the testing mock, can't respond
827
- * synchronously because that would change the execution of the code under test. For this reason the
828
- * mock $httpBackend has a `flush()` method, which allows the test to explicitly flush pending
829
- * requests and thus preserving the async api of the backend, while allowing the test to execute
830
- * synchronously.
970
+ * The $httpBackend used in production always responds to requests asynchronously. If we preserved
971
+ * this behavior in unit testing, we'd have to create async unit tests, which are hard to write,
972
+ * to follow and to maintain. But neither can the testing mock respond synchronously; that would
973
+ * change the execution of the code under test. For this reason, the mock $httpBackend has a
974
+ * `flush()` method, which allows the test to explicitly flush pending requests. This preserves
975
+ * the async api of the backend, while allowing the test to execute synchronously.
831
976
  *
832
977
  *
833
978
  * # Unit testing with mock $httpBackend
979
+ * The following code shows how to setup and use the mock backend when unit testing a controller.
980
+ * First we create the controller under test:
834
981
  *
835
- * <pre>
836
- // controller
837
- function MyController($scope, $http) {
838
- $http.get('/auth.py').success(function(data) {
839
- $scope.user = data;
840
- });
841
-
842
- this.saveMessage = function(message) {
843
- $scope.status = 'Saving...';
844
- $http.post('/add-msg.py', message).success(function(response) {
845
- $scope.status = '';
846
- }).error(function() {
847
- $scope.status = 'ERROR!';
848
- });
849
- };
850
- }
982
+ ```js
983
+ // The controller code
984
+ function MyController($scope, $http) {
985
+ var authToken;
851
986
 
852
- // testing controller
853
- var $httpBackend;
987
+ $http.get('/auth.py').success(function(data, status, headers) {
988
+ authToken = headers('A-Token');
989
+ $scope.user = data;
990
+ });
854
991
 
855
- beforeEach(inject(function($injector) {
856
- $httpBackend = $injector.get('$httpBackend');
992
+ $scope.saveMessage = function(message) {
993
+ var headers = { 'Authorization': authToken };
994
+ $scope.status = 'Saving...';
857
995
 
858
- // backend definition common for all tests
859
- $httpBackend.when('GET', '/auth.py').respond({userId: 'userX'}, {'A-Token': 'xxx'});
860
- }));
996
+ $http.post('/add-msg.py', message, { headers: headers } ).success(function(response) {
997
+ $scope.status = '';
998
+ }).error(function() {
999
+ $scope.status = 'ERROR!';
1000
+ });
1001
+ };
1002
+ }
1003
+ ```
1004
+ *
1005
+ * Now we setup the mock backend and create the test specs:
1006
+ *
1007
+ ```js
1008
+ // testing controller
1009
+ describe('MyController', function() {
1010
+ var $httpBackend, $rootScope, createController;
1011
+
1012
+ beforeEach(inject(function($injector) {
1013
+ // Set up the mock http service responses
1014
+ $httpBackend = $injector.get('$httpBackend');
1015
+ // backend definition common for all tests
1016
+ $httpBackend.when('GET', '/auth.py').respond({userId: 'userX'}, {'A-Token': 'xxx'});
1017
+
1018
+ // Get hold of a scope (i.e. the root scope)
1019
+ $rootScope = $injector.get('$rootScope');
1020
+ // The $controller service is used to create instances of controllers
1021
+ var $controller = $injector.get('$controller');
1022
+
1023
+ createController = function() {
1024
+ return $controller('MyController', {'$scope' : $rootScope });
1025
+ };
1026
+ }));
861
1027
 
862
1028
 
863
- afterEach(function() {
864
- $httpBackend.verifyNoOutstandingExpectation();
865
- $httpBackend.verifyNoOutstandingRequest();
866
- });
1029
+ afterEach(function() {
1030
+ $httpBackend.verifyNoOutstandingExpectation();
1031
+ $httpBackend.verifyNoOutstandingRequest();
1032
+ });
1033
+
1034
+
1035
+ it('should fetch authentication token', function() {
1036
+ $httpBackend.expectGET('/auth.py');
1037
+ var controller = createController();
1038
+ $httpBackend.flush();
1039
+ });
867
1040
 
868
1041
 
869
- it('should fetch authentication token', function() {
870
- $httpBackend.expectGET('/auth.py');
871
- var controller = scope.$new(MyController);
872
- $httpBackend.flush();
873
- });
1042
+ it('should send msg to server', function() {
1043
+ var controller = createController();
1044
+ $httpBackend.flush();
874
1045
 
1046
+ // now you don’t care about the authentication, but
1047
+ // the controller will still send the request and
1048
+ // $httpBackend will respond without you having to
1049
+ // specify the expectation and response for this request
875
1050
 
876
- it('should send msg to server', function() {
877
- // now you don’t care about the authentication, but
878
- // the controller will still send the request and
879
- // $httpBackend will respond without you having to
880
- // specify the expectation and response for this request
881
- $httpBackend.expectPOST('/add-msg.py', 'message content').respond(201, '');
1051
+ $httpBackend.expectPOST('/add-msg.py', 'message content').respond(201, '');
1052
+ $rootScope.saveMessage('message content');
1053
+ expect($rootScope.status).toBe('Saving...');
1054
+ $httpBackend.flush();
1055
+ expect($rootScope.status).toBe('');
1056
+ });
882
1057
 
883
- var controller = scope.$new(MyController);
884
- $httpBackend.flush();
885
- controller.saveMessage('message content');
886
- expect(controller.status).toBe('Saving...');
887
- $httpBackend.flush();
888
- expect(controller.status).toBe('');
889
- });
890
1058
 
1059
+ it('should send auth header', function() {
1060
+ var controller = createController();
1061
+ $httpBackend.flush();
891
1062
 
892
- it('should send auth header', function() {
893
- $httpBackend.expectPOST('/add-msg.py', undefined, function(headers) {
894
- // check if the header was send, if it wasn't the expectation won't
895
- // match the request and the test will fail
896
- return headers['Authorization'] == 'xxx';
897
- }).respond(201, '');
1063
+ $httpBackend.expectPOST('/add-msg.py', undefined, function(headers) {
1064
+ // check if the header was send, if it wasn't the expectation won't
1065
+ // match the request and the test will fail
1066
+ return headers['Authorization'] == 'xxx';
1067
+ }).respond(201, '');
898
1068
 
899
- var controller = scope.$new(MyController);
900
- controller.saveMessage('whatever');
901
- $httpBackend.flush();
902
- });
903
- </pre>
1069
+ $rootScope.saveMessage('whatever');
1070
+ $httpBackend.flush();
1071
+ });
1072
+ });
1073
+ ```
904
1074
  */
905
1075
  angular.mock.$HttpBackendProvider = function() {
906
1076
  this.$get = ['$rootScope', createHttpBackendMock];
@@ -924,7 +1094,8 @@ function createHttpBackendMock($rootScope, $delegate, $browser) {
924
1094
  var definitions = [],
925
1095
  expectations = [],
926
1096
  responses = [],
927
- responsesPush = angular.bind(responses, responses.push);
1097
+ responsesPush = angular.bind(responses, responses.push),
1098
+ copy = angular.copy;
928
1099
 
929
1100
  function createResponse(status, data, headers) {
930
1101
  if (angular.isFunction(status)) return status;
@@ -937,7 +1108,7 @@ function createHttpBackendMock($rootScope, $delegate, $browser) {
937
1108
  }
938
1109
 
939
1110
  // TODO(vojta): change params to: method, url, data, headers, callback
940
- function $httpBackend(method, url, data, callback, headers, timeout) {
1111
+ function $httpBackend(method, url, data, callback, headers, timeout, withCredentials) {
941
1112
  var xhr = new MockXhr(),
942
1113
  expectation = expectations[0],
943
1114
  wasExpected = false;
@@ -956,7 +1127,7 @@ function createHttpBackendMock($rootScope, $delegate, $browser) {
956
1127
  function handleResponse() {
957
1128
  var response = wrapped.response(method, url, data, headers);
958
1129
  xhr.$$respHeaders = response[2];
959
- callback(response[0], response[1], xhr.getAllResponseHeaders());
1130
+ callback(copy(response[0]), copy(response[1]), xhr.getAllResponseHeaders());
960
1131
  }
961
1132
 
962
1133
  function handleTimeout() {
@@ -972,13 +1143,13 @@ function createHttpBackendMock($rootScope, $delegate, $browser) {
972
1143
 
973
1144
  if (expectation && expectation.match(method, url)) {
974
1145
  if (!expectation.matchData(data))
975
- throw Error('Expected ' + expectation + ' with different data\n' +
1146
+ throw new Error('Expected ' + expectation + ' with different data\n' +
976
1147
  'EXPECTED: ' + prettyPrint(expectation.data) + '\nGOT: ' + data);
977
1148
 
978
1149
  if (!expectation.matchHeaders(headers))
979
- throw Error('Expected ' + expectation + ' with different headers\n' +
980
- 'EXPECTED: ' + prettyPrint(expectation.headers) + '\nGOT: ' +
981
- prettyPrint(headers));
1150
+ throw new Error('Expected ' + expectation + ' with different headers\n' +
1151
+ 'EXPECTED: ' + prettyPrint(expectation.headers) + '\nGOT: ' +
1152
+ prettyPrint(headers));
982
1153
 
983
1154
  expectations.shift();
984
1155
 
@@ -996,33 +1167,35 @@ function createHttpBackendMock($rootScope, $delegate, $browser) {
996
1167
  // if $browser specified, we do auto flush all requests
997
1168
  ($browser ? $browser.defer : responsesPush)(wrapResponse(definition));
998
1169
  } else if (definition.passThrough) {
999
- $delegate(method, url, data, callback, headers, timeout);
1000
- } else throw Error('No response defined !');
1170
+ $delegate(method, url, data, callback, headers, timeout, withCredentials);
1171
+ } else throw new Error('No response defined !');
1001
1172
  return;
1002
1173
  }
1003
1174
  }
1004
1175
  throw wasExpected ?
1005
- Error('No response defined !') :
1006
- Error('Unexpected request: ' + method + ' ' + url + '\n' +
1007
- (expectation ? 'Expected ' + expectation : 'No more request expected'));
1176
+ new Error('No response defined !') :
1177
+ new Error('Unexpected request: ' + method + ' ' + url + '\n' +
1178
+ (expectation ? 'Expected ' + expectation : 'No more request expected'));
1008
1179
  }
1009
1180
 
1010
1181
  /**
1011
1182
  * @ngdoc method
1012
- * @name ngMock.$httpBackend#when
1013
- * @methodOf ngMock.$httpBackend
1183
+ * @name $httpBackend#when
1014
1184
  * @description
1015
1185
  * Creates a new backend definition.
1016
1186
  *
1017
1187
  * @param {string} method HTTP method.
1018
- * @param {string|RegExp} url HTTP url.
1019
- * @param {(string|RegExp)=} data HTTP request body.
1188
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
1189
+ * and returns true if the url match the current definition.
1190
+ * @param {(string|RegExp|function(string))=} data HTTP request body or function that receives
1191
+ * data string and returns true if the data is as expected.
1020
1192
  * @param {(Object|function(Object))=} headers HTTP headers or function that receives http header
1021
1193
  * object and returns true if the headers match the current definition.
1022
- * @returns {requestHandler} Returns an object with `respond` method that control how a matched
1194
+ * @returns {requestHandler} Returns an object with `respond` method that controls how a matched
1023
1195
  * request is handled.
1024
1196
  *
1025
- * - respond – `{function([status,] data[, headers])|function(function(method, url, data, headers)}`
1197
+ * - respond –
1198
+ * `{function([status,] data[, headers])|function(function(method, url, data, headers)}`
1026
1199
  * – The respond method takes a set of static data to be returned or a function that can return
1027
1200
  * an array containing response status (number), response data (string) and response headers
1028
1201
  * (Object).
@@ -1047,12 +1220,12 @@ function createHttpBackendMock($rootScope, $delegate, $browser) {
1047
1220
 
1048
1221
  /**
1049
1222
  * @ngdoc method
1050
- * @name ngMock.$httpBackend#whenGET
1051
- * @methodOf ngMock.$httpBackend
1223
+ * @name $httpBackend#whenGET
1052
1224
  * @description
1053
1225
  * Creates a new backend definition for GET requests. For more info see `when()`.
1054
1226
  *
1055
- * @param {string|RegExp} url HTTP url.
1227
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
1228
+ * and returns true if the url match the current definition.
1056
1229
  * @param {(Object|function(Object))=} headers HTTP headers.
1057
1230
  * @returns {requestHandler} Returns an object with `respond` method that control how a matched
1058
1231
  * request is handled.
@@ -1060,12 +1233,12 @@ function createHttpBackendMock($rootScope, $delegate, $browser) {
1060
1233
 
1061
1234
  /**
1062
1235
  * @ngdoc method
1063
- * @name ngMock.$httpBackend#whenHEAD
1064
- * @methodOf ngMock.$httpBackend
1236
+ * @name $httpBackend#whenHEAD
1065
1237
  * @description
1066
1238
  * Creates a new backend definition for HEAD requests. For more info see `when()`.
1067
1239
  *
1068
- * @param {string|RegExp} url HTTP url.
1240
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
1241
+ * and returns true if the url match the current definition.
1069
1242
  * @param {(Object|function(Object))=} headers HTTP headers.
1070
1243
  * @returns {requestHandler} Returns an object with `respond` method that control how a matched
1071
1244
  * request is handled.
@@ -1073,12 +1246,12 @@ function createHttpBackendMock($rootScope, $delegate, $browser) {
1073
1246
 
1074
1247
  /**
1075
1248
  * @ngdoc method
1076
- * @name ngMock.$httpBackend#whenDELETE
1077
- * @methodOf ngMock.$httpBackend
1249
+ * @name $httpBackend#whenDELETE
1078
1250
  * @description
1079
1251
  * Creates a new backend definition for DELETE requests. For more info see `when()`.
1080
1252
  *
1081
- * @param {string|RegExp} url HTTP url.
1253
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
1254
+ * and returns true if the url match the current definition.
1082
1255
  * @param {(Object|function(Object))=} headers HTTP headers.
1083
1256
  * @returns {requestHandler} Returns an object with `respond` method that control how a matched
1084
1257
  * request is handled.
@@ -1086,13 +1259,14 @@ function createHttpBackendMock($rootScope, $delegate, $browser) {
1086
1259
 
1087
1260
  /**
1088
1261
  * @ngdoc method
1089
- * @name ngMock.$httpBackend#whenPOST
1090
- * @methodOf ngMock.$httpBackend
1262
+ * @name $httpBackend#whenPOST
1091
1263
  * @description
1092
1264
  * Creates a new backend definition for POST requests. For more info see `when()`.
1093
1265
  *
1094
- * @param {string|RegExp} url HTTP url.
1095
- * @param {(string|RegExp)=} data HTTP request body.
1266
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
1267
+ * and returns true if the url match the current definition.
1268
+ * @param {(string|RegExp|function(string))=} data HTTP request body or function that receives
1269
+ * data string and returns true if the data is as expected.
1096
1270
  * @param {(Object|function(Object))=} headers HTTP headers.
1097
1271
  * @returns {requestHandler} Returns an object with `respond` method that control how a matched
1098
1272
  * request is handled.
@@ -1100,13 +1274,14 @@ function createHttpBackendMock($rootScope, $delegate, $browser) {
1100
1274
 
1101
1275
  /**
1102
1276
  * @ngdoc method
1103
- * @name ngMock.$httpBackend#whenPUT
1104
- * @methodOf ngMock.$httpBackend
1277
+ * @name $httpBackend#whenPUT
1105
1278
  * @description
1106
1279
  * Creates a new backend definition for PUT requests. For more info see `when()`.
1107
1280
  *
1108
- * @param {string|RegExp} url HTTP url.
1109
- * @param {(string|RegExp)=} data HTTP request body.
1281
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
1282
+ * and returns true if the url match the current definition.
1283
+ * @param {(string|RegExp|function(string))=} data HTTP request body or function that receives
1284
+ * data string and returns true if the data is as expected.
1110
1285
  * @param {(Object|function(Object))=} headers HTTP headers.
1111
1286
  * @returns {requestHandler} Returns an object with `respond` method that control how a matched
1112
1287
  * request is handled.
@@ -1114,12 +1289,12 @@ function createHttpBackendMock($rootScope, $delegate, $browser) {
1114
1289
 
1115
1290
  /**
1116
1291
  * @ngdoc method
1117
- * @name ngMock.$httpBackend#whenJSONP
1118
- * @methodOf ngMock.$httpBackend
1292
+ * @name $httpBackend#whenJSONP
1119
1293
  * @description
1120
1294
  * Creates a new backend definition for JSONP requests. For more info see `when()`.
1121
1295
  *
1122
- * @param {string|RegExp} url HTTP url.
1296
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
1297
+ * and returns true if the url match the current definition.
1123
1298
  * @returns {requestHandler} Returns an object with `respond` method that control how a matched
1124
1299
  * request is handled.
1125
1300
  */
@@ -1128,20 +1303,23 @@ function createHttpBackendMock($rootScope, $delegate, $browser) {
1128
1303
 
1129
1304
  /**
1130
1305
  * @ngdoc method
1131
- * @name ngMock.$httpBackend#expect
1132
- * @methodOf ngMock.$httpBackend
1306
+ * @name $httpBackend#expect
1133
1307
  * @description
1134
1308
  * Creates a new request expectation.
1135
1309
  *
1136
1310
  * @param {string} method HTTP method.
1137
- * @param {string|RegExp} url HTTP url.
1138
- * @param {(string|RegExp)=} data HTTP request body.
1311
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
1312
+ * and returns true if the url match the current definition.
1313
+ * @param {(string|RegExp|function(string)|Object)=} data HTTP request body or function that
1314
+ * receives data string and returns true if the data is as expected, or Object if request body
1315
+ * is in JSON format.
1139
1316
  * @param {(Object|function(Object))=} headers HTTP headers or function that receives http header
1140
1317
  * object and returns true if the headers match the current expectation.
1141
1318
  * @returns {requestHandler} Returns an object with `respond` method that control how a matched
1142
1319
  * request is handled.
1143
1320
  *
1144
- * - respond – `{function([status,] data[, headers])|function(function(method, url, data, headers)}`
1321
+ * - respond –
1322
+ * `{function([status,] data[, headers])|function(function(method, url, data, headers)}`
1145
1323
  * – The respond method takes a set of static data to be returned or a function that can return
1146
1324
  * an array containing response status (number), response data (string) and response headers
1147
1325
  * (Object).
@@ -1159,12 +1337,12 @@ function createHttpBackendMock($rootScope, $delegate, $browser) {
1159
1337
 
1160
1338
  /**
1161
1339
  * @ngdoc method
1162
- * @name ngMock.$httpBackend#expectGET
1163
- * @methodOf ngMock.$httpBackend
1340
+ * @name $httpBackend#expectGET
1164
1341
  * @description
1165
1342
  * Creates a new request expectation for GET requests. For more info see `expect()`.
1166
1343
  *
1167
- * @param {string|RegExp} url HTTP url.
1344
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
1345
+ * and returns true if the url match the current definition.
1168
1346
  * @param {Object=} headers HTTP headers.
1169
1347
  * @returns {requestHandler} Returns an object with `respond` method that control how a matched
1170
1348
  * request is handled. See #expect for more info.
@@ -1172,12 +1350,12 @@ function createHttpBackendMock($rootScope, $delegate, $browser) {
1172
1350
 
1173
1351
  /**
1174
1352
  * @ngdoc method
1175
- * @name ngMock.$httpBackend#expectHEAD
1176
- * @methodOf ngMock.$httpBackend
1353
+ * @name $httpBackend#expectHEAD
1177
1354
  * @description
1178
1355
  * Creates a new request expectation for HEAD requests. For more info see `expect()`.
1179
1356
  *
1180
- * @param {string|RegExp} url HTTP url.
1357
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
1358
+ * and returns true if the url match the current definition.
1181
1359
  * @param {Object=} headers HTTP headers.
1182
1360
  * @returns {requestHandler} Returns an object with `respond` method that control how a matched
1183
1361
  * request is handled.
@@ -1185,12 +1363,12 @@ function createHttpBackendMock($rootScope, $delegate, $browser) {
1185
1363
 
1186
1364
  /**
1187
1365
  * @ngdoc method
1188
- * @name ngMock.$httpBackend#expectDELETE
1189
- * @methodOf ngMock.$httpBackend
1366
+ * @name $httpBackend#expectDELETE
1190
1367
  * @description
1191
1368
  * Creates a new request expectation for DELETE requests. For more info see `expect()`.
1192
1369
  *
1193
- * @param {string|RegExp} url HTTP url.
1370
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
1371
+ * and returns true if the url match the current definition.
1194
1372
  * @param {Object=} headers HTTP headers.
1195
1373
  * @returns {requestHandler} Returns an object with `respond` method that control how a matched
1196
1374
  * request is handled.
@@ -1198,13 +1376,15 @@ function createHttpBackendMock($rootScope, $delegate, $browser) {
1198
1376
 
1199
1377
  /**
1200
1378
  * @ngdoc method
1201
- * @name ngMock.$httpBackend#expectPOST
1202
- * @methodOf ngMock.$httpBackend
1379
+ * @name $httpBackend#expectPOST
1203
1380
  * @description
1204
1381
  * Creates a new request expectation for POST requests. For more info see `expect()`.
1205
1382
  *
1206
- * @param {string|RegExp} url HTTP url.
1207
- * @param {(string|RegExp)=} data HTTP request body.
1383
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
1384
+ * and returns true if the url match the current definition.
1385
+ * @param {(string|RegExp|function(string)|Object)=} data HTTP request body or function that
1386
+ * receives data string and returns true if the data is as expected, or Object if request body
1387
+ * is in JSON format.
1208
1388
  * @param {Object=} headers HTTP headers.
1209
1389
  * @returns {requestHandler} Returns an object with `respond` method that control how a matched
1210
1390
  * request is handled.
@@ -1212,13 +1392,15 @@ function createHttpBackendMock($rootScope, $delegate, $browser) {
1212
1392
 
1213
1393
  /**
1214
1394
  * @ngdoc method
1215
- * @name ngMock.$httpBackend#expectPUT
1216
- * @methodOf ngMock.$httpBackend
1395
+ * @name $httpBackend#expectPUT
1217
1396
  * @description
1218
1397
  * Creates a new request expectation for PUT requests. For more info see `expect()`.
1219
1398
  *
1220
- * @param {string|RegExp} url HTTP url.
1221
- * @param {(string|RegExp)=} data HTTP request body.
1399
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
1400
+ * and returns true if the url match the current definition.
1401
+ * @param {(string|RegExp|function(string)|Object)=} data HTTP request body or function that
1402
+ * receives data string and returns true if the data is as expected, or Object if request body
1403
+ * is in JSON format.
1222
1404
  * @param {Object=} headers HTTP headers.
1223
1405
  * @returns {requestHandler} Returns an object with `respond` method that control how a matched
1224
1406
  * request is handled.
@@ -1226,13 +1408,15 @@ function createHttpBackendMock($rootScope, $delegate, $browser) {
1226
1408
 
1227
1409
  /**
1228
1410
  * @ngdoc method
1229
- * @name ngMock.$httpBackend#expectPATCH
1230
- * @methodOf ngMock.$httpBackend
1411
+ * @name $httpBackend#expectPATCH
1231
1412
  * @description
1232
1413
  * Creates a new request expectation for PATCH requests. For more info see `expect()`.
1233
1414
  *
1234
- * @param {string|RegExp} url HTTP url.
1235
- * @param {(string|RegExp)=} data HTTP request body.
1415
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
1416
+ * and returns true if the url match the current definition.
1417
+ * @param {(string|RegExp|function(string)|Object)=} data HTTP request body or function that
1418
+ * receives data string and returns true if the data is as expected, or Object if request body
1419
+ * is in JSON format.
1236
1420
  * @param {Object=} headers HTTP headers.
1237
1421
  * @returns {requestHandler} Returns an object with `respond` method that control how a matched
1238
1422
  * request is handled.
@@ -1240,12 +1424,12 @@ function createHttpBackendMock($rootScope, $delegate, $browser) {
1240
1424
 
1241
1425
  /**
1242
1426
  * @ngdoc method
1243
- * @name ngMock.$httpBackend#expectJSONP
1244
- * @methodOf ngMock.$httpBackend
1427
+ * @name $httpBackend#expectJSONP
1245
1428
  * @description
1246
1429
  * Creates a new request expectation for JSONP requests. For more info see `expect()`.
1247
1430
  *
1248
- * @param {string|RegExp} url HTTP url.
1431
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
1432
+ * and returns true if the url match the current definition.
1249
1433
  * @returns {requestHandler} Returns an object with `respond` method that control how a matched
1250
1434
  * request is handled.
1251
1435
  */
@@ -1254,8 +1438,7 @@ function createHttpBackendMock($rootScope, $delegate, $browser) {
1254
1438
 
1255
1439
  /**
1256
1440
  * @ngdoc method
1257
- * @name ngMock.$httpBackend#flush
1258
- * @methodOf ngMock.$httpBackend
1441
+ * @name $httpBackend#flush
1259
1442
  * @description
1260
1443
  * Flushes all pending requests using the trained responses.
1261
1444
  *
@@ -1265,11 +1448,11 @@ function createHttpBackendMock($rootScope, $delegate, $browser) {
1265
1448
  */
1266
1449
  $httpBackend.flush = function(count) {
1267
1450
  $rootScope.$digest();
1268
- if (!responses.length) throw Error('No pending request to flush !');
1451
+ if (!responses.length) throw new Error('No pending request to flush !');
1269
1452
 
1270
1453
  if (angular.isDefined(count)) {
1271
1454
  while (count--) {
1272
- if (!responses.length) throw Error('No more pending request to flush !');
1455
+ if (!responses.length) throw new Error('No more pending request to flush !');
1273
1456
  responses.shift()();
1274
1457
  }
1275
1458
  } else {
@@ -1283,8 +1466,7 @@ function createHttpBackendMock($rootScope, $delegate, $browser) {
1283
1466
 
1284
1467
  /**
1285
1468
  * @ngdoc method
1286
- * @name ngMock.$httpBackend#verifyNoOutstandingExpectation
1287
- * @methodOf ngMock.$httpBackend
1469
+ * @name $httpBackend#verifyNoOutstandingExpectation
1288
1470
  * @description
1289
1471
  * Verifies that all of the requests defined via the `expect` api were made. If any of the
1290
1472
  * requests were not made, verifyNoOutstandingExpectation throws an exception.
@@ -1292,43 +1474,41 @@ function createHttpBackendMock($rootScope, $delegate, $browser) {
1292
1474
  * Typically, you would call this method following each test case that asserts requests using an
1293
1475
  * "afterEach" clause.
1294
1476
  *
1295
- * <pre>
1296
- * afterEach($httpBackend.verifyExpectations);
1297
- * </pre>
1477
+ * ```js
1478
+ * afterEach($httpBackend.verifyNoOutstandingExpectation);
1479
+ * ```
1298
1480
  */
1299
1481
  $httpBackend.verifyNoOutstandingExpectation = function() {
1300
1482
  $rootScope.$digest();
1301
1483
  if (expectations.length) {
1302
- throw Error('Unsatisfied requests: ' + expectations.join(', '));
1484
+ throw new Error('Unsatisfied requests: ' + expectations.join(', '));
1303
1485
  }
1304
1486
  };
1305
1487
 
1306
1488
 
1307
1489
  /**
1308
1490
  * @ngdoc method
1309
- * @name ngMock.$httpBackend#verifyNoOutstandingRequest
1310
- * @methodOf ngMock.$httpBackend
1491
+ * @name $httpBackend#verifyNoOutstandingRequest
1311
1492
  * @description
1312
1493
  * Verifies that there are no outstanding requests that need to be flushed.
1313
1494
  *
1314
1495
  * Typically, you would call this method following each test case that asserts requests using an
1315
1496
  * "afterEach" clause.
1316
1497
  *
1317
- * <pre>
1498
+ * ```js
1318
1499
  * afterEach($httpBackend.verifyNoOutstandingRequest);
1319
- * </pre>
1500
+ * ```
1320
1501
  */
1321
1502
  $httpBackend.verifyNoOutstandingRequest = function() {
1322
1503
  if (responses.length) {
1323
- throw Error('Unflushed requests: ' + responses.length);
1504
+ throw new Error('Unflushed requests: ' + responses.length);
1324
1505
  }
1325
1506
  };
1326
1507
 
1327
1508
 
1328
1509
  /**
1329
1510
  * @ngdoc method
1330
- * @name ngMock.$httpBackend#resetExpectations
1331
- * @methodOf ngMock.$httpBackend
1511
+ * @name $httpBackend#resetExpectations
1332
1512
  * @description
1333
1513
  * Resets all request expectations, but preserves all backend definitions. Typically, you would
1334
1514
  * call resetExpectations during a multiple-phase test when you want to reuse the same instance of
@@ -1345,14 +1525,14 @@ function createHttpBackendMock($rootScope, $delegate, $browser) {
1345
1525
  function createShortMethods(prefix) {
1346
1526
  angular.forEach(['GET', 'DELETE', 'JSONP'], function(method) {
1347
1527
  $httpBackend[prefix + method] = function(url, headers) {
1348
- return $httpBackend[prefix](method, url, undefined, headers)
1349
- }
1528
+ return $httpBackend[prefix](method, url, undefined, headers);
1529
+ };
1350
1530
  });
1351
1531
 
1352
1532
  angular.forEach(['PUT', 'POST', 'PATCH'], function(method) {
1353
1533
  $httpBackend[prefix + method] = function(url, data, headers) {
1354
- return $httpBackend[prefix](method, url, data, headers)
1355
- }
1534
+ return $httpBackend[prefix](method, url, data, headers);
1535
+ };
1356
1536
  });
1357
1537
  }
1358
1538
  }
@@ -1373,6 +1553,7 @@ function MockHttpExpectation(method, url, data, headers) {
1373
1553
  this.matchUrl = function(u) {
1374
1554
  if (!url) return true;
1375
1555
  if (angular.isFunction(url.test)) return url.test(u);
1556
+ if (angular.isFunction(url)) return url(u);
1376
1557
  return url == u;
1377
1558
  };
1378
1559
 
@@ -1385,7 +1566,8 @@ function MockHttpExpectation(method, url, data, headers) {
1385
1566
  this.matchData = function(d) {
1386
1567
  if (angular.isUndefined(data)) return true;
1387
1568
  if (data && angular.isFunction(data.test)) return data.test(d);
1388
- if (data && !angular.isString(data)) return angular.toJson(data) == d;
1569
+ if (data && angular.isFunction(data)) return data(d);
1570
+ if (data && !angular.isString(data)) return angular.equals(data, angular.fromJson(d));
1389
1571
  return data == d;
1390
1572
  };
1391
1573
 
@@ -1394,6 +1576,10 @@ function MockHttpExpectation(method, url, data, headers) {
1394
1576
  };
1395
1577
  }
1396
1578
 
1579
+ function createMockXhr() {
1580
+ return new MockXhr();
1581
+ }
1582
+
1397
1583
  function MockXhr() {
1398
1584
 
1399
1585
  // hack for testing $http, $httpBackend
@@ -1416,7 +1602,8 @@ function MockXhr() {
1416
1602
  };
1417
1603
 
1418
1604
  this.getResponseHeader = function(name) {
1419
- // the lookup must be case insensitive, that's why we try two quick lookups and full scan at last
1605
+ // the lookup must be case insensitive,
1606
+ // that's why we try two quick lookups first and full scan last
1420
1607
  var header = this.$$respHeaders[name];
1421
1608
  if (header) return header;
1422
1609
 
@@ -1445,39 +1632,39 @@ function MockXhr() {
1445
1632
 
1446
1633
 
1447
1634
  /**
1448
- * @ngdoc function
1449
- * @name ngMock.$timeout
1635
+ * @ngdoc service
1636
+ * @name $timeout
1450
1637
  * @description
1451
1638
  *
1452
1639
  * This service is just a simple decorator for {@link ng.$timeout $timeout} service
1453
1640
  * that adds a "flush" and "verifyNoPendingTasks" methods.
1454
- */
1641
+ */
1455
1642
 
1456
1643
  angular.mock.$TimeoutDecorator = function($delegate, $browser) {
1457
1644
 
1458
1645
  /**
1459
1646
  * @ngdoc method
1460
- * @name ngMock.$timeout#flush
1461
- * @methodOf ngMock.$timeout
1647
+ * @name $timeout#flush
1462
1648
  * @description
1463
1649
  *
1464
1650
  * Flushes the queue of pending tasks.
1651
+ *
1652
+ * @param {number=} delay maximum timeout amount to flush up until
1465
1653
  */
1466
- $delegate.flush = function() {
1467
- $browser.defer.flush();
1654
+ $delegate.flush = function(delay) {
1655
+ $browser.defer.flush(delay);
1468
1656
  };
1469
1657
 
1470
1658
  /**
1471
1659
  * @ngdoc method
1472
- * @name ngMock.$timeout#verifyNoPendingTasks
1473
- * @methodOf ngMock.$timeout
1660
+ * @name $timeout#verifyNoPendingTasks
1474
1661
  * @description
1475
1662
  *
1476
1663
  * Verifies that there are no pending tasks that need to be flushed.
1477
1664
  */
1478
1665
  $delegate.verifyNoPendingTasks = function() {
1479
1666
  if ($browser.deferredFns.length) {
1480
- throw Error('Deferred tasks to flush (' + $browser.deferredFns.length + '): ' +
1667
+ throw new Error('Deferred tasks to flush (' + $browser.deferredFns.length + '): ' +
1481
1668
  formatPendingTasksAsString($browser.deferredFns));
1482
1669
  }
1483
1670
  };
@@ -1494,49 +1681,103 @@ angular.mock.$TimeoutDecorator = function($delegate, $browser) {
1494
1681
  return $delegate;
1495
1682
  };
1496
1683
 
1684
+ angular.mock.$RAFDecorator = function($delegate) {
1685
+ var queue = [];
1686
+ var rafFn = function(fn) {
1687
+ var index = queue.length;
1688
+ queue.push(fn);
1689
+ return function() {
1690
+ queue.splice(index, 1);
1691
+ };
1692
+ };
1693
+
1694
+ rafFn.supported = $delegate.supported;
1695
+
1696
+ rafFn.flush = function() {
1697
+ if(queue.length === 0) {
1698
+ throw new Error('No rAF callbacks present');
1699
+ }
1700
+
1701
+ var length = queue.length;
1702
+ for(var i=0;i<length;i++) {
1703
+ queue[i]();
1704
+ }
1705
+
1706
+ queue = [];
1707
+ };
1708
+
1709
+ return rafFn;
1710
+ };
1711
+
1712
+ angular.mock.$AsyncCallbackDecorator = function($delegate) {
1713
+ var callbacks = [];
1714
+ var addFn = function(fn) {
1715
+ callbacks.push(fn);
1716
+ };
1717
+ addFn.flush = function() {
1718
+ angular.forEach(callbacks, function(fn) {
1719
+ fn();
1720
+ });
1721
+ callbacks = [];
1722
+ };
1723
+ return addFn;
1724
+ };
1725
+
1497
1726
  /**
1498
1727
  *
1499
1728
  */
1500
1729
  angular.mock.$RootElementProvider = function() {
1501
1730
  this.$get = function() {
1502
1731
  return angular.element('<div ng-app></div>');
1503
- }
1732
+ };
1504
1733
  };
1505
1734
 
1506
1735
  /**
1507
- * @ngdoc overview
1736
+ * @ngdoc module
1508
1737
  * @name ngMock
1509
1738
  * @description
1510
1739
  *
1511
- * The `ngMock` is an angular module which is used with `ng` module and adds unit-test configuration as well as useful
1512
- * mocks to the {@link AUTO.$injector $injector}.
1740
+ * # ngMock
1741
+ *
1742
+ * The `ngMock` module providers support to inject and mock Angular services into unit tests.
1743
+ * In addition, ngMock also extends various core ng services such that they can be
1744
+ * inspected and controlled in a synchronous manner within test code.
1745
+ *
1746
+ *
1747
+ * <div doc-module-components="ngMock"></div>
1748
+ *
1513
1749
  */
1514
1750
  angular.module('ngMock', ['ng']).provider({
1515
1751
  $browser: angular.mock.$BrowserProvider,
1516
1752
  $exceptionHandler: angular.mock.$ExceptionHandlerProvider,
1517
1753
  $log: angular.mock.$LogProvider,
1754
+ $interval: angular.mock.$IntervalProvider,
1518
1755
  $httpBackend: angular.mock.$HttpBackendProvider,
1519
1756
  $rootElement: angular.mock.$RootElementProvider
1520
- }).config(function($provide) {
1757
+ }).config(['$provide', function($provide) {
1521
1758
  $provide.decorator('$timeout', angular.mock.$TimeoutDecorator);
1522
- });
1759
+ $provide.decorator('$$rAF', angular.mock.$RAFDecorator);
1760
+ $provide.decorator('$$asyncCallback', angular.mock.$AsyncCallbackDecorator);
1761
+ }]);
1523
1762
 
1524
1763
  /**
1525
- * @ngdoc overview
1764
+ * @ngdoc module
1526
1765
  * @name ngMockE2E
1766
+ * @module ngMockE2E
1527
1767
  * @description
1528
1768
  *
1529
1769
  * The `ngMockE2E` is an angular module which contains mocks suitable for end-to-end testing.
1530
1770
  * Currently there is only one mock present in this module -
1531
1771
  * the {@link ngMockE2E.$httpBackend e2e $httpBackend} mock.
1532
1772
  */
1533
- angular.module('ngMockE2E', ['ng']).config(function($provide) {
1773
+ angular.module('ngMockE2E', ['ng']).config(['$provide', function($provide) {
1534
1774
  $provide.decorator('$httpBackend', angular.mock.e2e.$httpBackendDecorator);
1535
- });
1775
+ }]);
1536
1776
 
1537
1777
  /**
1538
- * @ngdoc object
1539
- * @name ngMockE2E.$httpBackend
1778
+ * @ngdoc service
1779
+ * @name $httpBackend
1780
+ * @module ngMockE2E
1540
1781
  * @description
1541
1782
  * Fake HTTP backend implementation suitable for end-to-end testing or backend-less development of
1542
1783
  * applications that use the {@link ng.$http $http service}.
@@ -1562,7 +1803,7 @@ angular.module('ngMockE2E', ['ng']).config(function($provide) {
1562
1803
  * To setup the application to run with this http backend, you have to create a module that depends
1563
1804
  * on the `ngMockE2E` and your application modules and defines the fake backend:
1564
1805
  *
1565
- * <pre>
1806
+ * ```js
1566
1807
  * myAppDev = angular.module('myAppDev', ['myApp', 'ngMockE2E']);
1567
1808
  * myAppDev.run(function($httpBackend) {
1568
1809
  * phones = [{name: 'phone1'}, {name: 'phone2'}];
@@ -1572,48 +1813,51 @@ angular.module('ngMockE2E', ['ng']).config(function($provide) {
1572
1813
  *
1573
1814
  * // adds a new phone to the phones array
1574
1815
  * $httpBackend.whenPOST('/phones').respond(function(method, url, data) {
1575
- * phones.push(angular.fromJSON(data));
1816
+ * phones.push(angular.fromJson(data));
1576
1817
  * });
1577
1818
  * $httpBackend.whenGET(/^\/templates\//).passThrough();
1578
1819
  * //...
1579
1820
  * });
1580
- * </pre>
1821
+ * ```
1581
1822
  *
1582
1823
  * Afterwards, bootstrap your app with this new module.
1583
1824
  */
1584
1825
 
1585
1826
  /**
1586
1827
  * @ngdoc method
1587
- * @name ngMockE2E.$httpBackend#when
1588
- * @methodOf ngMockE2E.$httpBackend
1828
+ * @name $httpBackend#when
1829
+ * @module ngMockE2E
1589
1830
  * @description
1590
1831
  * Creates a new backend definition.
1591
1832
  *
1592
1833
  * @param {string} method HTTP method.
1593
- * @param {string|RegExp} url HTTP url.
1834
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
1835
+ * and returns true if the url match the current definition.
1594
1836
  * @param {(string|RegExp)=} data HTTP request body.
1595
1837
  * @param {(Object|function(Object))=} headers HTTP headers or function that receives http header
1596
1838
  * object and returns true if the headers match the current definition.
1597
1839
  * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
1598
1840
  * control how a matched request is handled.
1599
1841
  *
1600
- * - respond – `{function([status,] data[, headers])|function(function(method, url, data, headers)}`
1842
+ * - respond –
1843
+ * `{function([status,] data[, headers])|function(function(method, url, data, headers)}`
1601
1844
  * – The respond method takes a set of static data to be returned or a function that can return
1602
1845
  * an array containing response status (number), response data (string) and response headers
1603
1846
  * (Object).
1604
1847
  * - passThrough – `{function()}` – Any request matching a backend definition with `passThrough`
1605
- * handler, will be pass through to the real backend (an XHR request will be made to the
1606
- * server.
1848
+ * handler will be passed through to the real backend (an XHR request will be made to the
1849
+ * server.)
1607
1850
  */
1608
1851
 
1609
1852
  /**
1610
1853
  * @ngdoc method
1611
- * @name ngMockE2E.$httpBackend#whenGET
1612
- * @methodOf ngMockE2E.$httpBackend
1854
+ * @name $httpBackend#whenGET
1855
+ * @module ngMockE2E
1613
1856
  * @description
1614
1857
  * Creates a new backend definition for GET requests. For more info see `when()`.
1615
1858
  *
1616
- * @param {string|RegExp} url HTTP url.
1859
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
1860
+ * and returns true if the url match the current definition.
1617
1861
  * @param {(Object|function(Object))=} headers HTTP headers.
1618
1862
  * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
1619
1863
  * control how a matched request is handled.
@@ -1621,12 +1865,13 @@ angular.module('ngMockE2E', ['ng']).config(function($provide) {
1621
1865
 
1622
1866
  /**
1623
1867
  * @ngdoc method
1624
- * @name ngMockE2E.$httpBackend#whenHEAD
1625
- * @methodOf ngMockE2E.$httpBackend
1868
+ * @name $httpBackend#whenHEAD
1869
+ * @module ngMockE2E
1626
1870
  * @description
1627
1871
  * Creates a new backend definition for HEAD requests. For more info see `when()`.
1628
1872
  *
1629
- * @param {string|RegExp} url HTTP url.
1873
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
1874
+ * and returns true if the url match the current definition.
1630
1875
  * @param {(Object|function(Object))=} headers HTTP headers.
1631
1876
  * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
1632
1877
  * control how a matched request is handled.
@@ -1634,12 +1879,13 @@ angular.module('ngMockE2E', ['ng']).config(function($provide) {
1634
1879
 
1635
1880
  /**
1636
1881
  * @ngdoc method
1637
- * @name ngMockE2E.$httpBackend#whenDELETE
1638
- * @methodOf ngMockE2E.$httpBackend
1882
+ * @name $httpBackend#whenDELETE
1883
+ * @module ngMockE2E
1639
1884
  * @description
1640
1885
  * Creates a new backend definition for DELETE requests. For more info see `when()`.
1641
1886
  *
1642
- * @param {string|RegExp} url HTTP url.
1887
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
1888
+ * and returns true if the url match the current definition.
1643
1889
  * @param {(Object|function(Object))=} headers HTTP headers.
1644
1890
  * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
1645
1891
  * control how a matched request is handled.
@@ -1647,12 +1893,13 @@ angular.module('ngMockE2E', ['ng']).config(function($provide) {
1647
1893
 
1648
1894
  /**
1649
1895
  * @ngdoc method
1650
- * @name ngMockE2E.$httpBackend#whenPOST
1651
- * @methodOf ngMockE2E.$httpBackend
1896
+ * @name $httpBackend#whenPOST
1897
+ * @module ngMockE2E
1652
1898
  * @description
1653
1899
  * Creates a new backend definition for POST requests. For more info see `when()`.
1654
1900
  *
1655
- * @param {string|RegExp} url HTTP url.
1901
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
1902
+ * and returns true if the url match the current definition.
1656
1903
  * @param {(string|RegExp)=} data HTTP request body.
1657
1904
  * @param {(Object|function(Object))=} headers HTTP headers.
1658
1905
  * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
@@ -1661,12 +1908,13 @@ angular.module('ngMockE2E', ['ng']).config(function($provide) {
1661
1908
 
1662
1909
  /**
1663
1910
  * @ngdoc method
1664
- * @name ngMockE2E.$httpBackend#whenPUT
1665
- * @methodOf ngMockE2E.$httpBackend
1911
+ * @name $httpBackend#whenPUT
1912
+ * @module ngMockE2E
1666
1913
  * @description
1667
1914
  * Creates a new backend definition for PUT requests. For more info see `when()`.
1668
1915
  *
1669
- * @param {string|RegExp} url HTTP url.
1916
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
1917
+ * and returns true if the url match the current definition.
1670
1918
  * @param {(string|RegExp)=} data HTTP request body.
1671
1919
  * @param {(Object|function(Object))=} headers HTTP headers.
1672
1920
  * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
@@ -1675,12 +1923,13 @@ angular.module('ngMockE2E', ['ng']).config(function($provide) {
1675
1923
 
1676
1924
  /**
1677
1925
  * @ngdoc method
1678
- * @name ngMockE2E.$httpBackend#whenPATCH
1679
- * @methodOf ngMockE2E.$httpBackend
1926
+ * @name $httpBackend#whenPATCH
1927
+ * @module ngMockE2E
1680
1928
  * @description
1681
1929
  * Creates a new backend definition for PATCH requests. For more info see `when()`.
1682
1930
  *
1683
- * @param {string|RegExp} url HTTP url.
1931
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
1932
+ * and returns true if the url match the current definition.
1684
1933
  * @param {(string|RegExp)=} data HTTP request body.
1685
1934
  * @param {(Object|function(Object))=} headers HTTP headers.
1686
1935
  * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
@@ -1689,17 +1938,19 @@ angular.module('ngMockE2E', ['ng']).config(function($provide) {
1689
1938
 
1690
1939
  /**
1691
1940
  * @ngdoc method
1692
- * @name ngMockE2E.$httpBackend#whenJSONP
1693
- * @methodOf ngMockE2E.$httpBackend
1941
+ * @name $httpBackend#whenJSONP
1942
+ * @module ngMockE2E
1694
1943
  * @description
1695
1944
  * Creates a new backend definition for JSONP requests. For more info see `when()`.
1696
1945
  *
1697
- * @param {string|RegExp} url HTTP url.
1946
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
1947
+ * and returns true if the url match the current definition.
1698
1948
  * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
1699
1949
  * control how a matched request is handled.
1700
1950
  */
1701
1951
  angular.mock.e2e = {};
1702
- angular.mock.e2e.$httpBackendDecorator = ['$rootScope', '$delegate', '$browser', createHttpBackendMock];
1952
+ angular.mock.e2e.$httpBackendDecorator =
1953
+ ['$rootScope', '$delegate', '$browser', createHttpBackendMock];
1703
1954
 
1704
1955
 
1705
1956
  angular.mock.clearDataCache = function() {
@@ -1707,36 +1958,23 @@ angular.mock.clearDataCache = function() {
1707
1958
  cache = angular.element.cache;
1708
1959
 
1709
1960
  for(key in cache) {
1710
- if (cache.hasOwnProperty(key)) {
1961
+ if (Object.prototype.hasOwnProperty.call(cache,key)) {
1711
1962
  var handle = cache[key].handle;
1712
1963
 
1713
- handle && angular.element(handle.elem).unbind();
1964
+ handle && angular.element(handle.elem).off();
1714
1965
  delete cache[key];
1715
1966
  }
1716
1967
  }
1717
1968
  };
1718
1969
 
1719
1970
 
1720
- window.jstestdriver && (function(window) {
1721
- /**
1722
- * Global method to output any number of objects into JSTD console. Useful for debugging.
1723
- */
1724
- window.dump = function() {
1725
- var args = [];
1726
- angular.forEach(arguments, function(arg) {
1727
- args.push(angular.mock.dump(arg));
1728
- });
1729
- jstestdriver.console.log.apply(jstestdriver.console, args);
1730
- if (window.console) {
1731
- window.console.log.apply(window.console, args);
1732
- }
1733
- };
1734
- })(window);
1735
-
1971
+ if(window.jasmine || window.mocha) {
1736
1972
 
1737
- (window.jasmine || window.mocha) && (function(window) {
1973
+ var currentSpec = null,
1974
+ isSpecRunning = function() {
1975
+ return !!currentSpec;
1976
+ };
1738
1977
 
1739
- var currentSpec = null;
1740
1978
 
1741
1979
  beforeEach(function() {
1742
1980
  currentSpec = this;
@@ -1750,7 +1988,7 @@ window.jstestdriver && (function(window) {
1750
1988
  currentSpec = null;
1751
1989
 
1752
1990
  if (injector) {
1753
- injector.get('$rootElement').unbind();
1991
+ injector.get('$rootElement').off();
1754
1992
  injector.get('$browser').pollFns.length = 0;
1755
1993
  }
1756
1994
 
@@ -1769,10 +2007,6 @@ window.jstestdriver && (function(window) {
1769
2007
  angular.callbacks.counter = 0;
1770
2008
  });
1771
2009
 
1772
- function isSpecRunning() {
1773
- return currentSpec && (window.mocha || currentSpec.queue.running);
1774
- }
1775
-
1776
2010
  /**
1777
2011
  * @ngdoc function
1778
2012
  * @name angular.mock.module
@@ -1785,9 +2019,11 @@ window.jstestdriver && (function(window) {
1785
2019
  *
1786
2020
  * See {@link angular.mock.inject inject} for usage example
1787
2021
  *
1788
- * @param {...(string|Function)} fns any number of modules which are represented as string
2022
+ * @param {...(string|Function|Object)} fns any number of modules which are represented as string
1789
2023
  * aliases or as anonymous module initialization functions. The modules are used to
1790
- * configure the injector. The 'ng' and 'ngMock' modules are automatically loaded.
2024
+ * configure the injector. The 'ng' and 'ngMock' modules are automatically loaded. If an
2025
+ * object literal is passed they will be register as values in the module, the key being
2026
+ * the module name and the value being what is returned.
1791
2027
  */
1792
2028
  window.module = angular.mock.module = function() {
1793
2029
  var moduleFns = Array.prototype.slice.call(arguments, 0);
@@ -1795,11 +2031,19 @@ window.jstestdriver && (function(window) {
1795
2031
  /////////////////////
1796
2032
  function workFn() {
1797
2033
  if (currentSpec.$injector) {
1798
- throw Error('Injector already created, can not register a module!');
2034
+ throw new Error('Injector already created, can not register a module!');
1799
2035
  } else {
1800
2036
  var modules = currentSpec.$modules || (currentSpec.$modules = []);
1801
2037
  angular.forEach(moduleFns, function(module) {
1802
- modules.push(module);
2038
+ if (angular.isObject(module) && !angular.isArray(module)) {
2039
+ modules.push(function($provide) {
2040
+ angular.forEach(module, function(value, key) {
2041
+ $provide.value(key, value);
2042
+ });
2043
+ });
2044
+ } else {
2045
+ modules.push(module);
2046
+ }
1803
2047
  });
1804
2048
  }
1805
2049
  }
@@ -1813,13 +2057,45 @@ window.jstestdriver && (function(window) {
1813
2057
  * *NOTE*: This function is also published on window for easy access.<br>
1814
2058
  *
1815
2059
  * The inject function wraps a function into an injectable function. The inject() creates new
1816
- * instance of {@link AUTO.$injector $injector} per test, which is then used for
2060
+ * instance of {@link auto.$injector $injector} per test, which is then used for
1817
2061
  * resolving references.
1818
2062
  *
1819
- * See also {@link angular.mock.module module}
1820
2063
  *
2064
+ * ## Resolving References (Underscore Wrapping)
2065
+ * Often, we would like to inject a reference once, in a `beforeEach()` block and reuse this
2066
+ * in multiple `it()` clauses. To be able to do this we must assign the reference to a variable
2067
+ * that is declared in the scope of the `describe()` block. Since we would, most likely, want
2068
+ * the variable to have the same name of the reference we have a problem, since the parameter
2069
+ * to the `inject()` function would hide the outer variable.
2070
+ *
2071
+ * To help with this, the injected parameters can, optionally, be enclosed with underscores.
2072
+ * These are ignored by the injector when the reference name is resolved.
2073
+ *
2074
+ * For example, the parameter `_myService_` would be resolved as the reference `myService`.
2075
+ * Since it is available in the function body as _myService_, we can then assign it to a variable
2076
+ * defined in an outer scope.
2077
+ *
2078
+ * ```
2079
+ * // Defined out reference variable outside
2080
+ * var myService;
2081
+ *
2082
+ * // Wrap the parameter in underscores
2083
+ * beforeEach( inject( function(_myService_){
2084
+ * myService = _myService_;
2085
+ * }));
2086
+ *
2087
+ * // Use myService in a series of tests.
2088
+ * it('makes use of myService', function() {
2089
+ * myService.doStuff();
2090
+ * });
2091
+ *
2092
+ * ```
2093
+ *
2094
+ * See also {@link angular.mock.module angular.mock.module}
2095
+ *
2096
+ * ## Example
1821
2097
  * Example of what a typical jasmine tests looks like with the inject method.
1822
- * <pre>
2098
+ * ```js
1823
2099
  *
1824
2100
  * angular.module('myApplicationModule', [])
1825
2101
  * .value('mode', 'app')
@@ -1850,17 +2126,31 @@ window.jstestdriver && (function(window) {
1850
2126
  * inject(function(version) {
1851
2127
  * expect(version).toEqual('overridden');
1852
2128
  * });
1853
- * ));
2129
+ * });
1854
2130
  * });
1855
2131
  *
1856
- * </pre>
2132
+ * ```
1857
2133
  *
1858
2134
  * @param {...Function} fns any number of functions which will be injected using the injector.
1859
2135
  */
2136
+
2137
+
2138
+
2139
+ var ErrorAddingDeclarationLocationStack = function(e, errorForStack) {
2140
+ this.message = e.message;
2141
+ this.name = e.name;
2142
+ if (e.line) this.line = e.line;
2143
+ if (e.sourceId) this.sourceId = e.sourceId;
2144
+ if (e.stack && errorForStack)
2145
+ this.stack = e.stack + '\n' + errorForStack.stack;
2146
+ if (e.stackArray) this.stackArray = e.stackArray;
2147
+ };
2148
+ ErrorAddingDeclarationLocationStack.prototype.toString = Error.prototype.toString;
2149
+
1860
2150
  window.inject = angular.mock.inject = function() {
1861
2151
  var blockFns = Array.prototype.slice.call(arguments, 0);
1862
2152
  var errorForStack = new Error('Declaration Location');
1863
- return isSpecRunning() ? workFn() : workFn;
2153
+ return isSpecRunning() ? workFn.call(currentSpec) : workFn;
1864
2154
  /////////////////////
1865
2155
  function workFn() {
1866
2156
  var modules = currentSpec.$modules || [];
@@ -1873,9 +2163,13 @@ window.jstestdriver && (function(window) {
1873
2163
  }
1874
2164
  for(var i = 0, ii = blockFns.length; i < ii; i++) {
1875
2165
  try {
2166
+ /* jshint -W040 *//* Jasmine explicitly provides a `this` object when calling functions */
1876
2167
  injector.invoke(blockFns[i] || angular.noop, this);
2168
+ /* jshint +W040 */
1877
2169
  } catch (e) {
1878
- if(e.stack && errorForStack) e.stack += '\n' + errorForStack.stack;
2170
+ if (e.stack && errorForStack) {
2171
+ throw new ErrorAddingDeclarationLocationStack(e, errorForStack);
2172
+ }
1879
2173
  throw e;
1880
2174
  } finally {
1881
2175
  errorForStack = null;
@@ -1883,4 +2177,7 @@ window.jstestdriver && (function(window) {
1883
2177
  }
1884
2178
  }
1885
2179
  };
1886
- })(window);
2180
+ }
2181
+
2182
+
2183
+ })(window, window.angular);