nexus site path corrected
[portal.git] / ecomp-portal-FE / client / bower_components / angular-mocks / angular-mocks.js
1 /**
2  * @license AngularJS v1.5.11
3  * (c) 2010-2017 Google, Inc. http://angularjs.org
4  * License: MIT
5  */
6 (function(window, angular) {
7
8 'use strict';
9
10 /**
11  * @ngdoc object
12  * @name angular.mock
13  * @description
14  *
15  * Namespace from 'angular-mocks.js' which contains testing related code.
16  *
17  */
18 angular.mock = {};
19
20 /**
21  * ! This is a private undocumented service !
22  *
23  * @name $browser
24  *
25  * @description
26  * This service is a mock implementation of {@link ng.$browser}. It provides fake
27  * implementation for commonly used browser apis that are hard to test, e.g. setTimeout, xhr,
28  * cookies, etc.
29  *
30  * The api of this service is the same as that of the real {@link ng.$browser $browser}, except
31  * that there are several helper methods available which can be used in tests.
32  */
33 angular.mock.$BrowserProvider = function() {
34   this.$get = function() {
35     return new angular.mock.$Browser();
36   };
37 };
38
39 angular.mock.$Browser = function() {
40   var self = this;
41
42   this.isMock = true;
43   self.$$url = 'http://server/';
44   self.$$lastUrl = self.$$url; // used by url polling fn
45   self.pollFns = [];
46
47   // TODO(vojta): remove this temporary api
48   self.$$completeOutstandingRequest = angular.noop;
49   self.$$incOutstandingRequestCount = angular.noop;
50
51
52   // register url polling fn
53
54   self.onUrlChange = function(listener) {
55     self.pollFns.push(
56       function() {
57         if (self.$$lastUrl !== self.$$url || self.$$state !== self.$$lastState) {
58           self.$$lastUrl = self.$$url;
59           self.$$lastState = self.$$state;
60           listener(self.$$url, self.$$state);
61         }
62       }
63     );
64
65     return listener;
66   };
67
68   self.$$applicationDestroyed = angular.noop;
69   self.$$checkUrlChange = angular.noop;
70
71   self.deferredFns = [];
72   self.deferredNextId = 0;
73
74   self.defer = function(fn, delay) {
75     delay = delay || 0;
76     self.deferredFns.push({time:(self.defer.now + delay), fn:fn, id: self.deferredNextId});
77     self.deferredFns.sort(function(a, b) { return a.time - b.time;});
78     return self.deferredNextId++;
79   };
80
81
82   /**
83    * @name $browser#defer.now
84    *
85    * @description
86    * Current milliseconds mock time.
87    */
88   self.defer.now = 0;
89
90
91   self.defer.cancel = function(deferId) {
92     var fnIndex;
93
94     angular.forEach(self.deferredFns, function(fn, index) {
95       if (fn.id === deferId) fnIndex = index;
96     });
97
98     if (angular.isDefined(fnIndex)) {
99       self.deferredFns.splice(fnIndex, 1);
100       return true;
101     }
102
103     return false;
104   };
105
106
107   /**
108    * @name $browser#defer.flush
109    *
110    * @description
111    * Flushes all pending requests and executes the defer callbacks.
112    *
113    * @param {number=} number of milliseconds to flush. See {@link #defer.now}
114    */
115   self.defer.flush = function(delay) {
116     var nextTime;
117
118     if (angular.isDefined(delay)) {
119       // A delay was passed so compute the next time
120       nextTime = self.defer.now + delay;
121     } else {
122       if (self.deferredFns.length) {
123         // No delay was passed so set the next time so that it clears the deferred queue
124         nextTime = self.deferredFns[self.deferredFns.length - 1].time;
125       } else {
126         // No delay passed, but there are no deferred tasks so flush - indicates an error!
127         throw new Error('No deferred tasks to be flushed');
128       }
129     }
130
131     while (self.deferredFns.length && self.deferredFns[0].time <= nextTime) {
132       // Increment the time and call the next deferred function
133       self.defer.now = self.deferredFns[0].time;
134       self.deferredFns.shift().fn();
135     }
136
137     // Ensure that the current time is correct
138     self.defer.now = nextTime;
139   };
140
141   self.$$baseHref = '/';
142   self.baseHref = function() {
143     return this.$$baseHref;
144   };
145 };
146 angular.mock.$Browser.prototype = {
147
148   /**
149    * @name $browser#poll
150    *
151    * @description
152    * run all fns in pollFns
153    */
154   poll: function poll() {
155     angular.forEach(this.pollFns, function(pollFn) {
156       pollFn();
157     });
158   },
159
160   url: function(url, replace, state) {
161     if (angular.isUndefined(state)) {
162       state = null;
163     }
164     if (url) {
165       this.$$url = url;
166       // Native pushState serializes & copies the object; simulate it.
167       this.$$state = angular.copy(state);
168       return this;
169     }
170
171     return this.$$url;
172   },
173
174   state: function() {
175     return this.$$state;
176   },
177
178   notifyWhenNoOutstandingRequests: function(fn) {
179     fn();
180   }
181 };
182
183
184 /**
185  * @ngdoc provider
186  * @name $exceptionHandlerProvider
187  *
188  * @description
189  * Configures the mock implementation of {@link ng.$exceptionHandler} to rethrow or to log errors
190  * passed to the `$exceptionHandler`.
191  */
192
193 /**
194  * @ngdoc service
195  * @name $exceptionHandler
196  *
197  * @description
198  * Mock implementation of {@link ng.$exceptionHandler} that rethrows or logs errors passed
199  * to it. See {@link ngMock.$exceptionHandlerProvider $exceptionHandlerProvider} for configuration
200  * information.
201  *
202  *
203  * ```js
204  *   describe('$exceptionHandlerProvider', function() {
205  *
206  *     it('should capture log messages and exceptions', function() {
207  *
208  *       module(function($exceptionHandlerProvider) {
209  *         $exceptionHandlerProvider.mode('log');
210  *       });
211  *
212  *       inject(function($log, $exceptionHandler, $timeout) {
213  *         $timeout(function() { $log.log(1); });
214  *         $timeout(function() { $log.log(2); throw 'banana peel'; });
215  *         $timeout(function() { $log.log(3); });
216  *         expect($exceptionHandler.errors).toEqual([]);
217  *         expect($log.assertEmpty());
218  *         $timeout.flush();
219  *         expect($exceptionHandler.errors).toEqual(['banana peel']);
220  *         expect($log.log.logs).toEqual([[1], [2], [3]]);
221  *       });
222  *     });
223  *   });
224  * ```
225  */
226
227 angular.mock.$ExceptionHandlerProvider = function() {
228   var handler;
229
230   /**
231    * @ngdoc method
232    * @name $exceptionHandlerProvider#mode
233    *
234    * @description
235    * Sets the logging mode.
236    *
237    * @param {string} mode Mode of operation, defaults to `rethrow`.
238    *
239    *   - `log`: Sometimes it is desirable to test that an error is thrown, for this case the `log`
240    *     mode stores an array of errors in `$exceptionHandler.errors`, to allow later assertion of
241    *     them. See {@link ngMock.$log#assertEmpty assertEmpty()} and
242    *     {@link ngMock.$log#reset reset()}.
243    *   - `rethrow`: If any errors are passed to the handler in tests, it typically means that there
244    *     is a bug in the application or test, so this mock will make these tests fail. For any
245    *     implementations that expect exceptions to be thrown, the `rethrow` mode will also maintain
246    *     a log of thrown errors in `$exceptionHandler.errors`.
247    */
248   this.mode = function(mode) {
249
250     switch (mode) {
251       case 'log':
252       case 'rethrow':
253         var errors = [];
254         handler = function(e) {
255           if (arguments.length === 1) {
256             errors.push(e);
257           } else {
258             errors.push([].slice.call(arguments, 0));
259           }
260           if (mode === 'rethrow') {
261             throw e;
262           }
263         };
264         handler.errors = errors;
265         break;
266       default:
267         throw new Error('Unknown mode \'' + mode + '\', only \'log\'/\'rethrow\' modes are allowed!');
268     }
269   };
270
271   this.$get = function() {
272     return handler;
273   };
274
275   this.mode('rethrow');
276 };
277
278
279 /**
280  * @ngdoc service
281  * @name $log
282  *
283  * @description
284  * Mock implementation of {@link ng.$log} that gathers all logged messages in arrays
285  * (one array per logging level). These arrays are exposed as `logs` property of each of the
286  * level-specific log function, e.g. for level `error` the array is exposed as `$log.error.logs`.
287  *
288  */
289 angular.mock.$LogProvider = function() {
290   var debug = true;
291
292   function concat(array1, array2, index) {
293     return array1.concat(Array.prototype.slice.call(array2, index));
294   }
295
296   this.debugEnabled = function(flag) {
297     if (angular.isDefined(flag)) {
298       debug = flag;
299       return this;
300     } else {
301       return debug;
302     }
303   };
304
305   this.$get = function() {
306     var $log = {
307       log: function() { $log.log.logs.push(concat([], arguments, 0)); },
308       warn: function() { $log.warn.logs.push(concat([], arguments, 0)); },
309       info: function() { $log.info.logs.push(concat([], arguments, 0)); },
310       error: function() { $log.error.logs.push(concat([], arguments, 0)); },
311       debug: function() {
312         if (debug) {
313           $log.debug.logs.push(concat([], arguments, 0));
314         }
315       }
316     };
317
318     /**
319      * @ngdoc method
320      * @name $log#reset
321      *
322      * @description
323      * Reset all of the logging arrays to empty.
324      */
325     $log.reset = function() {
326       /**
327        * @ngdoc property
328        * @name $log#log.logs
329        *
330        * @description
331        * Array of messages logged using {@link ng.$log#log `log()`}.
332        *
333        * @example
334        * ```js
335        * $log.log('Some Log');
336        * var first = $log.log.logs.unshift();
337        * ```
338        */
339       $log.log.logs = [];
340       /**
341        * @ngdoc property
342        * @name $log#info.logs
343        *
344        * @description
345        * Array of messages logged using {@link ng.$log#info `info()`}.
346        *
347        * @example
348        * ```js
349        * $log.info('Some Info');
350        * var first = $log.info.logs.unshift();
351        * ```
352        */
353       $log.info.logs = [];
354       /**
355        * @ngdoc property
356        * @name $log#warn.logs
357        *
358        * @description
359        * Array of messages logged using {@link ng.$log#warn `warn()`}.
360        *
361        * @example
362        * ```js
363        * $log.warn('Some Warning');
364        * var first = $log.warn.logs.unshift();
365        * ```
366        */
367       $log.warn.logs = [];
368       /**
369        * @ngdoc property
370        * @name $log#error.logs
371        *
372        * @description
373        * Array of messages logged using {@link ng.$log#error `error()`}.
374        *
375        * @example
376        * ```js
377        * $log.error('Some Error');
378        * var first = $log.error.logs.unshift();
379        * ```
380        */
381       $log.error.logs = [];
382         /**
383        * @ngdoc property
384        * @name $log#debug.logs
385        *
386        * @description
387        * Array of messages logged using {@link ng.$log#debug `debug()`}.
388        *
389        * @example
390        * ```js
391        * $log.debug('Some Error');
392        * var first = $log.debug.logs.unshift();
393        * ```
394        */
395       $log.debug.logs = [];
396     };
397
398     /**
399      * @ngdoc method
400      * @name $log#assertEmpty
401      *
402      * @description
403      * Assert that all of the logging methods have no logged messages. If any messages are present,
404      * an exception is thrown.
405      */
406     $log.assertEmpty = function() {
407       var errors = [];
408       angular.forEach(['error', 'warn', 'info', 'log', 'debug'], function(logLevel) {
409         angular.forEach($log[logLevel].logs, function(log) {
410           angular.forEach(log, function(logItem) {
411             errors.push('MOCK $log (' + logLevel + '): ' + String(logItem) + '\n' +
412                         (logItem.stack || ''));
413           });
414         });
415       });
416       if (errors.length) {
417         errors.unshift('Expected $log to be empty! Either a message was logged unexpectedly, or ' +
418           'an expected log message was not checked and removed:');
419         errors.push('');
420         throw new Error(errors.join('\n---------\n'));
421       }
422     };
423
424     $log.reset();
425     return $log;
426   };
427 };
428
429
430 /**
431  * @ngdoc service
432  * @name $interval
433  *
434  * @description
435  * Mock implementation of the $interval service.
436  *
437  * Use {@link ngMock.$interval#flush `$interval.flush(millis)`} to
438  * move forward by `millis` milliseconds and trigger any functions scheduled to run in that
439  * time.
440  *
441  * @param {function()} fn A function that should be called repeatedly.
442  * @param {number} delay Number of milliseconds between each function call.
443  * @param {number=} [count=0] Number of times to repeat. If not set, or 0, will repeat
444  *   indefinitely.
445  * @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise
446  *   will invoke `fn` within the {@link ng.$rootScope.Scope#$apply $apply} block.
447  * @param {...*=} Pass additional parameters to the executed function.
448  * @returns {promise} A promise which will be notified on each iteration.
449  */
450 angular.mock.$IntervalProvider = function() {
451   this.$get = ['$browser', '$rootScope', '$q', '$$q',
452        function($browser,   $rootScope,   $q,   $$q) {
453     var repeatFns = [],
454         nextRepeatId = 0,
455         now = 0;
456
457     var $interval = function(fn, delay, count, invokeApply) {
458       var hasParams = arguments.length > 4,
459           args = hasParams ? Array.prototype.slice.call(arguments, 4) : [],
460           iteration = 0,
461           skipApply = (angular.isDefined(invokeApply) && !invokeApply),
462           deferred = (skipApply ? $$q : $q).defer(),
463           promise = deferred.promise;
464
465       count = (angular.isDefined(count)) ? count : 0;
466       promise.then(null, null, (!hasParams) ? fn : function() {
467         fn.apply(null, args);
468       });
469
470       promise.$$intervalId = nextRepeatId;
471
472       function tick() {
473         deferred.notify(iteration++);
474
475         if (count > 0 && iteration >= count) {
476           var fnIndex;
477           deferred.resolve(iteration);
478
479           angular.forEach(repeatFns, function(fn, index) {
480             if (fn.id === promise.$$intervalId) fnIndex = index;
481           });
482
483           if (angular.isDefined(fnIndex)) {
484             repeatFns.splice(fnIndex, 1);
485           }
486         }
487
488         if (skipApply) {
489           $browser.defer.flush();
490         } else {
491           $rootScope.$apply();
492         }
493       }
494
495       repeatFns.push({
496         nextTime:(now + delay),
497         delay: delay,
498         fn: tick,
499         id: nextRepeatId,
500         deferred: deferred
501       });
502       repeatFns.sort(function(a, b) { return a.nextTime - b.nextTime;});
503
504       nextRepeatId++;
505       return promise;
506     };
507     /**
508      * @ngdoc method
509      * @name $interval#cancel
510      *
511      * @description
512      * Cancels a task associated with the `promise`.
513      *
514      * @param {promise} promise A promise from calling the `$interval` function.
515      * @returns {boolean} Returns `true` if the task was successfully cancelled.
516      */
517     $interval.cancel = function(promise) {
518       if (!promise) return false;
519       var fnIndex;
520
521       angular.forEach(repeatFns, function(fn, index) {
522         if (fn.id === promise.$$intervalId) fnIndex = index;
523       });
524
525       if (angular.isDefined(fnIndex)) {
526         repeatFns[fnIndex].deferred.reject('canceled');
527         repeatFns.splice(fnIndex, 1);
528         return true;
529       }
530
531       return false;
532     };
533
534     /**
535      * @ngdoc method
536      * @name $interval#flush
537      * @description
538      *
539      * Runs interval tasks scheduled to be run in the next `millis` milliseconds.
540      *
541      * @param {number=} millis maximum timeout amount to flush up until.
542      *
543      * @return {number} The amount of time moved forward.
544      */
545     $interval.flush = function(millis) {
546       now += millis;
547       while (repeatFns.length && repeatFns[0].nextTime <= now) {
548         var task = repeatFns[0];
549         task.fn();
550         task.nextTime += task.delay;
551         repeatFns.sort(function(a, b) { return a.nextTime - b.nextTime;});
552       }
553       return millis;
554     };
555
556     return $interval;
557   }];
558 };
559
560
561 function jsonStringToDate(string) {
562   // The R_ISO8061_STR regex is never going to fit into the 100 char limit!
563   // eslit-disable-next-line max-len
564   var R_ISO8061_STR = /^(-?\d{4})-?(\d\d)-?(\d\d)(?:T(\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d{3}))?)?)?(Z|([+-])(\d\d):?(\d\d)))?$/;
565
566   var match;
567   if ((match = string.match(R_ISO8061_STR))) {
568     var date = new Date(0),
569         tzHour = 0,
570         tzMin  = 0;
571     if (match[9]) {
572       tzHour = toInt(match[9] + match[10]);
573       tzMin = toInt(match[9] + match[11]);
574     }
575     date.setUTCFullYear(toInt(match[1]), toInt(match[2]) - 1, toInt(match[3]));
576     date.setUTCHours(toInt(match[4] || 0) - tzHour,
577                      toInt(match[5] || 0) - tzMin,
578                      toInt(match[6] || 0),
579                      toInt(match[7] || 0));
580     return date;
581   }
582   return string;
583 }
584
585 function toInt(str) {
586   return parseInt(str, 10);
587 }
588
589 function padNumberInMock(num, digits, trim) {
590   var neg = '';
591   if (num < 0) {
592     neg =  '-';
593     num = -num;
594   }
595   num = '' + num;
596   while (num.length < digits) num = '0' + num;
597   if (trim) {
598     num = num.substr(num.length - digits);
599   }
600   return neg + num;
601 }
602
603
604 /**
605  * @ngdoc type
606  * @name angular.mock.TzDate
607  * @description
608  *
609  * *NOTE*: this is not an injectable instance, just a globally available mock class of `Date`.
610  *
611  * Mock of the Date type which has its timezone specified via constructor arg.
612  *
613  * The main purpose is to create Date-like instances with timezone fixed to the specified timezone
614  * offset, so that we can test code that depends on local timezone settings without dependency on
615  * the time zone settings of the machine where the code is running.
616  *
617  * @param {number} offset Offset of the *desired* timezone in hours (fractions will be honored)
618  * @param {(number|string)} timestamp Timestamp representing the desired time in *UTC*
619  *
620  * @example
621  * !!!! WARNING !!!!!
622  * This is not a complete Date object so only methods that were implemented can be called safely.
623  * To make matters worse, TzDate instances inherit stuff from Date via a prototype.
624  *
625  * We do our best to intercept calls to "unimplemented" methods, but since the list of methods is
626  * incomplete we might be missing some non-standard methods. This can result in errors like:
627  * "Date.prototype.foo called on incompatible Object".
628  *
629  * ```js
630  * var newYearInBratislava = new TzDate(-1, '2009-12-31T23:00:00Z');
631  * newYearInBratislava.getTimezoneOffset() => -60;
632  * newYearInBratislava.getFullYear() => 2010;
633  * newYearInBratislava.getMonth() => 0;
634  * newYearInBratislava.getDate() => 1;
635  * newYearInBratislava.getHours() => 0;
636  * newYearInBratislava.getMinutes() => 0;
637  * newYearInBratislava.getSeconds() => 0;
638  * ```
639  *
640  */
641 angular.mock.TzDate = function(offset, timestamp) {
642   var self = new Date(0);
643   if (angular.isString(timestamp)) {
644     var tsStr = timestamp;
645
646     self.origDate = jsonStringToDate(timestamp);
647
648     timestamp = self.origDate.getTime();
649     if (isNaN(timestamp)) {
650       // eslint-disable-next-line no-throw-literal
651       throw {
652         name: 'Illegal Argument',
653         message: 'Arg \'' + tsStr + '\' passed into TzDate constructor is not a valid date string'
654       };
655     }
656   } else {
657     self.origDate = new Date(timestamp);
658   }
659
660   var localOffset = new Date(timestamp).getTimezoneOffset();
661   self.offsetDiff = localOffset * 60 * 1000 - offset * 1000 * 60 * 60;
662   self.date = new Date(timestamp + self.offsetDiff);
663
664   self.getTime = function() {
665     return self.date.getTime() - self.offsetDiff;
666   };
667
668   self.toLocaleDateString = function() {
669     return self.date.toLocaleDateString();
670   };
671
672   self.getFullYear = function() {
673     return self.date.getFullYear();
674   };
675
676   self.getMonth = function() {
677     return self.date.getMonth();
678   };
679
680   self.getDate = function() {
681     return self.date.getDate();
682   };
683
684   self.getHours = function() {
685     return self.date.getHours();
686   };
687
688   self.getMinutes = function() {
689     return self.date.getMinutes();
690   };
691
692   self.getSeconds = function() {
693     return self.date.getSeconds();
694   };
695
696   self.getMilliseconds = function() {
697     return self.date.getMilliseconds();
698   };
699
700   self.getTimezoneOffset = function() {
701     return offset * 60;
702   };
703
704   self.getUTCFullYear = function() {
705     return self.origDate.getUTCFullYear();
706   };
707
708   self.getUTCMonth = function() {
709     return self.origDate.getUTCMonth();
710   };
711
712   self.getUTCDate = function() {
713     return self.origDate.getUTCDate();
714   };
715
716   self.getUTCHours = function() {
717     return self.origDate.getUTCHours();
718   };
719
720   self.getUTCMinutes = function() {
721     return self.origDate.getUTCMinutes();
722   };
723
724   self.getUTCSeconds = function() {
725     return self.origDate.getUTCSeconds();
726   };
727
728   self.getUTCMilliseconds = function() {
729     return self.origDate.getUTCMilliseconds();
730   };
731
732   self.getDay = function() {
733     return self.date.getDay();
734   };
735
736   // provide this method only on browsers that already have it
737   if (self.toISOString) {
738     self.toISOString = function() {
739       return padNumberInMock(self.origDate.getUTCFullYear(), 4) + '-' +
740             padNumberInMock(self.origDate.getUTCMonth() + 1, 2) + '-' +
741             padNumberInMock(self.origDate.getUTCDate(), 2) + 'T' +
742             padNumberInMock(self.origDate.getUTCHours(), 2) + ':' +
743             padNumberInMock(self.origDate.getUTCMinutes(), 2) + ':' +
744             padNumberInMock(self.origDate.getUTCSeconds(), 2) + '.' +
745             padNumberInMock(self.origDate.getUTCMilliseconds(), 3) + 'Z';
746     };
747   }
748
749   //hide all methods not implemented in this mock that the Date prototype exposes
750   var unimplementedMethods = ['getUTCDay',
751       'getYear', 'setDate', 'setFullYear', 'setHours', 'setMilliseconds',
752       'setMinutes', 'setMonth', 'setSeconds', 'setTime', 'setUTCDate', 'setUTCFullYear',
753       'setUTCHours', 'setUTCMilliseconds', 'setUTCMinutes', 'setUTCMonth', 'setUTCSeconds',
754       'setYear', 'toDateString', 'toGMTString', 'toJSON', 'toLocaleFormat', 'toLocaleString',
755       'toLocaleTimeString', 'toSource', 'toString', 'toTimeString', 'toUTCString', 'valueOf'];
756
757   angular.forEach(unimplementedMethods, function(methodName) {
758     self[methodName] = function() {
759       throw new Error('Method \'' + methodName + '\' is not implemented in the TzDate mock');
760     };
761   });
762
763   return self;
764 };
765
766 //make "tzDateInstance instanceof Date" return true
767 angular.mock.TzDate.prototype = Date.prototype;
768
769
770 /**
771  * @ngdoc service
772  * @name $animate
773  *
774  * @description
775  * Mock implementation of the {@link ng.$animate `$animate`} service. Exposes two additional methods
776  * for testing animations.
777  *
778  * You need to require the `ngAnimateMock` module in your test suite for instance `beforeEach(module('ngAnimateMock'))`
779  */
780 angular.mock.animate = angular.module('ngAnimateMock', ['ng'])
781
782   .config(['$provide', function($provide) {
783
784     $provide.factory('$$forceReflow', function() {
785       function reflowFn() {
786         reflowFn.totalReflows++;
787       }
788       reflowFn.totalReflows = 0;
789       return reflowFn;
790     });
791
792     $provide.factory('$$animateAsyncRun', function() {
793       var queue = [];
794       var queueFn = function() {
795         return function(fn) {
796           queue.push(fn);
797         };
798       };
799       queueFn.flush = function() {
800         if (queue.length === 0) return false;
801
802         for (var i = 0; i < queue.length; i++) {
803           queue[i]();
804         }
805         queue = [];
806
807         return true;
808       };
809       return queueFn;
810     });
811
812     $provide.decorator('$$animateJs', ['$delegate', function($delegate) {
813       var runners = [];
814
815       var animateJsConstructor = function() {
816         var animator = $delegate.apply($delegate, arguments);
817         // If no javascript animation is found, animator is undefined
818         if (animator) {
819           runners.push(animator);
820         }
821         return animator;
822       };
823
824       animateJsConstructor.$closeAndFlush = function() {
825         runners.forEach(function(runner) {
826           runner.end();
827         });
828         runners = [];
829       };
830
831       return animateJsConstructor;
832     }]);
833
834     $provide.decorator('$animateCss', ['$delegate', function($delegate) {
835       var runners = [];
836
837       var animateCssConstructor = function(element, options) {
838         var animator = $delegate(element, options);
839         runners.push(animator);
840         return animator;
841       };
842
843       animateCssConstructor.$closeAndFlush = function() {
844         runners.forEach(function(runner) {
845           runner.end();
846         });
847         runners = [];
848       };
849
850       return animateCssConstructor;
851     }]);
852
853     $provide.decorator('$animate', ['$delegate', '$timeout', '$browser', '$$rAF', '$animateCss', '$$animateJs',
854                                     '$$forceReflow', '$$animateAsyncRun', '$rootScope',
855                             function($delegate,   $timeout,   $browser,   $$rAF,   $animateCss,   $$animateJs,
856                                      $$forceReflow,   $$animateAsyncRun,  $rootScope) {
857       var animate = {
858         queue: [],
859         cancel: $delegate.cancel,
860         on: $delegate.on,
861         off: $delegate.off,
862         pin: $delegate.pin,
863         get reflows() {
864           return $$forceReflow.totalReflows;
865         },
866         enabled: $delegate.enabled,
867         /**
868          * @ngdoc method
869          * @name $animate#closeAndFlush
870          * @description
871          *
872          * This method will close all pending animations (both {@link ngAnimate#javascript-based-animations Javascript}
873          * and {@link ngAnimate.$animateCss CSS}) and it will also flush any remaining animation frames and/or callbacks.
874          */
875         closeAndFlush: function() {
876           // we allow the flush command to swallow the errors
877           // because depending on whether CSS or JS animations are
878           // used, there may not be a RAF flush. The primary flush
879           // at the end of this function must throw an exception
880           // because it will track if there were pending animations
881           this.flush(true);
882           $animateCss.$closeAndFlush();
883           $$animateJs.$closeAndFlush();
884           this.flush();
885         },
886         /**
887          * @ngdoc method
888          * @name $animate#flush
889          * @description
890          *
891          * This method is used to flush the pending callbacks and animation frames to either start
892          * an animation or conclude an animation. Note that this will not actually close an
893          * actively running animation (see {@link ngMock.$animate#closeAndFlush `closeAndFlush()`} for that).
894          */
895         flush: function(hideErrors) {
896           $rootScope.$digest();
897
898           var doNextRun, somethingFlushed = false;
899           do {
900             doNextRun = false;
901
902             if ($$rAF.queue.length) {
903               $$rAF.flush();
904               doNextRun = somethingFlushed = true;
905             }
906
907             if ($$animateAsyncRun.flush()) {
908               doNextRun = somethingFlushed = true;
909             }
910           } while (doNextRun);
911
912           if (!somethingFlushed && !hideErrors) {
913             throw new Error('No pending animations ready to be closed or flushed');
914           }
915
916           $rootScope.$digest();
917         }
918       };
919
920       angular.forEach(
921         ['animate','enter','leave','move','addClass','removeClass','setClass'], function(method) {
922         animate[method] = function() {
923           animate.queue.push({
924             event: method,
925             element: arguments[0],
926             options: arguments[arguments.length - 1],
927             args: arguments
928           });
929           return $delegate[method].apply($delegate, arguments);
930         };
931       });
932
933       return animate;
934     }]);
935
936   }]);
937
938
939 /**
940  * @ngdoc function
941  * @name angular.mock.dump
942  * @description
943  *
944  * *NOTE*: This is not an injectable instance, just a globally available function.
945  *
946  * Method for serializing common angular objects (scope, elements, etc..) into strings.
947  * It is useful for logging objects to the console when debugging.
948  *
949  * @param {*} object - any object to turn into string.
950  * @return {string} a serialized string of the argument
951  */
952 angular.mock.dump = function(object) {
953   return serialize(object);
954
955   function serialize(object) {
956     var out;
957
958     if (angular.isElement(object)) {
959       object = angular.element(object);
960       out = angular.element('<div></div>');
961       angular.forEach(object, function(element) {
962         out.append(angular.element(element).clone());
963       });
964       out = out.html();
965     } else if (angular.isArray(object)) {
966       out = [];
967       angular.forEach(object, function(o) {
968         out.push(serialize(o));
969       });
970       out = '[ ' + out.join(', ') + ' ]';
971     } else if (angular.isObject(object)) {
972       if (angular.isFunction(object.$eval) && angular.isFunction(object.$apply)) {
973         out = serializeScope(object);
974       } else if (object instanceof Error) {
975         out = object.stack || ('' + object.name + ': ' + object.message);
976       } else {
977         // TODO(i): this prevents methods being logged,
978         // we should have a better way to serialize objects
979         out = angular.toJson(object, true);
980       }
981     } else {
982       out = String(object);
983     }
984
985     return out;
986   }
987
988   function serializeScope(scope, offset) {
989     offset = offset ||  '  ';
990     var log = [offset + 'Scope(' + scope.$id + '): {'];
991     for (var key in scope) {
992       if (Object.prototype.hasOwnProperty.call(scope, key) && !key.match(/^(\$|this)/)) {
993         log.push('  ' + key + ': ' + angular.toJson(scope[key]));
994       }
995     }
996     var child = scope.$$childHead;
997     while (child) {
998       log.push(serializeScope(child, offset + '  '));
999       child = child.$$nextSibling;
1000     }
1001     log.push('}');
1002     return log.join('\n' + offset);
1003   }
1004 };
1005
1006 /**
1007  * @ngdoc service
1008  * @name $httpBackend
1009  * @description
1010  * Fake HTTP backend implementation suitable for unit testing applications that use the
1011  * {@link ng.$http $http service}.
1012  *
1013  * <div class="alert alert-info">
1014  * **Note**: For fake HTTP backend implementation suitable for end-to-end testing or backend-less
1015  * development please see {@link ngMockE2E.$httpBackend e2e $httpBackend mock}.
1016  * </div>
1017  *
1018  * During unit testing, we want our unit tests to run quickly and have no external dependencies so
1019  * we don’t want to send [XHR](https://developer.mozilla.org/en/xmlhttprequest) or
1020  * [JSONP](http://en.wikipedia.org/wiki/JSONP) requests to a real server. All we really need is
1021  * to verify whether a certain request has been sent or not, or alternatively just let the
1022  * application make requests, respond with pre-trained responses and assert that the end result is
1023  * what we expect it to be.
1024  *
1025  * This mock implementation can be used to respond with static or dynamic responses via the
1026  * `expect` and `when` apis and their shortcuts (`expectGET`, `whenPOST`, etc).
1027  *
1028  * When an Angular application needs some data from a server, it calls the $http service, which
1029  * sends the request to a real server using $httpBackend service. With dependency injection, it is
1030  * easy to inject $httpBackend mock (which has the same API as $httpBackend) and use it to verify
1031  * the requests and respond with some testing data without sending a request to a real server.
1032  *
1033  * There are two ways to specify what test data should be returned as http responses by the mock
1034  * backend when the code under test makes http requests:
1035  *
1036  * - `$httpBackend.expect` - specifies a request expectation
1037  * - `$httpBackend.when` - specifies a backend definition
1038  *
1039  *
1040  * ## Request Expectations vs Backend Definitions
1041  *
1042  * Request expectations provide a way to make assertions about requests made by the application and
1043  * to define responses for those requests. The test will fail if the expected requests are not made
1044  * or they are made in the wrong order.
1045  *
1046  * Backend definitions allow you to define a fake backend for your application which doesn't assert
1047  * if a particular request was made or not, it just returns a trained response if a request is made.
1048  * The test will pass whether or not the request gets made during testing.
1049  *
1050  *
1051  * <table class="table">
1052  *   <tr><th width="220px"></th><th>Request expectations</th><th>Backend definitions</th></tr>
1053  *   <tr>
1054  *     <th>Syntax</th>
1055  *     <td>.expect(...).respond(...)</td>
1056  *     <td>.when(...).respond(...)</td>
1057  *   </tr>
1058  *   <tr>
1059  *     <th>Typical usage</th>
1060  *     <td>strict unit tests</td>
1061  *     <td>loose (black-box) unit testing</td>
1062  *   </tr>
1063  *   <tr>
1064  *     <th>Fulfills multiple requests</th>
1065  *     <td>NO</td>
1066  *     <td>YES</td>
1067  *   </tr>
1068  *   <tr>
1069  *     <th>Order of requests matters</th>
1070  *     <td>YES</td>
1071  *     <td>NO</td>
1072  *   </tr>
1073  *   <tr>
1074  *     <th>Request required</th>
1075  *     <td>YES</td>
1076  *     <td>NO</td>
1077  *   </tr>
1078  *   <tr>
1079  *     <th>Response required</th>
1080  *     <td>optional (see below)</td>
1081  *     <td>YES</td>
1082  *   </tr>
1083  * </table>
1084  *
1085  * In cases where both backend definitions and request expectations are specified during unit
1086  * testing, the request expectations are evaluated first.
1087  *
1088  * If a request expectation has no response specified, the algorithm will search your backend
1089  * definitions for an appropriate response.
1090  *
1091  * If a request didn't match any expectation or if the expectation doesn't have the response
1092  * defined, the backend definitions are evaluated in sequential order to see if any of them match
1093  * the request. The response from the first matched definition is returned.
1094  *
1095  *
1096  * ## Flushing HTTP requests
1097  *
1098  * The $httpBackend used in production always responds to requests asynchronously. If we preserved
1099  * this behavior in unit testing, we'd have to create async unit tests, which are hard to write,
1100  * to follow and to maintain. But neither can the testing mock respond synchronously; that would
1101  * change the execution of the code under test. For this reason, the mock $httpBackend has a
1102  * `flush()` method, which allows the test to explicitly flush pending requests. This preserves
1103  * the async api of the backend, while allowing the test to execute synchronously.
1104  *
1105  *
1106  * ## Unit testing with mock $httpBackend
1107  * The following code shows how to setup and use the mock backend when unit testing a controller.
1108  * First we create the controller under test:
1109  *
1110   ```js
1111   // The module code
1112   angular
1113     .module('MyApp', [])
1114     .controller('MyController', MyController);
1115
1116   // The controller code
1117   function MyController($scope, $http) {
1118     var authToken;
1119
1120     $http.get('/auth.py').then(function(response) {
1121       authToken = response.headers('A-Token');
1122       $scope.user = response.data;
1123     });
1124
1125     $scope.saveMessage = function(message) {
1126       var headers = { 'Authorization': authToken };
1127       $scope.status = 'Saving...';
1128
1129       $http.post('/add-msg.py', message, { headers: headers } ).then(function(response) {
1130         $scope.status = '';
1131       })['catch'](function() {
1132         $scope.status = 'Failed...';
1133       });
1134     };
1135   }
1136   ```
1137  *
1138  * Now we setup the mock backend and create the test specs:
1139  *
1140   ```js
1141     // testing controller
1142     describe('MyController', function() {
1143        var $httpBackend, $rootScope, createController, authRequestHandler;
1144
1145        // Set up the module
1146        beforeEach(module('MyApp'));
1147
1148        beforeEach(inject(function($injector) {
1149          // Set up the mock http service responses
1150          $httpBackend = $injector.get('$httpBackend');
1151          // backend definition common for all tests
1152          authRequestHandler = $httpBackend.when('GET', '/auth.py')
1153                                 .respond({userId: 'userX'}, {'A-Token': 'xxx'});
1154
1155          // Get hold of a scope (i.e. the root scope)
1156          $rootScope = $injector.get('$rootScope');
1157          // The $controller service is used to create instances of controllers
1158          var $controller = $injector.get('$controller');
1159
1160          createController = function() {
1161            return $controller('MyController', {'$scope' : $rootScope });
1162          };
1163        }));
1164
1165
1166        afterEach(function() {
1167          $httpBackend.verifyNoOutstandingExpectation();
1168          $httpBackend.verifyNoOutstandingRequest();
1169        });
1170
1171
1172        it('should fetch authentication token', function() {
1173          $httpBackend.expectGET('/auth.py');
1174          var controller = createController();
1175          $httpBackend.flush();
1176        });
1177
1178
1179        it('should fail authentication', function() {
1180
1181          // Notice how you can change the response even after it was set
1182          authRequestHandler.respond(401, '');
1183
1184          $httpBackend.expectGET('/auth.py');
1185          var controller = createController();
1186          $httpBackend.flush();
1187          expect($rootScope.status).toBe('Failed...');
1188        });
1189
1190
1191        it('should send msg to server', function() {
1192          var controller = createController();
1193          $httpBackend.flush();
1194
1195          // now you don’t care about the authentication, but
1196          // the controller will still send the request and
1197          // $httpBackend will respond without you having to
1198          // specify the expectation and response for this request
1199
1200          $httpBackend.expectPOST('/add-msg.py', 'message content').respond(201, '');
1201          $rootScope.saveMessage('message content');
1202          expect($rootScope.status).toBe('Saving...');
1203          $httpBackend.flush();
1204          expect($rootScope.status).toBe('');
1205        });
1206
1207
1208        it('should send auth header', function() {
1209          var controller = createController();
1210          $httpBackend.flush();
1211
1212          $httpBackend.expectPOST('/add-msg.py', undefined, function(headers) {
1213            // check if the header was sent, if it wasn't the expectation won't
1214            // match the request and the test will fail
1215            return headers['Authorization'] === 'xxx';
1216          }).respond(201, '');
1217
1218          $rootScope.saveMessage('whatever');
1219          $httpBackend.flush();
1220        });
1221     });
1222   ```
1223  *
1224  * ## Dynamic responses
1225  *
1226  * You define a response to a request by chaining a call to `respond()` onto a definition or expectation.
1227  * If you provide a **callback** as the first parameter to `respond(callback)` then you can dynamically generate
1228  * a response based on the properties of the request.
1229  *
1230  * The `callback` function should be of the form `function(method, url, data, headers, params)`.
1231  *
1232  * ### Query parameters
1233  *
1234  * By default, query parameters on request URLs are parsed into the `params` object. So a request URL
1235  * of `/list?q=searchstr&orderby=-name` would set `params` to be `{q: 'searchstr', orderby: '-name'}`.
1236  *
1237  * ### Regex parameter matching
1238  *
1239  * If an expectation or definition uses a **regex** to match the URL, you can provide an array of **keys** via a
1240  * `params` argument. The index of each **key** in the array will match the index of a **group** in the
1241  * **regex**.
1242  *
1243  * The `params` object in the **callback** will now have properties with these keys, which hold the value of the
1244  * corresponding **group** in the **regex**.
1245  *
1246  * This also applies to the `when` and `expect` shortcut methods.
1247  *
1248  *
1249  * ```js
1250  *   $httpBackend.expect('GET', /\/user\/(.+)/, undefined, undefined, ['id'])
1251  *     .respond(function(method, url, data, headers, params) {
1252  *       // for requested url of '/user/1234' params is {id: '1234'}
1253  *     });
1254  *
1255  *   $httpBackend.whenPATCH(/\/user\/(.+)\/article\/(.+)/, undefined, undefined, ['user', 'article'])
1256  *     .respond(function(method, url, data, headers, params) {
1257  *       // for url of '/user/1234/article/567' params is {user: '1234', article: '567'}
1258  *     });
1259  * ```
1260  *
1261  * ## Matching route requests
1262  *
1263  * For extra convenience, `whenRoute` and `expectRoute` shortcuts are available. These methods offer colon
1264  * delimited matching of the url path, ignoring the query string. This allows declarations
1265  * similar to how application routes are configured with `$routeProvider`. Because these methods convert
1266  * the definition url to regex, declaration order is important. Combined with query parameter parsing,
1267  * the following is possible:
1268  *
1269   ```js
1270     $httpBackend.whenRoute('GET', '/users/:id')
1271       .respond(function(method, url, data, headers, params) {
1272         return [200, MockUserList[Number(params.id)]];
1273       });
1274
1275     $httpBackend.whenRoute('GET', '/users')
1276       .respond(function(method, url, data, headers, params) {
1277         var userList = angular.copy(MockUserList),
1278           defaultSort = 'lastName',
1279           count, pages, isPrevious, isNext;
1280
1281         // paged api response '/v1/users?page=2'
1282         params.page = Number(params.page) || 1;
1283
1284         // query for last names '/v1/users?q=Archer'
1285         if (params.q) {
1286           userList = $filter('filter')({lastName: params.q});
1287         }
1288
1289         pages = Math.ceil(userList.length / pagingLength);
1290         isPrevious = params.page > 1;
1291         isNext = params.page < pages;
1292
1293         return [200, {
1294           count:    userList.length,
1295           previous: isPrevious,
1296           next:     isNext,
1297           // sort field -> '/v1/users?sortBy=firstName'
1298           results:  $filter('orderBy')(userList, params.sortBy || defaultSort)
1299                       .splice((params.page - 1) * pagingLength, pagingLength)
1300         }];
1301       });
1302   ```
1303  */
1304 angular.mock.$HttpBackendProvider = function() {
1305   this.$get = ['$rootScope', '$timeout', createHttpBackendMock];
1306 };
1307
1308 /**
1309  * General factory function for $httpBackend mock.
1310  * Returns instance for unit testing (when no arguments specified):
1311  *   - passing through is disabled
1312  *   - auto flushing is disabled
1313  *
1314  * Returns instance for e2e testing (when `$delegate` and `$browser` specified):
1315  *   - passing through (delegating request to real backend) is enabled
1316  *   - auto flushing is enabled
1317  *
1318  * @param {Object=} $delegate Real $httpBackend instance (allow passing through if specified)
1319  * @param {Object=} $browser Auto-flushing enabled if specified
1320  * @return {Object} Instance of $httpBackend mock
1321  */
1322 function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) {
1323   var definitions = [],
1324       expectations = [],
1325       responses = [],
1326       responsesPush = angular.bind(responses, responses.push),
1327       copy = angular.copy;
1328
1329   function createResponse(status, data, headers, statusText) {
1330     if (angular.isFunction(status)) return status;
1331
1332     return function() {
1333       return angular.isNumber(status)
1334           ? [status, data, headers, statusText]
1335           : [200, status, data, headers];
1336     };
1337   }
1338
1339   // TODO(vojta): change params to: method, url, data, headers, callback
1340   function $httpBackend(method, url, data, callback, headers, timeout, withCredentials, responseType, eventHandlers, uploadEventHandlers) {
1341
1342     var xhr = new MockXhr(),
1343         expectation = expectations[0],
1344         wasExpected = false;
1345
1346     xhr.$$events = eventHandlers;
1347     xhr.upload.$$events = uploadEventHandlers;
1348
1349     function prettyPrint(data) {
1350       return (angular.isString(data) || angular.isFunction(data) || data instanceof RegExp)
1351           ? data
1352           : angular.toJson(data);
1353     }
1354
1355     function wrapResponse(wrapped) {
1356       if (!$browser && timeout) {
1357         if (timeout.then) {
1358           timeout.then(handleTimeout);
1359         } else {
1360           $timeout(handleTimeout, timeout);
1361         }
1362       }
1363
1364       return handleResponse;
1365
1366       function handleResponse() {
1367         var response = wrapped.response(method, url, data, headers, wrapped.params(url));
1368         xhr.$$respHeaders = response[2];
1369         callback(copy(response[0]), copy(response[1]), xhr.getAllResponseHeaders(),
1370                  copy(response[3] || ''));
1371       }
1372
1373       function handleTimeout() {
1374         for (var i = 0, ii = responses.length; i < ii; i++) {
1375           if (responses[i] === handleResponse) {
1376             responses.splice(i, 1);
1377             callback(-1, undefined, '');
1378             break;
1379           }
1380         }
1381       }
1382     }
1383
1384     if (expectation && expectation.match(method, url)) {
1385       if (!expectation.matchData(data)) {
1386         throw new Error('Expected ' + expectation + ' with different data\n' +
1387             'EXPECTED: ' + prettyPrint(expectation.data) + '\nGOT:      ' + data);
1388       }
1389
1390       if (!expectation.matchHeaders(headers)) {
1391         throw new Error('Expected ' + expectation + ' with different headers\n' +
1392                         'EXPECTED: ' + prettyPrint(expectation.headers) + '\nGOT:      ' +
1393                         prettyPrint(headers));
1394       }
1395
1396       expectations.shift();
1397
1398       if (expectation.response) {
1399         responses.push(wrapResponse(expectation));
1400         return;
1401       }
1402       wasExpected = true;
1403     }
1404
1405     var i = -1, definition;
1406     while ((definition = definitions[++i])) {
1407       if (definition.match(method, url, data, headers || {})) {
1408         if (definition.response) {
1409           // if $browser specified, we do auto flush all requests
1410           ($browser ? $browser.defer : responsesPush)(wrapResponse(definition));
1411         } else if (definition.passThrough) {
1412           $delegate(method, url, data, callback, headers, timeout, withCredentials, responseType, eventHandlers, uploadEventHandlers);
1413         } else throw new Error('No response defined !');
1414         return;
1415       }
1416     }
1417     throw wasExpected ?
1418         new Error('No response defined !') :
1419         new Error('Unexpected request: ' + method + ' ' + url + '\n' +
1420                   (expectation ? 'Expected ' + expectation : 'No more request expected'));
1421   }
1422
1423   /**
1424    * @ngdoc method
1425    * @name $httpBackend#when
1426    * @description
1427    * Creates a new backend definition.
1428    *
1429    * @param {string} method HTTP method.
1430    * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
1431    *   and returns true if the url matches the current definition.
1432    * @param {(string|RegExp|function(string))=} data HTTP request body or function that receives
1433    *   data string and returns true if the data is as expected.
1434    * @param {(Object|function(Object))=} headers HTTP headers or function that receives http header
1435    *   object and returns true if the headers match the current definition.
1436    * @param {(Array)=} keys Array of keys to assign to regex matches in request url described above.
1437    * @returns {requestHandler} Returns an object with `respond` method that controls how a matched
1438    *   request is handled. You can save this object for later use and invoke `respond` again in
1439    *   order to change how a matched request is handled.
1440    *
1441    *  - respond â€“
1442    *      ```js
1443    *      {function([status,] data[, headers, statusText])
1444    *      | function(function(method, url, data, headers, params)}
1445    *      ```
1446    *    â€“ The respond method takes a set of static data to be returned or a function that can
1447    *    return an array containing response status (number), response data (Array|Object|string),
1448    *    response headers (Object), and the text for the status (string). The respond method returns
1449    *    the `requestHandler` object for possible overrides.
1450    */
1451   $httpBackend.when = function(method, url, data, headers, keys) {
1452     var definition = new MockHttpExpectation(method, url, data, headers, keys),
1453         chain = {
1454           respond: function(status, data, headers, statusText) {
1455             definition.passThrough = undefined;
1456             definition.response = createResponse(status, data, headers, statusText);
1457             return chain;
1458           }
1459         };
1460
1461     if ($browser) {
1462       chain.passThrough = function() {
1463         definition.response = undefined;
1464         definition.passThrough = true;
1465         return chain;
1466       };
1467     }
1468
1469     definitions.push(definition);
1470     return chain;
1471   };
1472
1473   /**
1474    * @ngdoc method
1475    * @name $httpBackend#whenGET
1476    * @description
1477    * Creates a new backend definition for GET requests. For more info see `when()`.
1478    *
1479    * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
1480    *   and returns true if the url matches the current definition.
1481    * @param {(Object|function(Object))=} headers HTTP headers.
1482    * @param {(Array)=} keys Array of keys to assign to regex matches in request url described above.
1483    * @returns {requestHandler} Returns an object with `respond` method that controls how a matched
1484    * request is handled. You can save this object for later use and invoke `respond` again in
1485    * order to change how a matched request is handled.
1486    */
1487
1488   /**
1489    * @ngdoc method
1490    * @name $httpBackend#whenHEAD
1491    * @description
1492    * Creates a new backend definition for HEAD requests. For more info see `when()`.
1493    *
1494    * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
1495    *   and returns true if the url matches the current definition.
1496    * @param {(Object|function(Object))=} headers HTTP headers.
1497    * @param {(Array)=} keys Array of keys to assign to regex matches in request url described above.
1498    * @returns {requestHandler} Returns an object with `respond` method that controls how a matched
1499    * request is handled. You can save this object for later use and invoke `respond` again in
1500    * order to change how a matched request is handled.
1501    */
1502
1503   /**
1504    * @ngdoc method
1505    * @name $httpBackend#whenDELETE
1506    * @description
1507    * Creates a new backend definition for DELETE requests. For more info see `when()`.
1508    *
1509    * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
1510    *   and returns true if the url matches the current definition.
1511    * @param {(Object|function(Object))=} headers HTTP headers.
1512    * @param {(Array)=} keys Array of keys to assign to regex matches in request url described above.
1513    * @returns {requestHandler} Returns an object with `respond` method that controls how a matched
1514    * request is handled. You can save this object for later use and invoke `respond` again in
1515    * order to change how a matched request is handled.
1516    */
1517
1518   /**
1519    * @ngdoc method
1520    * @name $httpBackend#whenPOST
1521    * @description
1522    * Creates a new backend definition for POST requests. For more info see `when()`.
1523    *
1524    * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
1525    *   and returns true if the url matches the current definition.
1526    * @param {(string|RegExp|function(string))=} data HTTP request body or function that receives
1527    *   data string and returns true if the data is as expected.
1528    * @param {(Object|function(Object))=} headers HTTP headers.
1529    * @param {(Array)=} keys Array of keys to assign to regex matches in request url described above.
1530    * @returns {requestHandler} Returns an object with `respond` method that controls how a matched
1531    * request is handled. You can save this object for later use and invoke `respond` again in
1532    * order to change how a matched request is handled.
1533    */
1534
1535   /**
1536    * @ngdoc method
1537    * @name $httpBackend#whenPUT
1538    * @description
1539    * Creates a new backend definition for PUT requests.  For more info see `when()`.
1540    *
1541    * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
1542    *   and returns true if the url matches the current definition.
1543    * @param {(string|RegExp|function(string))=} data HTTP request body or function that receives
1544    *   data string and returns true if the data is as expected.
1545    * @param {(Object|function(Object))=} headers HTTP headers.
1546    * @param {(Array)=} keys Array of keys to assign to regex matches in request url described above.
1547    * @returns {requestHandler} Returns an object with `respond` method that controls how a matched
1548    * request is handled. You can save this object for later use and invoke `respond` again in
1549    * order to change how a matched request is handled.
1550    */
1551
1552   /**
1553    * @ngdoc method
1554    * @name $httpBackend#whenJSONP
1555    * @description
1556    * Creates a new backend definition for JSONP requests. For more info see `when()`.
1557    *
1558    * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
1559    *   and returns true if the url matches the current definition.
1560    * @param {(Array)=} keys Array of keys to assign to regex matches in request url described above.
1561    * @returns {requestHandler} Returns an object with `respond` method that controls how a matched
1562    * request is handled. You can save this object for later use and invoke `respond` again in
1563    * order to change how a matched request is handled.
1564    */
1565   createShortMethods('when');
1566
1567   /**
1568    * @ngdoc method
1569    * @name $httpBackend#whenRoute
1570    * @description
1571    * Creates a new backend definition that compares only with the requested route.
1572    *
1573    * @param {string} method HTTP method.
1574    * @param {string} url HTTP url string that supports colon param matching.
1575    * @returns {requestHandler} Returns an object with `respond` method that controls how a matched
1576    * request is handled. You can save this object for later use and invoke `respond` again in
1577    * order to change how a matched request is handled. See #when for more info.
1578    */
1579   $httpBackend.whenRoute = function(method, url) {
1580     var pathObj = parseRoute(url);
1581     return $httpBackend.when(method, pathObj.regexp, undefined, undefined, pathObj.keys);
1582   };
1583
1584   function parseRoute(url) {
1585     var ret = {
1586       regexp: url
1587     },
1588     keys = ret.keys = [];
1589
1590     if (!url || !angular.isString(url)) return ret;
1591
1592     url = url
1593       .replace(/([().])/g, '\\$1')
1594       .replace(/(\/)?:(\w+)([?*])?/g, function(_, slash, key, option) {
1595         var optional = option === '?' ? option : null;
1596         var star = option === '*' ? option : null;
1597         keys.push({ name: key, optional: !!optional });
1598         slash = slash || '';
1599         return ''
1600           + (optional ? '' : slash)
1601           + '(?:'
1602           + (optional ? slash : '')
1603           + (star && '(.+?)' || '([^/]+)')
1604           + (optional || '')
1605           + ')'
1606           + (optional || '');
1607       })
1608       .replace(/([/$*])/g, '\\$1');
1609
1610     ret.regexp = new RegExp('^' + url, 'i');
1611     return ret;
1612   }
1613
1614   /**
1615    * @ngdoc method
1616    * @name $httpBackend#expect
1617    * @description
1618    * Creates a new request expectation.
1619    *
1620    * @param {string} method HTTP method.
1621    * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
1622    *   and returns true if the url matches the current definition.
1623    * @param {(string|RegExp|function(string)|Object)=} data HTTP request body or function that
1624    *  receives data string and returns true if the data is as expected, or Object if request body
1625    *  is in JSON format.
1626    * @param {(Object|function(Object))=} headers HTTP headers or function that receives http header
1627    *   object and returns true if the headers match the current expectation.
1628    * @param {(Array)=} keys Array of keys to assign to regex matches in request url described above.
1629    * @returns {requestHandler} Returns an object with `respond` method that controls how a matched
1630    *  request is handled. You can save this object for later use and invoke `respond` again in
1631    *  order to change how a matched request is handled.
1632    *
1633    *  - respond â€“
1634    *    ```
1635    *    { function([status,] data[, headers, statusText])
1636    *    | function(function(method, url, data, headers, params)}
1637    *    ```
1638    *    â€“ The respond method takes a set of static data to be returned or a function that can
1639    *    return an array containing response status (number), response data (Array|Object|string),
1640    *    response headers (Object), and the text for the status (string). The respond method returns
1641    *    the `requestHandler` object for possible overrides.
1642    */
1643   $httpBackend.expect = function(method, url, data, headers, keys) {
1644     var expectation = new MockHttpExpectation(method, url, data, headers, keys),
1645         chain = {
1646           respond: function(status, data, headers, statusText) {
1647             expectation.response = createResponse(status, data, headers, statusText);
1648             return chain;
1649           }
1650         };
1651
1652     expectations.push(expectation);
1653     return chain;
1654   };
1655
1656   /**
1657    * @ngdoc method
1658    * @name $httpBackend#expectGET
1659    * @description
1660    * Creates a new request expectation for GET requests. For more info see `expect()`.
1661    *
1662    * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
1663    *   and returns true if the url matches the current definition.
1664    * @param {Object=} headers HTTP headers.
1665    * @param {(Array)=} keys Array of keys to assign to regex matches in request url described above.
1666    * @returns {requestHandler} Returns an object with `respond` method that controls how a matched
1667    * request is handled. You can save this object for later use and invoke `respond` again in
1668    * order to change how a matched request is handled. See #expect for more info.
1669    */
1670
1671   /**
1672    * @ngdoc method
1673    * @name $httpBackend#expectHEAD
1674    * @description
1675    * Creates a new request expectation for HEAD requests. For more info see `expect()`.
1676    *
1677    * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
1678    *   and returns true if the url matches the current definition.
1679    * @param {Object=} headers HTTP headers.
1680    * @param {(Array)=} keys Array of keys to assign to regex matches in request url described above.
1681    * @returns {requestHandler} Returns an object with `respond` method that controls how a matched
1682    *   request is handled. You can save this object for later use and invoke `respond` again in
1683    *   order to change how a matched request is handled.
1684    */
1685
1686   /**
1687    * @ngdoc method
1688    * @name $httpBackend#expectDELETE
1689    * @description
1690    * Creates a new request expectation for DELETE requests. For more info see `expect()`.
1691    *
1692    * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
1693    *   and returns true if the url matches the current definition.
1694    * @param {Object=} headers HTTP headers.
1695    * @param {(Array)=} keys Array of keys to assign to regex matches in request url described above.
1696    * @returns {requestHandler} Returns an object with `respond` method that controls how a matched
1697    *   request is handled. You can save this object for later use and invoke `respond` again in
1698    *   order to change how a matched request is handled.
1699    */
1700
1701   /**
1702    * @ngdoc method
1703    * @name $httpBackend#expectPOST
1704    * @description
1705    * Creates a new request expectation for POST requests. For more info see `expect()`.
1706    *
1707    * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
1708    *   and returns true if the url matches the current definition.
1709    * @param {(string|RegExp|function(string)|Object)=} data HTTP request body or function that
1710    *  receives data string and returns true if the data is as expected, or Object if request body
1711    *  is in JSON format.
1712    * @param {Object=} headers HTTP headers.
1713    * @param {(Array)=} keys Array of keys to assign to regex matches in request url described above.
1714    * @returns {requestHandler} Returns an object with `respond` method that controls how a matched
1715    *   request is handled. You can save this object for later use and invoke `respond` again in
1716    *   order to change how a matched request is handled.
1717    */
1718
1719   /**
1720    * @ngdoc method
1721    * @name $httpBackend#expectPUT
1722    * @description
1723    * Creates a new request expectation for PUT requests. For more info see `expect()`.
1724    *
1725    * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
1726    *   and returns true if the url matches the current definition.
1727    * @param {(string|RegExp|function(string)|Object)=} data HTTP request body or function that
1728    *  receives data string and returns true if the data is as expected, or Object if request body
1729    *  is in JSON format.
1730    * @param {Object=} headers HTTP headers.
1731    * @param {(Array)=} keys Array of keys to assign to regex matches in request url described above.
1732    * @returns {requestHandler} Returns an object with `respond` method that controls how a matched
1733    *   request is handled. You can save this object for later use and invoke `respond` again in
1734    *   order to change how a matched request is handled.
1735    */
1736
1737   /**
1738    * @ngdoc method
1739    * @name $httpBackend#expectPATCH
1740    * @description
1741    * Creates a new request expectation for PATCH requests. For more info see `expect()`.
1742    *
1743    * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
1744    *   and returns true if the url matches the current definition.
1745    * @param {(string|RegExp|function(string)|Object)=} data HTTP request body or function that
1746    *  receives data string and returns true if the data is as expected, or Object if request body
1747    *  is in JSON format.
1748    * @param {Object=} headers HTTP headers.
1749    * @param {(Array)=} keys Array of keys to assign to regex matches in request url described above.
1750    * @returns {requestHandler} Returns an object with `respond` method that controls how a matched
1751    *   request is handled. You can save this object for later use and invoke `respond` again in
1752    *   order to change how a matched request is handled.
1753    */
1754
1755   /**
1756    * @ngdoc method
1757    * @name $httpBackend#expectJSONP
1758    * @description
1759    * Creates a new request expectation for JSONP requests. For more info see `expect()`.
1760    *
1761    * @param {string|RegExp|function(string)} url HTTP url or function that receives an url
1762    *   and returns true if the url matches the current definition.
1763    * @param {(Array)=} keys Array of keys to assign to regex matches in request url described above.
1764    * @returns {requestHandler} Returns an object with `respond` method that controls how a matched
1765    *   request is handled. You can save this object for later use and invoke `respond` again in
1766    *   order to change how a matched request is handled.
1767    */
1768   createShortMethods('expect');
1769
1770   /**
1771    * @ngdoc method
1772    * @name $httpBackend#expectRoute
1773    * @description
1774    * Creates a new request expectation that compares only with the requested route.
1775    *
1776    * @param {string} method HTTP method.
1777    * @param {string} url HTTP url string that supports colon param matching.
1778    * @returns {requestHandler} Returns an object with `respond` method that controls how a matched
1779    * request is handled. You can save this object for later use and invoke `respond` again in
1780    * order to change how a matched request is handled. See #expect for more info.
1781    */
1782   $httpBackend.expectRoute = function(method, url) {
1783     var pathObj = parseRoute(url);
1784     return $httpBackend.expect(method, pathObj.regexp, undefined, undefined, pathObj.keys);
1785   };
1786
1787
1788   /**
1789    * @ngdoc method
1790    * @name $httpBackend#flush
1791    * @description
1792    * Flushes pending requests using the trained responses. Requests are flushed in the order they
1793    * were made, but it is also possible to skip one or more requests (for example to have them
1794    * flushed later). This is useful for simulating scenarios where responses arrive from the server
1795    * in any order.
1796    *
1797    * If there are no pending requests to flush when the method is called, an exception is thrown (as
1798    * this is typically a sign of programming error).
1799    *
1800    * @param {number=} count - Number of responses to flush. If undefined/null, all pending requests
1801    *     (starting after `skip`) will be flushed.
1802    * @param {number=} [skip=0] - Number of pending requests to skip. For example, a value of `5`
1803    *     would skip the first 5 pending requests and start flushing from the 6th onwards.
1804    */
1805   $httpBackend.flush = function(count, skip, digest) {
1806     if (digest !== false) $rootScope.$digest();
1807
1808     skip = skip || 0;
1809     if (skip >= responses.length) throw new Error('No pending request to flush !');
1810
1811     if (angular.isDefined(count) && count !== null) {
1812       while (count--) {
1813         var part = responses.splice(skip, 1);
1814         if (!part.length) throw new Error('No more pending request to flush !');
1815         part[0]();
1816       }
1817     } else {
1818       while (responses.length > skip) {
1819         responses.splice(skip, 1)[0]();
1820       }
1821     }
1822     $httpBackend.verifyNoOutstandingExpectation(digest);
1823   };
1824
1825
1826   /**
1827    * @ngdoc method
1828    * @name $httpBackend#verifyNoOutstandingExpectation
1829    * @description
1830    * Verifies that all of the requests defined via the `expect` api were made. If any of the
1831    * requests were not made, verifyNoOutstandingExpectation throws an exception.
1832    *
1833    * Typically, you would call this method following each test case that asserts requests using an
1834    * "afterEach" clause.
1835    *
1836    * ```js
1837    *   afterEach($httpBackend.verifyNoOutstandingExpectation);
1838    * ```
1839    */
1840   $httpBackend.verifyNoOutstandingExpectation = function(digest) {
1841     if (digest !== false) $rootScope.$digest();
1842     if (expectations.length) {
1843       throw new Error('Unsatisfied requests: ' + expectations.join(', '));
1844     }
1845   };
1846
1847
1848   /**
1849    * @ngdoc method
1850    * @name $httpBackend#verifyNoOutstandingRequest
1851    * @description
1852    * Verifies that there are no outstanding requests that need to be flushed.
1853    *
1854    * Typically, you would call this method following each test case that asserts requests using an
1855    * "afterEach" clause.
1856    *
1857    * ```js
1858    *   afterEach($httpBackend.verifyNoOutstandingRequest);
1859    * ```
1860    */
1861   $httpBackend.verifyNoOutstandingRequest = function() {
1862     if (responses.length) {
1863       throw new Error('Unflushed requests: ' + responses.length);
1864     }
1865   };
1866
1867
1868   /**
1869    * @ngdoc method
1870    * @name $httpBackend#resetExpectations
1871    * @description
1872    * Resets all request expectations, but preserves all backend definitions. Typically, you would
1873    * call resetExpectations during a multiple-phase test when you want to reuse the same instance of
1874    * $httpBackend mock.
1875    */
1876   $httpBackend.resetExpectations = function() {
1877     expectations.length = 0;
1878     responses.length = 0;
1879   };
1880
1881   return $httpBackend;
1882
1883
1884   function createShortMethods(prefix) {
1885     angular.forEach(['GET', 'DELETE', 'JSONP', 'HEAD'], function(method) {
1886      $httpBackend[prefix + method] = function(url, headers, keys) {
1887        return $httpBackend[prefix](method, url, undefined, headers, keys);
1888      };
1889     });
1890
1891     angular.forEach(['PUT', 'POST', 'PATCH'], function(method) {
1892       $httpBackend[prefix + method] = function(url, data, headers, keys) {
1893         return $httpBackend[prefix](method, url, data, headers, keys);
1894       };
1895     });
1896   }
1897 }
1898
1899 function MockHttpExpectation(method, url, data, headers, keys) {
1900
1901   function getUrlParams(u) {
1902     var params = u.slice(u.indexOf('?') + 1).split('&');
1903     return params.sort();
1904   }
1905
1906   function compareUrl(u) {
1907     return (url.slice(0, url.indexOf('?')) === u.slice(0, u.indexOf('?')) &&
1908       getUrlParams(url).join() === getUrlParams(u).join());
1909   }
1910
1911   this.data = data;
1912   this.headers = headers;
1913
1914   this.match = function(m, u, d, h) {
1915     if (method !== m) return false;
1916     if (!this.matchUrl(u)) return false;
1917     if (angular.isDefined(d) && !this.matchData(d)) return false;
1918     if (angular.isDefined(h) && !this.matchHeaders(h)) return false;
1919     return true;
1920   };
1921
1922   this.matchUrl = function(u) {
1923     if (!url) return true;
1924     if (angular.isFunction(url.test)) return url.test(u);
1925     if (angular.isFunction(url)) return url(u);
1926     return (url === u || compareUrl(u));
1927   };
1928
1929   this.matchHeaders = function(h) {
1930     if (angular.isUndefined(headers)) return true;
1931     if (angular.isFunction(headers)) return headers(h);
1932     return angular.equals(headers, h);
1933   };
1934
1935   this.matchData = function(d) {
1936     if (angular.isUndefined(data)) return true;
1937     if (data && angular.isFunction(data.test)) return data.test(d);
1938     if (data && angular.isFunction(data)) return data(d);
1939     if (data && !angular.isString(data)) {
1940       return angular.equals(angular.fromJson(angular.toJson(data)), angular.fromJson(d));
1941     }
1942     // eslint-disable-next-line eqeqeq
1943     return data == d;
1944   };
1945
1946   this.toString = function() {
1947     return method + ' ' + url;
1948   };
1949
1950   this.params = function(u) {
1951     return angular.extend(parseQuery(), pathParams());
1952
1953     function pathParams() {
1954       var keyObj = {};
1955       if (!url || !angular.isFunction(url.test) || !keys || keys.length === 0) return keyObj;
1956
1957       var m = url.exec(u);
1958       if (!m) return keyObj;
1959       for (var i = 1, len = m.length; i < len; ++i) {
1960         var key = keys[i - 1];
1961         var val = m[i];
1962         if (key && val) {
1963           keyObj[key.name || key] = val;
1964         }
1965       }
1966
1967       return keyObj;
1968     }
1969
1970     function parseQuery() {
1971       var obj = {}, key_value, key,
1972           queryStr = u.indexOf('?') > -1
1973           ? u.substring(u.indexOf('?') + 1)
1974           : '';
1975
1976       angular.forEach(queryStr.split('&'), function(keyValue) {
1977         if (keyValue) {
1978           key_value = keyValue.replace(/\+/g,'%20').split('=');
1979           key = tryDecodeURIComponent(key_value[0]);
1980           if (angular.isDefined(key)) {
1981             var val = angular.isDefined(key_value[1]) ? tryDecodeURIComponent(key_value[1]) : true;
1982             if (!hasOwnProperty.call(obj, key)) {
1983               obj[key] = val;
1984             } else if (angular.isArray(obj[key])) {
1985               obj[key].push(val);
1986             } else {
1987               obj[key] = [obj[key],val];
1988             }
1989           }
1990         }
1991       });
1992       return obj;
1993     }
1994     function tryDecodeURIComponent(value) {
1995       try {
1996         return decodeURIComponent(value);
1997       } catch (e) {
1998         // Ignore any invalid uri component
1999       }
2000     }
2001   };
2002 }
2003
2004 function createMockXhr() {
2005   return new MockXhr();
2006 }
2007
2008 function MockXhr() {
2009
2010   // hack for testing $http, $httpBackend
2011   MockXhr.$$lastInstance = this;
2012
2013   this.open = function(method, url, async) {
2014     this.$$method = method;
2015     this.$$url = url;
2016     this.$$async = async;
2017     this.$$reqHeaders = {};
2018     this.$$respHeaders = {};
2019   };
2020
2021   this.send = function(data) {
2022     this.$$data = data;
2023   };
2024
2025   this.setRequestHeader = function(key, value) {
2026     this.$$reqHeaders[key] = value;
2027   };
2028
2029   this.getResponseHeader = function(name) {
2030     // the lookup must be case insensitive,
2031     // that's why we try two quick lookups first and full scan last
2032     var header = this.$$respHeaders[name];
2033     if (header) return header;
2034
2035     name = angular.lowercase(name);
2036     header = this.$$respHeaders[name];
2037     if (header) return header;
2038
2039     header = undefined;
2040     angular.forEach(this.$$respHeaders, function(headerVal, headerName) {
2041       if (!header && angular.lowercase(headerName) === name) header = headerVal;
2042     });
2043     return header;
2044   };
2045
2046   this.getAllResponseHeaders = function() {
2047     var lines = [];
2048
2049     angular.forEach(this.$$respHeaders, function(value, key) {
2050       lines.push(key + ': ' + value);
2051     });
2052     return lines.join('\n');
2053   };
2054
2055   this.abort = angular.noop;
2056
2057   // This section simulates the events on a real XHR object (and the upload object)
2058   // When we are testing $httpBackend (inside the angular project) we make partial use of this
2059   // but store the events directly ourselves on `$$events`, instead of going through the `addEventListener`
2060   this.$$events = {};
2061   this.addEventListener = function(name, listener) {
2062     if (angular.isUndefined(this.$$events[name])) this.$$events[name] = [];
2063     this.$$events[name].push(listener);
2064   };
2065
2066   this.upload = {
2067     $$events: {},
2068     addEventListener: this.addEventListener
2069   };
2070 }
2071
2072
2073 /**
2074  * @ngdoc service
2075  * @name $timeout
2076  * @description
2077  *
2078  * This service is just a simple decorator for {@link ng.$timeout $timeout} service
2079  * that adds a "flush" and "verifyNoPendingTasks" methods.
2080  */
2081
2082 angular.mock.$TimeoutDecorator = ['$delegate', '$browser', function($delegate, $browser) {
2083
2084   /**
2085    * @ngdoc method
2086    * @name $timeout#flush
2087    * @description
2088    *
2089    * Flushes the queue of pending tasks.
2090    *
2091    * @param {number=} delay maximum timeout amount to flush up until
2092    */
2093   $delegate.flush = function(delay) {
2094     $browser.defer.flush(delay);
2095   };
2096
2097   /**
2098    * @ngdoc method
2099    * @name $timeout#verifyNoPendingTasks
2100    * @description
2101    *
2102    * Verifies that there are no pending tasks that need to be flushed.
2103    */
2104   $delegate.verifyNoPendingTasks = function() {
2105     if ($browser.deferredFns.length) {
2106       throw new Error('Deferred tasks to flush (' + $browser.deferredFns.length + '): ' +
2107           formatPendingTasksAsString($browser.deferredFns));
2108     }
2109   };
2110
2111   function formatPendingTasksAsString(tasks) {
2112     var result = [];
2113     angular.forEach(tasks, function(task) {
2114       result.push('{id: ' + task.id + ', time: ' + task.time + '}');
2115     });
2116
2117     return result.join(', ');
2118   }
2119
2120   return $delegate;
2121 }];
2122
2123 angular.mock.$RAFDecorator = ['$delegate', function($delegate) {
2124   var rafFn = function(fn) {
2125     var index = rafFn.queue.length;
2126     rafFn.queue.push(fn);
2127     return function() {
2128       rafFn.queue.splice(index, 1);
2129     };
2130   };
2131
2132   rafFn.queue = [];
2133   rafFn.supported = $delegate.supported;
2134
2135   rafFn.flush = function() {
2136     if (rafFn.queue.length === 0) {
2137       throw new Error('No rAF callbacks present');
2138     }
2139
2140     var length = rafFn.queue.length;
2141     for (var i = 0; i < length; i++) {
2142       rafFn.queue[i]();
2143     }
2144
2145     rafFn.queue = rafFn.queue.slice(i);
2146   };
2147
2148   return rafFn;
2149 }];
2150
2151 /**
2152  *
2153  */
2154 var originalRootElement;
2155 angular.mock.$RootElementProvider = function() {
2156   this.$get = ['$injector', function($injector) {
2157     originalRootElement = angular.element('<div ng-app></div>').data('$injector', $injector);
2158     return originalRootElement;
2159   }];
2160 };
2161
2162 /**
2163  * @ngdoc service
2164  * @name $controller
2165  * @description
2166  * A decorator for {@link ng.$controller} with additional `bindings` parameter, useful when testing
2167  * controllers of directives that use {@link $compile#-bindtocontroller- `bindToController`}.
2168  *
2169  * Depending on the value of
2170  * {@link ng.$compileProvider#preAssignBindingsEnabled `preAssignBindingsEnabled()`}, the properties
2171  * will be bound before or after invoking the constructor.
2172  *
2173  *
2174  * ## Example
2175  *
2176  * ```js
2177  *
2178  * // Directive definition ...
2179  *
2180  * myMod.directive('myDirective', {
2181  *   controller: 'MyDirectiveController',
2182  *   bindToController: {
2183  *     name: '@'
2184  *   }
2185  * });
2186  *
2187  *
2188  * // Controller definition ...
2189  *
2190  * myMod.controller('MyDirectiveController', ['$log', function($log) {
2191  *   this.log = function() {
2192  *     $log.info(this.name);
2193  *   };
2194  * }]);
2195  *
2196  *
2197  * // In a test ...
2198  *
2199  * describe('myDirectiveController', function() {
2200  *   describe('log()', function() {
2201  *     it('should write the bound name to the log', inject(function($controller, $log) {
2202  *       var ctrl = $controller('MyDirectiveController', { /* no locals &#42;/ }, { name: 'Clark Kent' });
2203  *       ctrl.log();
2204  *
2205  *       expect(ctrl.name).toEqual('Clark Kent');
2206  *       expect($log.info.logs).toEqual(['Clark Kent']);
2207  *     }));
2208  *   });
2209  * });
2210  *
2211  * ```
2212  *
2213  * @param {Function|string} constructor If called with a function then it's considered to be the
2214  *    controller constructor function. Otherwise it's considered to be a string which is used
2215  *    to retrieve the controller constructor using the following steps:
2216  *
2217  *    * check if a controller with given name is registered via `$controllerProvider`
2218  *    * check if evaluating the string on the current scope returns a constructor
2219  *    * if $controllerProvider#allowGlobals, check `window[constructor]` on the global
2220  *      `window` object (not recommended)
2221  *
2222  *    The string can use the `controller as property` syntax, where the controller instance is published
2223  *    as the specified property on the `scope`; the `scope` must be injected into `locals` param for this
2224  *    to work correctly.
2225  *
2226  * @param {Object} locals Injection locals for Controller.
2227  * @param {Object=} bindings Properties to add to the controller instance. This is used to simulate
2228  *                           the `bindToController` feature and simplify certain kinds of tests.
2229  * @return {Object} Instance of given controller.
2230  */
2231 function createControllerDecorator(compileProvider) {
2232   angular.mock.$ControllerDecorator = ['$delegate', function($delegate) {
2233     return function(expression, locals, later, ident) {
2234       if (later && typeof later === 'object') {
2235         var preAssignBindingsEnabled = compileProvider.preAssignBindingsEnabled();
2236
2237         var instantiate = $delegate(expression, locals, true, ident);
2238         if (preAssignBindingsEnabled) {
2239           angular.extend(instantiate.instance, later);
2240         }
2241
2242         var instance = instantiate();
2243         if (!preAssignBindingsEnabled || instance !== instantiate.instance) {
2244           angular.extend(instance, later);
2245         }
2246
2247         return instance;
2248       }
2249       return $delegate(expression, locals, later, ident);
2250     };
2251   }];
2252
2253   return angular.mock.$ControllerDecorator;
2254 }
2255
2256 /**
2257  * @ngdoc service
2258  * @name $componentController
2259  * @description
2260  * A service that can be used to create instances of component controllers. Useful for unit-testing.
2261  *
2262  * Be aware that the controller will be instantiated and attached to the scope as specified in
2263  * the component definition object. If you do not provide a `$scope` object in the `locals` param
2264  * then the helper will create a new isolated scope as a child of `$rootScope`.
2265  *
2266  * If you are using `$element` or `$attrs` in the controller, make sure to provide them as `locals`.
2267  * The `$element` must be a jqLite-wrapped DOM element, and `$attrs` should be an object that
2268  * has all properties / functions that you are using in the controller. If this is getting too complex,
2269  * you should compile the component instead and access the component's controller via the
2270  * {@link angular.element#methods `controller`} function.
2271  *
2272  * See also the section on {@link guide/component#unit-testing-component-controllers unit-testing component controllers}
2273  * in the guide.
2274  *
2275  * @param {string} componentName the name of the component whose controller we want to instantiate
2276  * @param {Object} locals Injection locals for Controller.
2277  * @param {Object=} bindings Properties to add to the controller before invoking the constructor. This is used
2278  *                           to simulate the `bindToController` feature and simplify certain kinds of tests.
2279  * @param {string=} ident Override the property name to use when attaching the controller to the scope.
2280  * @return {Object} Instance of requested controller.
2281  */
2282 angular.mock.$ComponentControllerProvider = ['$compileProvider',
2283     function ComponentControllerProvider($compileProvider) {
2284   this.$get = ['$controller','$injector', '$rootScope', function($controller, $injector, $rootScope) {
2285     return function $componentController(componentName, locals, bindings, ident) {
2286       // get all directives associated to the component name
2287       var directives = $injector.get(componentName + 'Directive');
2288       // look for those directives that are components
2289       var candidateDirectives = directives.filter(function(directiveInfo) {
2290         // components have controller, controllerAs and restrict:'E'
2291         return directiveInfo.controller && directiveInfo.controllerAs && directiveInfo.restrict === 'E';
2292       });
2293       // check if valid directives found
2294       if (candidateDirectives.length === 0) {
2295         throw new Error('No component found');
2296       }
2297       if (candidateDirectives.length > 1) {
2298         throw new Error('Too many components found');
2299       }
2300       // get the info of the component
2301       var directiveInfo = candidateDirectives[0];
2302       // create a scope if needed
2303       locals = locals || {};
2304       locals.$scope = locals.$scope || $rootScope.$new(true);
2305       return $controller(directiveInfo.controller, locals, bindings, ident || directiveInfo.controllerAs);
2306     };
2307   }];
2308 }];
2309
2310
2311 /**
2312  * @ngdoc module
2313  * @name ngMock
2314  * @packageName angular-mocks
2315  * @description
2316  *
2317  * # ngMock
2318  *
2319  * The `ngMock` module provides support to inject and mock Angular services into unit tests.
2320  * In addition, ngMock also extends various core ng services such that they can be
2321  * inspected and controlled in a synchronous manner within test code.
2322  *
2323  *
2324  * <div doc-module-components="ngMock"></div>
2325  *
2326  * @installation
2327  *
2328  *  First, download the file:
2329  *  * [Google CDN](https://developers.google.com/speed/libraries/devguide#angularjs) e.g.
2330  *    `"//ajax.googleapis.com/ajax/libs/angularjs/X.Y.Z/angular-mocks.js"`
2331  *  * [NPM](https://www.npmjs.com/) e.g. `npm install angular-mocks@X.Y.Z`
2332  *  * [Yarn](https://yarnpkg.com) e.g. `yarn add angular-mocks@X.Y.Z`
2333  *  * [Bower](http://bower.io) e.g. `bower install angular-mocks#X.Y.Z`
2334  *  * [code.angularjs.org](https://code.angularjs.org/) (discouraged for production use)  e.g.
2335  *    `"//code.angularjs.org/X.Y.Z/angular-mocks.js"`
2336  *
2337  * where X.Y.Z is the AngularJS version you are running.
2338  *
2339  * Then, configure your test runner to load `angular-mocks.js` after `angular.js`.
2340  * This example uses <a href="http://karma-runner.github.io/">Karma</a>:
2341  *
2342  * ```
2343  * config.set({
2344  *   files: [
2345  *     'build/angular.js', // and other module files you need
2346  *     'build/angular-mocks.js',
2347  *     '<path/to/application/files>',
2348  *     '<path/to/spec/files>'
2349  *   ]
2350  * });
2351  * ```
2352  *
2353  * Including the `angular-mocks.js` file automatically adds the `ngMock` module, so your tests
2354  *  are ready to go!
2355  */
2356 angular.module('ngMock', ['ng']).provider({
2357   $browser: angular.mock.$BrowserProvider,
2358   $exceptionHandler: angular.mock.$ExceptionHandlerProvider,
2359   $log: angular.mock.$LogProvider,
2360   $interval: angular.mock.$IntervalProvider,
2361   $httpBackend: angular.mock.$HttpBackendProvider,
2362   $rootElement: angular.mock.$RootElementProvider,
2363   $componentController: angular.mock.$ComponentControllerProvider
2364 }).config(['$provide', '$compileProvider', function($provide, $compileProvider) {
2365   $provide.decorator('$timeout', angular.mock.$TimeoutDecorator);
2366   $provide.decorator('$$rAF', angular.mock.$RAFDecorator);
2367   $provide.decorator('$rootScope', angular.mock.$RootScopeDecorator);
2368   $provide.decorator('$controller', createControllerDecorator($compileProvider));
2369 }]);
2370
2371 /**
2372  * @ngdoc module
2373  * @name ngMockE2E
2374  * @module ngMockE2E
2375  * @packageName angular-mocks
2376  * @description
2377  *
2378  * The `ngMockE2E` is an angular module which contains mocks suitable for end-to-end testing.
2379  * Currently there is only one mock present in this module -
2380  * the {@link ngMockE2E.$httpBackend e2e $httpBackend} mock.
2381  */
2382 angular.module('ngMockE2E', ['ng']).config(['$provide', function($provide) {
2383   $provide.value('$httpBackend', angular.injector(['ng']).get('$httpBackend'));
2384   $provide.decorator('$httpBackend', angular.mock.e2e.$httpBackendDecorator);
2385 }]);
2386
2387 /**
2388  * @ngdoc service
2389  * @name $httpBackend
2390  * @module ngMockE2E
2391  * @description
2392  * Fake HTTP backend implementation suitable for end-to-end testing or backend-less development of
2393  * applications that use the {@link ng.$http $http service}.
2394  *
2395  * <div class="alert alert-info">
2396  * **Note**: For fake http backend implementation suitable for unit testing please see
2397  * {@link ngMock.$httpBackend unit-testing $httpBackend mock}.
2398  * </div>
2399  *
2400  * This implementation can be used to respond with static or dynamic responses via the `when` api
2401  * and its shortcuts (`whenGET`, `whenPOST`, etc) and optionally pass through requests to the
2402  * real $httpBackend for specific requests (e.g. to interact with certain remote apis or to fetch
2403  * templates from a webserver).
2404  *
2405  * As opposed to unit-testing, in an end-to-end testing scenario or in scenario when an application
2406  * is being developed with the real backend api replaced with a mock, it is often desirable for
2407  * certain category of requests to bypass the mock and issue a real http request (e.g. to fetch
2408  * templates or static files from the webserver). To configure the backend with this behavior
2409  * use the `passThrough` request handler of `when` instead of `respond`.
2410  *
2411  * Additionally, we don't want to manually have to flush mocked out requests like we do during unit
2412  * testing. For this reason the e2e $httpBackend flushes mocked out requests
2413  * automatically, closely simulating the behavior of the XMLHttpRequest object.
2414  *
2415  * To setup the application to run with this http backend, you have to create a module that depends
2416  * on the `ngMockE2E` and your application modules and defines the fake backend:
2417  *
2418  * ```js
2419  *   var myAppDev = angular.module('myAppDev', ['myApp', 'ngMockE2E']);
2420  *   myAppDev.run(function($httpBackend) {
2421  *     var phones = [{name: 'phone1'}, {name: 'phone2'}];
2422  *
2423  *     // returns the current list of phones
2424  *     $httpBackend.whenGET('/phones').respond(phones);
2425  *
2426  *     // adds a new phone to the phones array
2427  *     $httpBackend.whenPOST('/phones').respond(function(method, url, data) {
2428  *       var phone = angular.fromJson(data);
2429  *       phones.push(phone);
2430  *       return [200, phone, {}];
2431  *     });
2432  *     $httpBackend.whenGET(/^\/templates\//).passThrough(); // Requests for templare are handled by the real server
2433  *     //...
2434  *   });
2435  * ```
2436  *
2437  * Afterwards, bootstrap your app with this new module.
2438  *
2439  * ## Example
2440  * <example name="httpbackend-e2e-testing" module="myAppE2E" deps="angular-mocks.js">
2441  * <file name="app.js">
2442  *   var myApp = angular.module('myApp', []);
2443  *
2444  *   myApp.controller('MainCtrl', function MainCtrl($http) {
2445  *     var ctrl = this;
2446  *
2447  *     ctrl.phones = [];
2448  *     ctrl.newPhone = {
2449  *       name: ''
2450  *     };
2451  *
2452  *     ctrl.getPhones = function() {
2453  *       $http.get('/phones').then(function(response) {
2454  *         ctrl.phones = response.data;
2455  *       });
2456  *     };
2457  *
2458  *     ctrl.addPhone = function(phone) {
2459  *       $http.post('/phones', phone).then(function() {
2460  *         ctrl.newPhone = {name: ''};
2461  *         return ctrl.getPhones();
2462  *       });
2463  *     };
2464  *
2465  *     ctrl.getPhones();
2466  *   });
2467  * </file>
2468  * <file name="e2e.js">
2469  *   var myAppDev = angular.module('myAppE2E', ['myApp', 'ngMockE2E']);
2470  *
2471  *   myAppDev.run(function($httpBackend) {
2472  *     var phones = [{name: 'phone1'}, {name: 'phone2'}];
2473  *
2474  *     // returns the current list of phones
2475  *     $httpBackend.whenGET('/phones').respond(phones);
2476  *
2477  *     // adds a new phone to the phones array
2478  *     $httpBackend.whenPOST('/phones').respond(function(method, url, data) {
2479  *       var phone = angular.fromJson(data);
2480  *       phones.push(phone);
2481  *       return [200, phone, {}];
2482  *     });
2483  *   });
2484  * </file>
2485  * <file name="index.html">
2486  *   <div ng-controller="MainCtrl as $ctrl">
2487  *   <form name="newPhoneForm" ng-submit="$ctrl.addPhone($ctrl.newPhone)">
2488  *     <input type="text" ng-model="$ctrl.newPhone.name">
2489  *     <input type="submit" value="Add Phone">
2490  *   </form>
2491  *   <h1>Phones</h1>
2492  *   <ul>
2493  *     <li ng-repeat="phone in $ctrl.phones">{{phone.name}}</li>
2494  *   </ul>
2495  *   </div>
2496  * </file>
2497  * </example>
2498  *
2499  *
2500  */
2501
2502 /**
2503  * @ngdoc method
2504  * @name $httpBackend#when
2505  * @module ngMockE2E
2506  * @description
2507  * Creates a new backend definition.
2508  *
2509  * @param {string} method HTTP method.
2510  * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
2511  *   and returns true if the url matches the current definition.
2512  * @param {(string|RegExp|function(string))=} data HTTP request body or function that receives
2513  *   data string and returns true if the data is as expected.
2514  * @param {(Object|function(Object))=} headers HTTP headers or function that receives http header
2515  *   object and returns true if the headers match the current definition.
2516  * @param {(Array)=} keys Array of keys to assign to regex matches in request url described on
2517  *   {@link ngMock.$httpBackend $httpBackend mock}.
2518  * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
2519  *   control how a matched request is handled. You can save this object for later use and invoke
2520  *   `respond` or `passThrough` again in order to change how a matched request is handled.
2521  *
2522  *  - respond â€“
2523  *    ```
2524  *    { function([status,] data[, headers, statusText])
2525  *    | function(function(method, url, data, headers, params)}
2526  *    ```
2527  *    â€“ The respond method takes a set of static data to be returned or a function that can return
2528  *    an array containing response status (number), response data (Array|Object|string), response
2529  *    headers (Object), and the text for the status (string).
2530  *  - passThrough â€“ `{function()}` â€“ Any request matching a backend definition with
2531  *    `passThrough` handler will be passed through to the real backend (an XHR request will be made
2532  *    to the server.)
2533  *  - Both methods return the `requestHandler` object for possible overrides.
2534  */
2535
2536 /**
2537  * @ngdoc method
2538  * @name $httpBackend#whenGET
2539  * @module ngMockE2E
2540  * @description
2541  * Creates a new backend definition for GET requests. For more info see `when()`.
2542  *
2543  * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
2544  *   and returns true if the url matches the current definition.
2545  * @param {(Object|function(Object))=} headers HTTP headers.
2546  * @param {(Array)=} keys Array of keys to assign to regex matches in request url described on
2547  *   {@link ngMock.$httpBackend $httpBackend mock}.
2548  * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
2549  *   control how a matched request is handled. You can save this object for later use and invoke
2550  *   `respond` or `passThrough` again in order to change how a matched request is handled.
2551  */
2552
2553 /**
2554  * @ngdoc method
2555  * @name $httpBackend#whenHEAD
2556  * @module ngMockE2E
2557  * @description
2558  * Creates a new backend definition for HEAD requests. For more info see `when()`.
2559  *
2560  * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
2561  *   and returns true if the url matches the current definition.
2562  * @param {(Object|function(Object))=} headers HTTP headers.
2563  * @param {(Array)=} keys Array of keys to assign to regex matches in request url described on
2564  *   {@link ngMock.$httpBackend $httpBackend mock}.
2565  * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
2566  *   control how a matched request is handled. You can save this object for later use and invoke
2567  *   `respond` or `passThrough` again in order to change how a matched request is handled.
2568  */
2569
2570 /**
2571  * @ngdoc method
2572  * @name $httpBackend#whenDELETE
2573  * @module ngMockE2E
2574  * @description
2575  * Creates a new backend definition for DELETE requests. For more info see `when()`.
2576  *
2577  * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
2578  *   and returns true if the url matches the current definition.
2579  * @param {(Object|function(Object))=} headers HTTP headers.
2580  * @param {(Array)=} keys Array of keys to assign to regex matches in request url described on
2581  *   {@link ngMock.$httpBackend $httpBackend mock}.
2582  * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
2583  *   control how a matched request is handled. You can save this object for later use and invoke
2584  *   `respond` or `passThrough` again in order to change how a matched request is handled.
2585  */
2586
2587 /**
2588  * @ngdoc method
2589  * @name $httpBackend#whenPOST
2590  * @module ngMockE2E
2591  * @description
2592  * Creates a new backend definition for POST requests. For more info see `when()`.
2593  *
2594  * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
2595  *   and returns true if the url matches the current definition.
2596  * @param {(string|RegExp|function(string))=} data HTTP request body or function that receives
2597  *   data string and returns true if the data is as expected.
2598  * @param {(Object|function(Object))=} headers HTTP headers.
2599  * @param {(Array)=} keys Array of keys to assign to regex matches in request url described on
2600  *   {@link ngMock.$httpBackend $httpBackend mock}.
2601  * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
2602  *   control how a matched request is handled. You can save this object for later use and invoke
2603  *   `respond` or `passThrough` again in order to change how a matched request is handled.
2604  */
2605
2606 /**
2607  * @ngdoc method
2608  * @name $httpBackend#whenPUT
2609  * @module ngMockE2E
2610  * @description
2611  * Creates a new backend definition for PUT requests.  For more info see `when()`.
2612  *
2613  * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
2614  *   and returns true if the url matches the current definition.
2615  * @param {(string|RegExp|function(string))=} data HTTP request body or function that receives
2616  *   data string and returns true if the data is as expected.
2617  * @param {(Object|function(Object))=} headers HTTP headers.
2618  * @param {(Array)=} keys Array of keys to assign to regex matches in request url described on
2619  *   {@link ngMock.$httpBackend $httpBackend mock}.
2620  * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
2621  *   control how a matched request is handled. You can save this object for later use and invoke
2622  *   `respond` or `passThrough` again in order to change how a matched request is handled.
2623  */
2624
2625 /**
2626  * @ngdoc method
2627  * @name $httpBackend#whenPATCH
2628  * @module ngMockE2E
2629  * @description
2630  * Creates a new backend definition for PATCH requests.  For more info see `when()`.
2631  *
2632  * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
2633  *   and returns true if the url matches the current definition.
2634  * @param {(string|RegExp|function(string))=} data HTTP request body or function that receives
2635  *   data string and returns true if the data is as expected.
2636  * @param {(Object|function(Object))=} headers HTTP headers.
2637  * @param {(Array)=} keys Array of keys to assign to regex matches in request url described on
2638  *   {@link ngMock.$httpBackend $httpBackend mock}.
2639  * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
2640  *   control how a matched request is handled. You can save this object for later use and invoke
2641  *   `respond` or `passThrough` again in order to change how a matched request is handled.
2642  */
2643
2644 /**
2645  * @ngdoc method
2646  * @name $httpBackend#whenJSONP
2647  * @module ngMockE2E
2648  * @description
2649  * Creates a new backend definition for JSONP requests. For more info see `when()`.
2650  *
2651  * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
2652  *   and returns true if the url matches the current definition.
2653  * @param {(Array)=} keys Array of keys to assign to regex matches in request url described on
2654  *   {@link ngMock.$httpBackend $httpBackend mock}.
2655  * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
2656  *   control how a matched request is handled. You can save this object for later use and invoke
2657  *   `respond` or `passThrough` again in order to change how a matched request is handled.
2658  */
2659 /**
2660  * @ngdoc method
2661  * @name $httpBackend#whenRoute
2662  * @module ngMockE2E
2663  * @description
2664  * Creates a new backend definition that compares only with the requested route.
2665  *
2666  * @param {string} method HTTP method.
2667  * @param {string} url HTTP url string that supports colon param matching.
2668  * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
2669  *   control how a matched request is handled. You can save this object for later use and invoke
2670  *   `respond` or `passThrough` again in order to change how a matched request is handled.
2671  */
2672 angular.mock.e2e = {};
2673 angular.mock.e2e.$httpBackendDecorator =
2674   ['$rootScope', '$timeout', '$delegate', '$browser', createHttpBackendMock];
2675
2676
2677 /**
2678  * @ngdoc type
2679  * @name $rootScope.Scope
2680  * @module ngMock
2681  * @description
2682  * {@link ng.$rootScope.Scope Scope} type decorated with helper methods useful for testing. These
2683  * methods are automatically available on any {@link ng.$rootScope.Scope Scope} instance when
2684  * `ngMock` module is loaded.
2685  *
2686  * In addition to all the regular `Scope` methods, the following helper methods are available:
2687  */
2688 angular.mock.$RootScopeDecorator = ['$delegate', function($delegate) {
2689
2690   var $rootScopePrototype = Object.getPrototypeOf($delegate);
2691
2692   $rootScopePrototype.$countChildScopes = countChildScopes;
2693   $rootScopePrototype.$countWatchers = countWatchers;
2694
2695   return $delegate;
2696
2697   // ------------------------------------------------------------------------------------------ //
2698
2699   /**
2700    * @ngdoc method
2701    * @name $rootScope.Scope#$countChildScopes
2702    * @module ngMock
2703    * @this $rootScope.Scope
2704    * @description
2705    * Counts all the direct and indirect child scopes of the current scope.
2706    *
2707    * The current scope is excluded from the count. The count includes all isolate child scopes.
2708    *
2709    * @returns {number} Total number of child scopes.
2710    */
2711   function countChildScopes() {
2712     var count = 0; // exclude the current scope
2713     var pendingChildHeads = [this.$$childHead];
2714     var currentScope;
2715
2716     while (pendingChildHeads.length) {
2717       currentScope = pendingChildHeads.shift();
2718
2719       while (currentScope) {
2720         count += 1;
2721         pendingChildHeads.push(currentScope.$$childHead);
2722         currentScope = currentScope.$$nextSibling;
2723       }
2724     }
2725
2726     return count;
2727   }
2728
2729
2730   /**
2731    * @ngdoc method
2732    * @name $rootScope.Scope#$countWatchers
2733    * @this $rootScope.Scope
2734    * @module ngMock
2735    * @description
2736    * Counts all the watchers of direct and indirect child scopes of the current scope.
2737    *
2738    * The watchers of the current scope are included in the count and so are all the watchers of
2739    * isolate child scopes.
2740    *
2741    * @returns {number} Total number of watchers.
2742    */
2743   function countWatchers() {
2744     var count = this.$$watchers ? this.$$watchers.length : 0; // include the current scope
2745     var pendingChildHeads = [this.$$childHead];
2746     var currentScope;
2747
2748     while (pendingChildHeads.length) {
2749       currentScope = pendingChildHeads.shift();
2750
2751       while (currentScope) {
2752         count += currentScope.$$watchers ? currentScope.$$watchers.length : 0;
2753         pendingChildHeads.push(currentScope.$$childHead);
2754         currentScope = currentScope.$$nextSibling;
2755       }
2756     }
2757
2758     return count;
2759   }
2760 }];
2761
2762
2763 (function(jasmineOrMocha) {
2764
2765   if (!jasmineOrMocha) {
2766     return;
2767   }
2768
2769   var currentSpec = null,
2770       injectorState = new InjectorState(),
2771       annotatedFunctions = [],
2772       wasInjectorCreated = function() {
2773         return !!currentSpec;
2774       };
2775
2776   angular.mock.$$annotate = angular.injector.$$annotate;
2777   angular.injector.$$annotate = function(fn) {
2778     if (typeof fn === 'function' && !fn.$inject) {
2779       annotatedFunctions.push(fn);
2780     }
2781     return angular.mock.$$annotate.apply(this, arguments);
2782   };
2783
2784   /**
2785    * @ngdoc function
2786    * @name angular.mock.module
2787    * @description
2788    *
2789    * *NOTE*: This function is also published on window for easy access.<br>
2790    * *NOTE*: This function is declared ONLY WHEN running tests with jasmine or mocha
2791    *
2792    * This function registers a module configuration code. It collects the configuration information
2793    * which will be used when the injector is created by {@link angular.mock.inject inject}.
2794    *
2795    * See {@link angular.mock.inject inject} for usage example
2796    *
2797    * @param {...(string|Function|Object)} fns any number of modules which are represented as string
2798    *        aliases or as anonymous module initialization functions. The modules are used to
2799    *        configure the injector. The 'ng' and 'ngMock' modules are automatically loaded. If an
2800    *        object literal is passed each key-value pair will be registered on the module via
2801    *        {@link auto.$provide $provide}.value, the key being the string name (or token) to associate
2802    *        with the value on the injector.
2803    */
2804   var module = window.module = angular.mock.module = function() {
2805     var moduleFns = Array.prototype.slice.call(arguments, 0);
2806     return wasInjectorCreated() ? workFn() : workFn;
2807     /////////////////////
2808     function workFn() {
2809       if (currentSpec.$injector) {
2810         throw new Error('Injector already created, can not register a module!');
2811       } else {
2812         var fn, modules = currentSpec.$modules || (currentSpec.$modules = []);
2813         angular.forEach(moduleFns, function(module) {
2814           if (angular.isObject(module) && !angular.isArray(module)) {
2815             fn = ['$provide', function($provide) {
2816               angular.forEach(module, function(value, key) {
2817                 $provide.value(key, value);
2818               });
2819             }];
2820           } else {
2821             fn = module;
2822           }
2823           if (currentSpec.$providerInjector) {
2824             currentSpec.$providerInjector.invoke(fn);
2825           } else {
2826             modules.push(fn);
2827           }
2828         });
2829       }
2830     }
2831   };
2832
2833   module.$$beforeAllHook = (window.before || window.beforeAll);
2834   module.$$afterAllHook = (window.after || window.afterAll);
2835
2836   // purely for testing ngMock itself
2837   module.$$currentSpec = function(to) {
2838     if (arguments.length === 0) return to;
2839     currentSpec = to;
2840   };
2841
2842   /**
2843    * @ngdoc function
2844    * @name angular.mock.module.sharedInjector
2845    * @description
2846    *
2847    * *NOTE*: This function is declared ONLY WHEN running tests with jasmine or mocha
2848    *
2849    * This function ensures a single injector will be used for all tests in a given describe context.
2850    * This contrasts with the default behaviour where a new injector is created per test case.
2851    *
2852    * Use sharedInjector when you want to take advantage of Jasmine's `beforeAll()`, or mocha's
2853    * `before()` methods. Call `module.sharedInjector()` before you setup any other hooks that
2854    * will create (i.e call `module()`) or use (i.e call `inject()`) the injector.
2855    *
2856    * You cannot call `sharedInjector()` from within a context already using `sharedInjector()`.
2857    *
2858    * ## Example
2859    *
2860    * Typically beforeAll is used to make many assertions about a single operation. This can
2861    * cut down test run-time as the test setup doesn't need to be re-run, and enabling focussed
2862    * tests each with a single assertion.
2863    *
2864    * ```js
2865    * describe("Deep Thought", function() {
2866    *
2867    *   module.sharedInjector();
2868    *
2869    *   beforeAll(module("UltimateQuestion"));
2870    *
2871    *   beforeAll(inject(function(DeepThought) {
2872    *     expect(DeepThought.answer).toBeUndefined();
2873    *     DeepThought.generateAnswer();
2874    *   }));
2875    *
2876    *   it("has calculated the answer correctly", inject(function(DeepThought) {
2877    *     // Because of sharedInjector, we have access to the instance of the DeepThought service
2878    *     // that was provided to the beforeAll() hook. Therefore we can test the generated answer
2879    *     expect(DeepThought.answer).toBe(42);
2880    *   }));
2881    *
2882    *   it("has calculated the answer within the expected time", inject(function(DeepThought) {
2883    *     expect(DeepThought.runTimeMillennia).toBeLessThan(8000);
2884    *   }));
2885    *
2886    *   it("has double checked the answer", inject(function(DeepThought) {
2887    *     expect(DeepThought.absolutelySureItIsTheRightAnswer).toBe(true);
2888    *   }));
2889    *
2890    * });
2891    *
2892    * ```
2893    */
2894   module.sharedInjector = function() {
2895     if (!(module.$$beforeAllHook && module.$$afterAllHook)) {
2896       throw Error('sharedInjector() cannot be used unless your test runner defines beforeAll/afterAll');
2897     }
2898
2899     var initialized = false;
2900
2901     module.$$beforeAllHook(/** @this */ function() {
2902       if (injectorState.shared) {
2903         injectorState.sharedError = Error('sharedInjector() cannot be called inside a context that has already called sharedInjector()');
2904         throw injectorState.sharedError;
2905       }
2906       initialized = true;
2907       currentSpec = this;
2908       injectorState.shared = true;
2909     });
2910
2911     module.$$afterAllHook(function() {
2912       if (initialized) {
2913         injectorState = new InjectorState();
2914         module.$$cleanup();
2915       } else {
2916         injectorState.sharedError = null;
2917       }
2918     });
2919   };
2920
2921   module.$$beforeEach = function() {
2922     if (injectorState.shared && currentSpec && currentSpec !== this) {
2923       var state = currentSpec;
2924       currentSpec = this;
2925       angular.forEach(['$injector','$modules','$providerInjector', '$injectorStrict'], function(k) {
2926         currentSpec[k] = state[k];
2927         state[k] = null;
2928       });
2929     } else {
2930       currentSpec = this;
2931       originalRootElement = null;
2932       annotatedFunctions = [];
2933     }
2934   };
2935
2936   module.$$afterEach = function() {
2937     if (injectorState.cleanupAfterEach()) {
2938       module.$$cleanup();
2939     }
2940   };
2941
2942   module.$$cleanup = function() {
2943     var injector = currentSpec.$injector;
2944
2945     annotatedFunctions.forEach(function(fn) {
2946       delete fn.$inject;
2947     });
2948
2949     angular.forEach(currentSpec.$modules, function(module) {
2950       if (module && module.$$hashKey) {
2951         module.$$hashKey = undefined;
2952       }
2953     });
2954
2955     currentSpec.$injector = null;
2956     currentSpec.$modules = null;
2957     currentSpec.$providerInjector = null;
2958     currentSpec = null;
2959
2960     if (injector) {
2961       // Ensure `$rootElement` is instantiated, before checking `originalRootElement`
2962       var $rootElement = injector.get('$rootElement');
2963       var rootNode = $rootElement && $rootElement[0];
2964       var cleanUpNodes = !originalRootElement ? [] : [originalRootElement[0]];
2965       if (rootNode && (!originalRootElement || rootNode !== originalRootElement[0])) {
2966         cleanUpNodes.push(rootNode);
2967       }
2968       angular.element.cleanData(cleanUpNodes);
2969
2970       // Ensure `$destroy()` is available, before calling it
2971       // (a mocked `$rootScope` might not implement it (or not even be an object at all))
2972       var $rootScope = injector.get('$rootScope');
2973       if ($rootScope && $rootScope.$destroy) $rootScope.$destroy();
2974     }
2975
2976     // clean up jquery's fragment cache
2977     angular.forEach(angular.element.fragments, function(val, key) {
2978       delete angular.element.fragments[key];
2979     });
2980
2981     MockXhr.$$lastInstance = null;
2982
2983     angular.forEach(angular.callbacks, function(val, key) {
2984       delete angular.callbacks[key];
2985     });
2986     angular.callbacks.$$counter = 0;
2987   };
2988
2989   (window.beforeEach || window.setup)(module.$$beforeEach);
2990   (window.afterEach || window.teardown)(module.$$afterEach);
2991
2992   /**
2993    * @ngdoc function
2994    * @name angular.mock.inject
2995    * @description
2996    *
2997    * *NOTE*: This function is also published on window for easy access.<br>
2998    * *NOTE*: This function is declared ONLY WHEN running tests with jasmine or mocha
2999    *
3000    * The inject function wraps a function into an injectable function. The inject() creates new
3001    * instance of {@link auto.$injector $injector} per test, which is then used for
3002    * resolving references.
3003    *
3004    *
3005    * ## Resolving References (Underscore Wrapping)
3006    * Often, we would like to inject a reference once, in a `beforeEach()` block and reuse this
3007    * in multiple `it()` clauses. To be able to do this we must assign the reference to a variable
3008    * that is declared in the scope of the `describe()` block. Since we would, most likely, want
3009    * the variable to have the same name of the reference we have a problem, since the parameter
3010    * to the `inject()` function would hide the outer variable.
3011    *
3012    * To help with this, the injected parameters can, optionally, be enclosed with underscores.
3013    * These are ignored by the injector when the reference name is resolved.
3014    *
3015    * For example, the parameter `_myService_` would be resolved as the reference `myService`.
3016    * Since it is available in the function body as `_myService_`, we can then assign it to a variable
3017    * defined in an outer scope.
3018    *
3019    * ```
3020    * // Defined out reference variable outside
3021    * var myService;
3022    *
3023    * // Wrap the parameter in underscores
3024    * beforeEach( inject( function(_myService_){
3025    *   myService = _myService_;
3026    * }));
3027    *
3028    * // Use myService in a series of tests.
3029    * it('makes use of myService', function() {
3030    *   myService.doStuff();
3031    * });
3032    *
3033    * ```
3034    *
3035    * See also {@link angular.mock.module angular.mock.module}
3036    *
3037    * ## Example
3038    * Example of what a typical jasmine tests looks like with the inject method.
3039    * ```js
3040    *
3041    *   angular.module('myApplicationModule', [])
3042    *       .value('mode', 'app')
3043    *       .value('version', 'v1.0.1');
3044    *
3045    *
3046    *   describe('MyApp', function() {
3047    *
3048    *     // You need to load modules that you want to test,
3049    *     // it loads only the "ng" module by default.
3050    *     beforeEach(module('myApplicationModule'));
3051    *
3052    *
3053    *     // inject() is used to inject arguments of all given functions
3054    *     it('should provide a version', inject(function(mode, version) {
3055    *       expect(version).toEqual('v1.0.1');
3056    *       expect(mode).toEqual('app');
3057    *     }));
3058    *
3059    *
3060    *     // The inject and module method can also be used inside of the it or beforeEach
3061    *     it('should override a version and test the new version is injected', function() {
3062    *       // module() takes functions or strings (module aliases)
3063    *       module(function($provide) {
3064    *         $provide.value('version', 'overridden'); // override version here
3065    *       });
3066    *
3067    *       inject(function(version) {
3068    *         expect(version).toEqual('overridden');
3069    *       });
3070    *     });
3071    *   });
3072    *
3073    * ```
3074    *
3075    * @param {...Function} fns any number of functions which will be injected using the injector.
3076    */
3077
3078
3079
3080   var ErrorAddingDeclarationLocationStack = function ErrorAddingDeclarationLocationStack(e, errorForStack) {
3081     this.message = e.message;
3082     this.name = e.name;
3083     if (e.line) this.line = e.line;
3084     if (e.sourceId) this.sourceId = e.sourceId;
3085     if (e.stack && errorForStack)
3086       this.stack = e.stack + '\n' + errorForStack.stack;
3087     if (e.stackArray) this.stackArray = e.stackArray;
3088   };
3089   ErrorAddingDeclarationLocationStack.prototype = Error.prototype;
3090
3091   window.inject = angular.mock.inject = function() {
3092     var blockFns = Array.prototype.slice.call(arguments, 0);
3093     var errorForStack = new Error('Declaration Location');
3094     // IE10+ and PhanthomJS do not set stack trace information, until the error is thrown
3095     if (!errorForStack.stack) {
3096       try {
3097         throw errorForStack;
3098       } catch (e) { /* empty */ }
3099     }
3100     return wasInjectorCreated() ? WorkFn.call(currentSpec) : WorkFn;
3101     /////////////////////
3102     function WorkFn() {
3103       var modules = currentSpec.$modules || [];
3104       var strictDi = !!currentSpec.$injectorStrict;
3105       modules.unshift(['$injector', function($injector) {
3106         currentSpec.$providerInjector = $injector;
3107       }]);
3108       modules.unshift('ngMock');
3109       modules.unshift('ng');
3110       var injector = currentSpec.$injector;
3111       if (!injector) {
3112         if (strictDi) {
3113           // If strictDi is enabled, annotate the providerInjector blocks
3114           angular.forEach(modules, function(moduleFn) {
3115             if (typeof moduleFn === 'function') {
3116               angular.injector.$$annotate(moduleFn);
3117             }
3118           });
3119         }
3120         injector = currentSpec.$injector = angular.injector(modules, strictDi);
3121         currentSpec.$injectorStrict = strictDi;
3122       }
3123       for (var i = 0, ii = blockFns.length; i < ii; i++) {
3124         if (currentSpec.$injectorStrict) {
3125           // If the injector is strict / strictDi, and the spec wants to inject using automatic
3126           // annotation, then annotate the function here.
3127           injector.annotate(blockFns[i]);
3128         }
3129         try {
3130           injector.invoke(blockFns[i] || angular.noop, this);
3131         } catch (e) {
3132           if (e.stack && errorForStack) {
3133             throw new ErrorAddingDeclarationLocationStack(e, errorForStack);
3134           }
3135           throw e;
3136         } finally {
3137           errorForStack = null;
3138         }
3139       }
3140     }
3141   };
3142
3143
3144   angular.mock.inject.strictDi = function(value) {
3145     value = arguments.length ? !!value : true;
3146     return wasInjectorCreated() ? workFn() : workFn;
3147
3148     function workFn() {
3149       if (value !== currentSpec.$injectorStrict) {
3150         if (currentSpec.$injector) {
3151           throw new Error('Injector already created, can not modify strict annotations');
3152         } else {
3153           currentSpec.$injectorStrict = value;
3154         }
3155       }
3156     }
3157   };
3158
3159   function InjectorState() {
3160     this.shared = false;
3161     this.sharedError = null;
3162
3163     this.cleanupAfterEach = function() {
3164       return !this.shared || this.sharedError;
3165     };
3166   }
3167 })(window.jasmine || window.mocha);
3168
3169
3170 })(window, window.angular);