angularjs-rails 1.2.14 → 1.2.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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);