source: cats/SCHEMAcat/trunk/urn.org.isocat.schemacat.site/site/test/lib/AngularJS-1.2.5/angular-mocks.js @ 4192

Last change on this file since 4192 was 4192, checked in by andmor, 10 years ago

Updated to AngularJS 1.2.5

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