2 * @license AngularJS v1.3.15
3 * (c) 2010-2014 Google, Inc. http://angularjs.org
6 (function(window, angular, undefined) {
15 * Namespace from 'angular-mocks.js' which contains testing related code.
20 * ! This is a private undocumented service !
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,
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.
32 angular.mock.$BrowserProvider = function() {
33 this.$get = function() {
34 return new angular.mock.$Browser();
38 angular.mock.$Browser = function() {
42 self.$$url = "http://server/";
43 self.$$lastUrl = self.$$url; // used by url polling fn
46 // TODO(vojta): remove this temporary api
47 self.$$completeOutstandingRequest = angular.noop;
48 self.$$incOutstandingRequestCount = angular.noop;
51 // register url polling fn
53 self.onUrlChange = function(listener) {
56 if (self.$$lastUrl !== self.$$url || self.$$state !== self.$$lastState) {
57 self.$$lastUrl = self.$$url;
58 self.$$lastState = self.$$state;
59 listener(self.$$url, self.$$state);
67 self.$$checkUrlChange = angular.noop;
70 self.lastCookieHash = {};
71 self.deferredFns = [];
72 self.deferredNextId = 0;
74 self.defer = function(fn, delay) {
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++;
83 * @name $browser#defer.now
86 * Current milliseconds mock time.
91 self.defer.cancel = function(deferId) {
94 angular.forEach(self.deferredFns, function(fn, index) {
95 if (fn.id === deferId) fnIndex = index;
98 if (fnIndex !== undefined) {
99 self.deferredFns.splice(fnIndex, 1);
108 * @name $browser#defer.flush
111 * Flushes all pending requests and executes the defer callbacks.
113 * @param {number=} number of milliseconds to flush. See {@link #defer.now}
115 self.defer.flush = function(delay) {
116 if (angular.isDefined(delay)) {
117 self.defer.now += delay;
119 if (self.deferredFns.length) {
120 self.defer.now = self.deferredFns[self.deferredFns.length - 1].time;
122 throw new Error('No deferred tasks to be flushed');
126 while (self.deferredFns.length && self.deferredFns[0].time <= self.defer.now) {
127 self.deferredFns.shift().fn();
131 self.$$baseHref = '/';
132 self.baseHref = function() {
133 return this.$$baseHref;
136 angular.mock.$Browser.prototype = {
139 * @name $browser#poll
142 * run all fns in pollFns
144 poll: function poll() {
145 angular.forEach(this.pollFns, function(pollFn) {
150 addPollFn: function(pollFn) {
151 this.pollFns.push(pollFn);
155 url: function(url, replace, state) {
156 if (angular.isUndefined(state)) {
161 // Native pushState serializes & copies the object; simulate it.
162 this.$$state = angular.copy(state);
173 cookies: function(name, value) {
175 if (angular.isUndefined(value)) {
176 delete this.cookieHash[name];
178 if (angular.isString(value) && //strings only
179 value.length <= 4096) { //strict cookie storage limits
180 this.cookieHash[name] = value;
184 if (!angular.equals(this.cookieHash, this.lastCookieHash)) {
185 this.lastCookieHash = angular.copy(this.cookieHash);
186 this.cookieHash = angular.copy(this.cookieHash);
188 return this.cookieHash;
192 notifyWhenNoOutstandingRequests: function(fn) {
200 * @name $exceptionHandlerProvider
203 * Configures the mock implementation of {@link ng.$exceptionHandler} to rethrow or to log errors
204 * passed to the `$exceptionHandler`.
209 * @name $exceptionHandler
212 * Mock implementation of {@link ng.$exceptionHandler} that rethrows or logs errors passed
213 * to it. See {@link ngMock.$exceptionHandlerProvider $exceptionHandlerProvider} for configuration
218 * describe('$exceptionHandlerProvider', function() {
220 * it('should capture log messages and exceptions', function() {
222 * module(function($exceptionHandlerProvider) {
223 * $exceptionHandlerProvider.mode('log');
226 * inject(function($log, $exceptionHandler, $timeout) {
227 * $timeout(function() { $log.log(1); });
228 * $timeout(function() { $log.log(2); throw 'banana peel'; });
229 * $timeout(function() { $log.log(3); });
230 * expect($exceptionHandler.errors).toEqual([]);
231 * expect($log.assertEmpty());
233 * expect($exceptionHandler.errors).toEqual(['banana peel']);
234 * expect($log.log.logs).toEqual([[1], [2], [3]]);
241 angular.mock.$ExceptionHandlerProvider = function() {
246 * @name $exceptionHandlerProvider#mode
249 * Sets the logging mode.
251 * @param {string} mode Mode of operation, defaults to `rethrow`.
253 * - `log`: Sometimes it is desirable to test that an error is thrown, for this case the `log`
254 * mode stores an array of errors in `$exceptionHandler.errors`, to allow later
255 * assertion of them. See {@link ngMock.$log#assertEmpty assertEmpty()} and
256 * {@link ngMock.$log#reset reset()}
257 * - `rethrow`: If any errors are passed to the handler in tests, it typically means that there
258 * is a bug in the application or test, so this mock will make these tests fail.
259 * For any implementations that expect exceptions to be thrown, the `rethrow` mode
260 * will also maintain a log of thrown errors.
262 this.mode = function(mode) {
268 handler = function(e) {
269 if (arguments.length == 1) {
272 errors.push([].slice.call(arguments, 0));
274 if (mode === "rethrow") {
278 handler.errors = errors;
281 throw new Error("Unknown mode '" + mode + "', only 'log'/'rethrow' modes are allowed!");
285 this.$get = function() {
289 this.mode('rethrow');
298 * Mock implementation of {@link ng.$log} that gathers all logged messages in arrays
299 * (one array per logging level). These arrays are exposed as `logs` property of each of the
300 * level-specific log function, e.g. for level `error` the array is exposed as `$log.error.logs`.
303 angular.mock.$LogProvider = function() {
306 function concat(array1, array2, index) {
307 return array1.concat(Array.prototype.slice.call(array2, index));
310 this.debugEnabled = function(flag) {
311 if (angular.isDefined(flag)) {
319 this.$get = function() {
321 log: function() { $log.log.logs.push(concat([], arguments, 0)); },
322 warn: function() { $log.warn.logs.push(concat([], arguments, 0)); },
323 info: function() { $log.info.logs.push(concat([], arguments, 0)); },
324 error: function() { $log.error.logs.push(concat([], arguments, 0)); },
327 $log.debug.logs.push(concat([], arguments, 0));
337 * Reset all of the logging arrays to empty.
339 $log.reset = function() {
342 * @name $log#log.logs
345 * Array of messages logged using {@link ng.$log#log `log()`}.
349 * $log.log('Some Log');
350 * var first = $log.log.logs.unshift();
356 * @name $log#info.logs
359 * Array of messages logged using {@link ng.$log#info `info()`}.
363 * $log.info('Some Info');
364 * var first = $log.info.logs.unshift();
370 * @name $log#warn.logs
373 * Array of messages logged using {@link ng.$log#warn `warn()`}.
377 * $log.warn('Some Warning');
378 * var first = $log.warn.logs.unshift();
384 * @name $log#error.logs
387 * Array of messages logged using {@link ng.$log#error `error()`}.
391 * $log.error('Some Error');
392 * var first = $log.error.logs.unshift();
395 $log.error.logs = [];
398 * @name $log#debug.logs
401 * Array of messages logged using {@link ng.$log#debug `debug()`}.
405 * $log.debug('Some Error');
406 * var first = $log.debug.logs.unshift();
409 $log.debug.logs = [];
414 * @name $log#assertEmpty
417 * Assert that all of the logging methods have no logged messages. If any messages are present,
418 * an exception is thrown.
420 $log.assertEmpty = function() {
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 || ''));
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:");
434 throw new Error(errors.join('\n---------\n'));
449 * Mock implementation of the $interval service.
451 * Use {@link ngMock.$interval#flush `$interval.flush(millis)`} to
452 * move forward by `millis` milliseconds and trigger any functions scheduled to run in that
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
459 * @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise
460 * will invoke `fn` within the {@link ng.$rootScope.Scope#$apply $apply} block.
461 * @returns {promise} A promise which will be notified on each iteration.
463 angular.mock.$IntervalProvider = function() {
464 this.$get = ['$browser', '$rootScope', '$q', '$$q',
465 function($browser, $rootScope, $q, $$q) {
470 var $interval = function(fn, delay, count, invokeApply) {
472 skipApply = (angular.isDefined(invokeApply) && !invokeApply),
473 deferred = (skipApply ? $$q : $q).defer(),
474 promise = deferred.promise;
476 count = (angular.isDefined(count)) ? count : 0;
477 promise.then(null, null, fn);
479 promise.$$intervalId = nextRepeatId;
482 deferred.notify(iteration++);
484 if (count > 0 && iteration >= count) {
486 deferred.resolve(iteration);
488 angular.forEach(repeatFns, function(fn, index) {
489 if (fn.id === promise.$$intervalId) fnIndex = index;
492 if (fnIndex !== undefined) {
493 repeatFns.splice(fnIndex, 1);
498 $browser.defer.flush();
505 nextTime:(now + delay),
511 repeatFns.sort(function(a, b) { return a.nextTime - b.nextTime;});
518 * @name $interval#cancel
521 * Cancels a task associated with the `promise`.
523 * @param {promise} promise A promise from calling the `$interval` function.
524 * @returns {boolean} Returns `true` if the task was successfully cancelled.
526 $interval.cancel = function(promise) {
527 if (!promise) return false;
530 angular.forEach(repeatFns, function(fn, index) {
531 if (fn.id === promise.$$intervalId) fnIndex = index;
534 if (fnIndex !== undefined) {
535 repeatFns[fnIndex].deferred.reject('canceled');
536 repeatFns.splice(fnIndex, 1);
545 * @name $interval#flush
548 * Runs interval tasks scheduled to be run in the next `millis` milliseconds.
550 * @param {number=} millis maximum timeout amount to flush up until.
552 * @return {number} The amount of time moved forward.
554 $interval.flush = function(millis) {
556 while (repeatFns.length && repeatFns[0].nextTime <= now) {
557 var task = repeatFns[0];
559 task.nextTime += task.delay;
560 repeatFns.sort(function(a, b) { return a.nextTime - b.nextTime;});
571 /* The R_ISO8061_STR regex is never going to fit into the 100 char limit!
572 * This directive should go inside the anonymous function but a bug in JSHint means that it would
573 * not be enacted early enough to prevent the warning.
575 var R_ISO8061_STR = /^(\d{4})-?(\d\d)-?(\d\d)(?:T(\d\d)(?:\:?(\d\d)(?:\:?(\d\d)(?:\.(\d{3}))?)?)?(Z|([+-])(\d\d):?(\d\d)))?$/;
577 function jsonStringToDate(string) {
579 if (match = string.match(R_ISO8061_STR)) {
580 var date = new Date(0),
584 tzHour = int(match[9] + match[10]);
585 tzMin = int(match[9] + match[11]);
587 date.setUTCFullYear(int(match[1]), int(match[2]) - 1, int(match[3]));
588 date.setUTCHours(int(match[4] || 0) - tzHour,
589 int(match[5] || 0) - tzMin,
598 return parseInt(str, 10);
601 function padNumber(num, digits, trim) {
608 while (num.length < digits) num = '0' + num;
610 num = num.substr(num.length - digits);
617 * @name angular.mock.TzDate
620 * *NOTE*: this is not an injectable instance, just a globally available mock class of `Date`.
622 * Mock of the Date type which has its timezone specified via constructor arg.
624 * The main purpose is to create Date-like instances with timezone fixed to the specified timezone
625 * offset, so that we can test code that depends on local timezone settings without dependency on
626 * the time zone settings of the machine where the code is running.
628 * @param {number} offset Offset of the *desired* timezone in hours (fractions will be honored)
629 * @param {(number|string)} timestamp Timestamp representing the desired time in *UTC*
633 * This is not a complete Date object so only methods that were implemented can be called safely.
634 * To make matters worse, TzDate instances inherit stuff from Date via a prototype.
636 * We do our best to intercept calls to "unimplemented" methods, but since the list of methods is
637 * incomplete we might be missing some non-standard methods. This can result in errors like:
638 * "Date.prototype.foo called on incompatible Object".
641 * var newYearInBratislava = new TzDate(-1, '2009-12-31T23:00:00Z');
642 * newYearInBratislava.getTimezoneOffset() => -60;
643 * newYearInBratislava.getFullYear() => 2010;
644 * newYearInBratislava.getMonth() => 0;
645 * newYearInBratislava.getDate() => 1;
646 * newYearInBratislava.getHours() => 0;
647 * newYearInBratislava.getMinutes() => 0;
648 * newYearInBratislava.getSeconds() => 0;
652 angular.mock.TzDate = function(offset, timestamp) {
653 var self = new Date(0);
654 if (angular.isString(timestamp)) {
655 var tsStr = timestamp;
657 self.origDate = jsonStringToDate(timestamp);
659 timestamp = self.origDate.getTime();
660 if (isNaN(timestamp))
662 name: "Illegal Argument",
663 message: "Arg '" + tsStr + "' passed into TzDate constructor is not a valid date string"
666 self.origDate = new Date(timestamp);
669 var localOffset = new Date(timestamp).getTimezoneOffset();
670 self.offsetDiff = localOffset * 60 * 1000 - offset * 1000 * 60 * 60;
671 self.date = new Date(timestamp + self.offsetDiff);
673 self.getTime = function() {
674 return self.date.getTime() - self.offsetDiff;
677 self.toLocaleDateString = function() {
678 return self.date.toLocaleDateString();
681 self.getFullYear = function() {
682 return self.date.getFullYear();
685 self.getMonth = function() {
686 return self.date.getMonth();
689 self.getDate = function() {
690 return self.date.getDate();
693 self.getHours = function() {
694 return self.date.getHours();
697 self.getMinutes = function() {
698 return self.date.getMinutes();
701 self.getSeconds = function() {
702 return self.date.getSeconds();
705 self.getMilliseconds = function() {
706 return self.date.getMilliseconds();
709 self.getTimezoneOffset = function() {
713 self.getUTCFullYear = function() {
714 return self.origDate.getUTCFullYear();
717 self.getUTCMonth = function() {
718 return self.origDate.getUTCMonth();
721 self.getUTCDate = function() {
722 return self.origDate.getUTCDate();
725 self.getUTCHours = function() {
726 return self.origDate.getUTCHours();
729 self.getUTCMinutes = function() {
730 return self.origDate.getUTCMinutes();
733 self.getUTCSeconds = function() {
734 return self.origDate.getUTCSeconds();
737 self.getUTCMilliseconds = function() {
738 return self.origDate.getUTCMilliseconds();
741 self.getDay = function() {
742 return self.date.getDay();
745 // provide this method only on browsers that already have it
746 if (self.toISOString) {
747 self.toISOString = function() {
748 return padNumber(self.origDate.getUTCFullYear(), 4) + '-' +
749 padNumber(self.origDate.getUTCMonth() + 1, 2) + '-' +
750 padNumber(self.origDate.getUTCDate(), 2) + 'T' +
751 padNumber(self.origDate.getUTCHours(), 2) + ':' +
752 padNumber(self.origDate.getUTCMinutes(), 2) + ':' +
753 padNumber(self.origDate.getUTCSeconds(), 2) + '.' +
754 padNumber(self.origDate.getUTCMilliseconds(), 3) + 'Z';
758 //hide all methods not implemented in this mock that the Date prototype exposes
759 var unimplementedMethods = ['getUTCDay',
760 'getYear', 'setDate', 'setFullYear', 'setHours', 'setMilliseconds',
761 'setMinutes', 'setMonth', 'setSeconds', 'setTime', 'setUTCDate', 'setUTCFullYear',
762 'setUTCHours', 'setUTCMilliseconds', 'setUTCMinutes', 'setUTCMonth', 'setUTCSeconds',
763 'setYear', 'toDateString', 'toGMTString', 'toJSON', 'toLocaleFormat', 'toLocaleString',
764 'toLocaleTimeString', 'toSource', 'toString', 'toTimeString', 'toUTCString', 'valueOf'];
766 angular.forEach(unimplementedMethods, function(methodName) {
767 self[methodName] = function() {
768 throw new Error("Method '" + methodName + "' is not implemented in the TzDate mock");
775 //make "tzDateInstance instanceof Date" return true
776 angular.mock.TzDate.prototype = Date.prototype;
779 angular.mock.animate = angular.module('ngAnimateMock', ['ng'])
781 .config(['$provide', function($provide) {
783 var reflowQueue = [];
784 $provide.value('$$animateReflow', function(fn) {
785 var index = reflowQueue.length;
786 reflowQueue.push(fn);
787 return function cancel() {
788 reflowQueue.splice(index, 1);
792 $provide.decorator('$animate', ['$delegate', '$$asyncCallback', '$timeout', '$browser',
793 function($delegate, $$asyncCallback, $timeout, $browser) {
796 cancel: $delegate.cancel,
797 enabled: $delegate.enabled,
798 triggerCallbackEvents: function() {
799 $$asyncCallback.flush();
801 triggerCallbackPromise: function() {
804 triggerCallbacks: function() {
805 this.triggerCallbackEvents();
806 this.triggerCallbackPromise();
808 triggerReflow: function() {
809 angular.forEach(reflowQueue, function(fn) {
817 ['animate','enter','leave','move','addClass','removeClass','setClass'], function(method) {
818 animate[method] = function() {
821 element: arguments[0],
822 options: arguments[arguments.length - 1],
825 return $delegate[method].apply($delegate, arguments);
837 * @name angular.mock.dump
840 * *NOTE*: this is not an injectable instance, just a globally available function.
842 * Method for serializing common angular objects (scope, elements, etc..) into strings, useful for
845 * This method is also available on window, where it can be used to display objects on debug
848 * @param {*} object - any object to turn into string.
849 * @return {string} a serialized string of the argument
851 angular.mock.dump = function(object) {
852 return serialize(object);
854 function serialize(object) {
857 if (angular.isElement(object)) {
858 object = angular.element(object);
859 out = angular.element('<div></div>');
860 angular.forEach(object, function(element) {
861 out.append(angular.element(element).clone());
864 } else if (angular.isArray(object)) {
866 angular.forEach(object, function(o) {
867 out.push(serialize(o));
869 out = '[ ' + out.join(', ') + ' ]';
870 } else if (angular.isObject(object)) {
871 if (angular.isFunction(object.$eval) && angular.isFunction(object.$apply)) {
872 out = serializeScope(object);
873 } else if (object instanceof Error) {
874 out = object.stack || ('' + object.name + ': ' + object.message);
876 // TODO(i): this prevents methods being logged,
877 // we should have a better way to serialize objects
878 out = angular.toJson(object, true);
881 out = String(object);
887 function serializeScope(scope, offset) {
888 offset = offset || ' ';
889 var log = [offset + 'Scope(' + scope.$id + '): {'];
890 for (var key in scope) {
891 if (Object.prototype.hasOwnProperty.call(scope, key) && !key.match(/^(\$|this)/)) {
892 log.push(' ' + key + ': ' + angular.toJson(scope[key]));
895 var child = scope.$$childHead;
897 log.push(serializeScope(child, offset + ' '));
898 child = child.$$nextSibling;
901 return log.join('\n' + offset);
909 * Fake HTTP backend implementation suitable for unit testing applications that use the
910 * {@link ng.$http $http service}.
912 * *Note*: For fake HTTP backend implementation suitable for end-to-end testing or backend-less
913 * development please see {@link ngMockE2E.$httpBackend e2e $httpBackend mock}.
915 * During unit testing, we want our unit tests to run quickly and have no external dependencies so
916 * we don’t want to send [XHR](https://developer.mozilla.org/en/xmlhttprequest) or
917 * [JSONP](http://en.wikipedia.org/wiki/JSONP) requests to a real server. All we really need is
918 * to verify whether a certain request has been sent or not, or alternatively just let the
919 * application make requests, respond with pre-trained responses and assert that the end result is
920 * what we expect it to be.
922 * This mock implementation can be used to respond with static or dynamic responses via the
923 * `expect` and `when` apis and their shortcuts (`expectGET`, `whenPOST`, etc).
925 * When an Angular application needs some data from a server, it calls the $http service, which
926 * sends the request to a real server using $httpBackend service. With dependency injection, it is
927 * easy to inject $httpBackend mock (which has the same API as $httpBackend) and use it to verify
928 * the requests and respond with some testing data without sending a request to a real server.
930 * There are two ways to specify what test data should be returned as http responses by the mock
931 * backend when the code under test makes http requests:
933 * - `$httpBackend.expect` - specifies a request expectation
934 * - `$httpBackend.when` - specifies a backend definition
937 * # Request Expectations vs Backend Definitions
939 * Request expectations provide a way to make assertions about requests made by the application and
940 * to define responses for those requests. The test will fail if the expected requests are not made
941 * or they are made in the wrong order.
943 * Backend definitions allow you to define a fake backend for your application which doesn't assert
944 * if a particular request was made or not, it just returns a trained response if a request is made.
945 * The test will pass whether or not the request gets made during testing.
948 * <table class="table">
949 * <tr><th width="220px"></th><th>Request expectations</th><th>Backend definitions</th></tr>
952 * <td>.expect(...).respond(...)</td>
953 * <td>.when(...).respond(...)</td>
956 * <th>Typical usage</th>
957 * <td>strict unit tests</td>
958 * <td>loose (black-box) unit testing</td>
961 * <th>Fulfills multiple requests</th>
966 * <th>Order of requests matters</th>
971 * <th>Request required</th>
976 * <th>Response required</th>
977 * <td>optional (see below)</td>
982 * In cases where both backend definitions and request expectations are specified during unit
983 * testing, the request expectations are evaluated first.
985 * If a request expectation has no response specified, the algorithm will search your backend
986 * definitions for an appropriate response.
988 * If a request didn't match any expectation or if the expectation doesn't have the response
989 * defined, the backend definitions are evaluated in sequential order to see if any of them match
990 * the request. The response from the first matched definition is returned.
993 * # Flushing HTTP requests
995 * The $httpBackend used in production always responds to requests asynchronously. If we preserved
996 * this behavior in unit testing, we'd have to create async unit tests, which are hard to write,
997 * to follow and to maintain. But neither can the testing mock respond synchronously; that would
998 * change the execution of the code under test. For this reason, the mock $httpBackend has a
999 * `flush()` method, which allows the test to explicitly flush pending requests. This preserves
1000 * the async api of the backend, while allowing the test to execute synchronously.
1003 * # Unit testing with mock $httpBackend
1004 * The following code shows how to setup and use the mock backend when unit testing a controller.
1005 * First we create the controller under test:
1010 .module('MyApp', [])
1011 .controller('MyController', MyController);
1013 // The controller code
1014 function MyController($scope, $http) {
1017 $http.get('/auth.py').success(function(data, status, headers) {
1018 authToken = headers('A-Token');
1022 $scope.saveMessage = function(message) {
1023 var headers = { 'Authorization': authToken };
1024 $scope.status = 'Saving...';
1026 $http.post('/add-msg.py', message, { headers: headers } ).success(function(response) {
1028 }).error(function() {
1029 $scope.status = 'ERROR!';
1035 * Now we setup the mock backend and create the test specs:
1038 // testing controller
1039 describe('MyController', function() {
1040 var $httpBackend, $rootScope, createController, authRequestHandler;
1042 // Set up the module
1043 beforeEach(module('MyApp'));
1045 beforeEach(inject(function($injector) {
1046 // Set up the mock http service responses
1047 $httpBackend = $injector.get('$httpBackend');
1048 // backend definition common for all tests
1049 authRequestHandler = $httpBackend.when('GET', '/auth.py')
1050 .respond({userId: 'userX'}, {'A-Token': 'xxx'});
1052 // Get hold of a scope (i.e. the root scope)
1053 $rootScope = $injector.get('$rootScope');
1054 // The $controller service is used to create instances of controllers
1055 var $controller = $injector.get('$controller');
1057 createController = function() {
1058 return $controller('MyController', {'$scope' : $rootScope });
1063 afterEach(function() {
1064 $httpBackend.verifyNoOutstandingExpectation();
1065 $httpBackend.verifyNoOutstandingRequest();
1069 it('should fetch authentication token', function() {
1070 $httpBackend.expectGET('/auth.py');
1071 var controller = createController();
1072 $httpBackend.flush();
1076 it('should fail authentication', function() {
1078 // Notice how you can change the response even after it was set
1079 authRequestHandler.respond(401, '');
1081 $httpBackend.expectGET('/auth.py');
1082 var controller = createController();
1083 $httpBackend.flush();
1084 expect($rootScope.status).toBe('Failed...');
1088 it('should send msg to server', function() {
1089 var controller = createController();
1090 $httpBackend.flush();
1092 // now you don’t care about the authentication, but
1093 // the controller will still send the request and
1094 // $httpBackend will respond without you having to
1095 // specify the expectation and response for this request
1097 $httpBackend.expectPOST('/add-msg.py', 'message content').respond(201, '');
1098 $rootScope.saveMessage('message content');
1099 expect($rootScope.status).toBe('Saving...');
1100 $httpBackend.flush();
1101 expect($rootScope.status).toBe('');
1105 it('should send auth header', function() {
1106 var controller = createController();
1107 $httpBackend.flush();
1109 $httpBackend.expectPOST('/add-msg.py', undefined, function(headers) {
1110 // check if the header was send, if it wasn't the expectation won't
1111 // match the request and the test will fail
1112 return headers['Authorization'] == 'xxx';
1113 }).respond(201, '');
1115 $rootScope.saveMessage('whatever');
1116 $httpBackend.flush();
1121 angular.mock.$HttpBackendProvider = function() {
1122 this.$get = ['$rootScope', '$timeout', createHttpBackendMock];
1126 * General factory function for $httpBackend mock.
1127 * Returns instance for unit testing (when no arguments specified):
1128 * - passing through is disabled
1129 * - auto flushing is disabled
1131 * Returns instance for e2e testing (when `$delegate` and `$browser` specified):
1132 * - passing through (delegating request to real backend) is enabled
1133 * - auto flushing is enabled
1135 * @param {Object=} $delegate Real $httpBackend instance (allow passing through if specified)
1136 * @param {Object=} $browser Auto-flushing enabled if specified
1137 * @return {Object} Instance of $httpBackend mock
1139 function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) {
1140 var definitions = [],
1143 responsesPush = angular.bind(responses, responses.push),
1144 copy = angular.copy;
1146 function createResponse(status, data, headers, statusText) {
1147 if (angular.isFunction(status)) return status;
1150 return angular.isNumber(status)
1151 ? [status, data, headers, statusText]
1152 : [200, status, data, headers];
1156 // TODO(vojta): change params to: method, url, data, headers, callback
1157 function $httpBackend(method, url, data, callback, headers, timeout, withCredentials) {
1158 var xhr = new MockXhr(),
1159 expectation = expectations[0],
1160 wasExpected = false;
1162 function prettyPrint(data) {
1163 return (angular.isString(data) || angular.isFunction(data) || data instanceof RegExp)
1165 : angular.toJson(data);
1168 function wrapResponse(wrapped) {
1169 if (!$browser && timeout) {
1170 timeout.then ? timeout.then(handleTimeout) : $timeout(handleTimeout, timeout);
1173 return handleResponse;
1175 function handleResponse() {
1176 var response = wrapped.response(method, url, data, headers);
1177 xhr.$$respHeaders = response[2];
1178 callback(copy(response[0]), copy(response[1]), xhr.getAllResponseHeaders(),
1179 copy(response[3] || ''));
1182 function handleTimeout() {
1183 for (var i = 0, ii = responses.length; i < ii; i++) {
1184 if (responses[i] === handleResponse) {
1185 responses.splice(i, 1);
1186 callback(-1, undefined, '');
1193 if (expectation && expectation.match(method, url)) {
1194 if (!expectation.matchData(data))
1195 throw new Error('Expected ' + expectation + ' with different data\n' +
1196 'EXPECTED: ' + prettyPrint(expectation.data) + '\nGOT: ' + data);
1198 if (!expectation.matchHeaders(headers))
1199 throw new Error('Expected ' + expectation + ' with different headers\n' +
1200 'EXPECTED: ' + prettyPrint(expectation.headers) + '\nGOT: ' +
1201 prettyPrint(headers));
1203 expectations.shift();
1205 if (expectation.response) {
1206 responses.push(wrapResponse(expectation));
1212 var i = -1, definition;
1213 while ((definition = definitions[++i])) {
1214 if (definition.match(method, url, data, headers || {})) {
1215 if (definition.response) {
1216 // if $browser specified, we do auto flush all requests
1217 ($browser ? $browser.defer : responsesPush)(wrapResponse(definition));
1218 } else if (definition.passThrough) {
1219 $delegate(method, url, data, callback, headers, timeout, withCredentials);
1220 } else throw new Error('No response defined !');
1225 new Error('No response defined !') :
1226 new Error('Unexpected request: ' + method + ' ' + url + '\n' +
1227 (expectation ? 'Expected ' + expectation : 'No more request expected'));
1232 * @name $httpBackend#when
1234 * Creates a new backend definition.
1236 * @param {string} method HTTP method.
1237 * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
1238 * and returns true if the url match the current definition.
1239 * @param {(string|RegExp|function(string))=} data HTTP request body or function that receives
1240 * data string and returns true if the data is as expected.
1241 * @param {(Object|function(Object))=} headers HTTP headers or function that receives http header
1242 * object and returns true if the headers match the current definition.
1243 * @returns {requestHandler} Returns an object with `respond` method that controls how a matched
1244 * request is handled. You can save this object for later use and invoke `respond` again in
1245 * order to change how a matched request is handled.
1248 * `{function([status,] data[, headers, statusText])
1249 * | function(function(method, url, data, headers)}`
1250 * – The respond method takes a set of static data to be returned or a function that can
1251 * return an array containing response status (number), response data (string), response
1252 * headers (Object), and the text for the status (string). The respond method returns the
1253 * `requestHandler` object for possible overrides.
1255 $httpBackend.when = function(method, url, data, headers) {
1256 var definition = new MockHttpExpectation(method, url, data, headers),
1258 respond: function(status, data, headers, statusText) {
1259 definition.passThrough = undefined;
1260 definition.response = createResponse(status, data, headers, statusText);
1266 chain.passThrough = function() {
1267 definition.response = undefined;
1268 definition.passThrough = true;
1273 definitions.push(definition);
1279 * @name $httpBackend#whenGET
1281 * Creates a new backend definition for GET requests. For more info see `when()`.
1283 * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
1284 * and returns true if the url match the current definition.
1285 * @param {(Object|function(Object))=} headers HTTP headers.
1286 * @returns {requestHandler} Returns an object with `respond` method that controls how a matched
1287 * request is handled. You can save this object for later use and invoke `respond` again in
1288 * order to change how a matched request is handled.
1293 * @name $httpBackend#whenHEAD
1295 * Creates a new backend definition for HEAD requests. For more info see `when()`.
1297 * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
1298 * and returns true if the url match the current definition.
1299 * @param {(Object|function(Object))=} headers HTTP headers.
1300 * @returns {requestHandler} Returns an object with `respond` method that controls how a matched
1301 * request is handled. You can save this object for later use and invoke `respond` again in
1302 * order to change how a matched request is handled.
1307 * @name $httpBackend#whenDELETE
1309 * Creates a new backend definition for DELETE requests. For more info see `when()`.
1311 * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
1312 * and returns true if the url match the current definition.
1313 * @param {(Object|function(Object))=} headers HTTP headers.
1314 * @returns {requestHandler} Returns an object with `respond` method that controls how a matched
1315 * request is handled. You can save this object for later use and invoke `respond` again in
1316 * order to change how a matched request is handled.
1321 * @name $httpBackend#whenPOST
1323 * Creates a new backend definition for POST requests. For more info see `when()`.
1325 * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
1326 * and returns true if the url match the current definition.
1327 * @param {(string|RegExp|function(string))=} data HTTP request body or function that receives
1328 * data string and returns true if the data is as expected.
1329 * @param {(Object|function(Object))=} headers HTTP headers.
1330 * @returns {requestHandler} Returns an object with `respond` method that controls how a matched
1331 * request is handled. You can save this object for later use and invoke `respond` again in
1332 * order to change how a matched request is handled.
1337 * @name $httpBackend#whenPUT
1339 * Creates a new backend definition for PUT requests. For more info see `when()`.
1341 * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
1342 * and returns true if the url match the current definition.
1343 * @param {(string|RegExp|function(string))=} data HTTP request body or function that receives
1344 * data string and returns true if the data is as expected.
1345 * @param {(Object|function(Object))=} headers HTTP headers.
1346 * @returns {requestHandler} Returns an object with `respond` method that controls how a matched
1347 * request is handled. You can save this object for later use and invoke `respond` again in
1348 * order to change how a matched request is handled.
1353 * @name $httpBackend#whenJSONP
1355 * Creates a new backend definition for JSONP requests. For more info see `when()`.
1357 * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
1358 * and returns true if the url match the current definition.
1359 * @returns {requestHandler} Returns an object with `respond` method that controls how a matched
1360 * request is handled. You can save this object for later use and invoke `respond` again in
1361 * order to change how a matched request is handled.
1363 createShortMethods('when');
1368 * @name $httpBackend#expect
1370 * Creates a new request expectation.
1372 * @param {string} method HTTP method.
1373 * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
1374 * and returns true if the url match the current definition.
1375 * @param {(string|RegExp|function(string)|Object)=} data HTTP request body or function that
1376 * receives data string and returns true if the data is as expected, or Object if request body
1377 * is in JSON format.
1378 * @param {(Object|function(Object))=} headers HTTP headers or function that receives http header
1379 * object and returns true if the headers match the current expectation.
1380 * @returns {requestHandler} Returns an object with `respond` method that controls how a matched
1381 * request is handled. You can save this object for later use and invoke `respond` again in
1382 * order to change how a matched request is handled.
1385 * `{function([status,] data[, headers, statusText])
1386 * | function(function(method, url, data, headers)}`
1387 * – The respond method takes a set of static data to be returned or a function that can
1388 * return an array containing response status (number), response data (string), response
1389 * headers (Object), and the text for the status (string). The respond method returns the
1390 * `requestHandler` object for possible overrides.
1392 $httpBackend.expect = function(method, url, data, headers) {
1393 var expectation = new MockHttpExpectation(method, url, data, headers),
1395 respond: function(status, data, headers, statusText) {
1396 expectation.response = createResponse(status, data, headers, statusText);
1401 expectations.push(expectation);
1408 * @name $httpBackend#expectGET
1410 * Creates a new request expectation for GET requests. For more info see `expect()`.
1412 * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
1413 * and returns true if the url match the current definition.
1414 * @param {Object=} headers HTTP headers.
1415 * @returns {requestHandler} Returns an object with `respond` method that controls how a matched
1416 * request is handled. You can save this object for later use and invoke `respond` again in
1417 * order to change how a matched request is handled. See #expect for more info.
1422 * @name $httpBackend#expectHEAD
1424 * Creates a new request expectation for HEAD requests. For more info see `expect()`.
1426 * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
1427 * and returns true if the url match the current definition.
1428 * @param {Object=} headers HTTP headers.
1429 * @returns {requestHandler} Returns an object with `respond` method that controls how a matched
1430 * request is handled. You can save this object for later use and invoke `respond` again in
1431 * order to change how a matched request is handled.
1436 * @name $httpBackend#expectDELETE
1438 * Creates a new request expectation for DELETE requests. For more info see `expect()`.
1440 * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
1441 * and returns true if the url match the current definition.
1442 * @param {Object=} headers HTTP headers.
1443 * @returns {requestHandler} Returns an object with `respond` method that controls how a matched
1444 * request is handled. You can save this object for later use and invoke `respond` again in
1445 * order to change how a matched request is handled.
1450 * @name $httpBackend#expectPOST
1452 * Creates a new request expectation for POST requests. For more info see `expect()`.
1454 * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
1455 * and returns true if the url match the current definition.
1456 * @param {(string|RegExp|function(string)|Object)=} data HTTP request body or function that
1457 * receives data string and returns true if the data is as expected, or Object if request body
1458 * is in JSON format.
1459 * @param {Object=} headers HTTP headers.
1460 * @returns {requestHandler} Returns an object with `respond` method that controls how a matched
1461 * request is handled. You can save this object for later use and invoke `respond` again in
1462 * order to change how a matched request is handled.
1467 * @name $httpBackend#expectPUT
1469 * Creates a new request expectation for PUT requests. For more info see `expect()`.
1471 * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
1472 * and returns true if the url match the current definition.
1473 * @param {(string|RegExp|function(string)|Object)=} data HTTP request body or function that
1474 * receives data string and returns true if the data is as expected, or Object if request body
1475 * is in JSON format.
1476 * @param {Object=} headers HTTP headers.
1477 * @returns {requestHandler} Returns an object with `respond` method that controls how a matched
1478 * request is handled. You can save this object for later use and invoke `respond` again in
1479 * order to change how a matched request is handled.
1484 * @name $httpBackend#expectPATCH
1486 * Creates a new request expectation for PATCH requests. For more info see `expect()`.
1488 * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
1489 * and returns true if the url match the current definition.
1490 * @param {(string|RegExp|function(string)|Object)=} data HTTP request body or function that
1491 * receives data string and returns true if the data is as expected, or Object if request body
1492 * is in JSON format.
1493 * @param {Object=} headers HTTP headers.
1494 * @returns {requestHandler} Returns an object with `respond` method that controls how a matched
1495 * request is handled. You can save this object for later use and invoke `respond` again in
1496 * order to change how a matched request is handled.
1501 * @name $httpBackend#expectJSONP
1503 * Creates a new request expectation for JSONP requests. For more info see `expect()`.
1505 * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
1506 * and returns true if the url match the current definition.
1507 * @returns {requestHandler} Returns an object with `respond` method that controls how a matched
1508 * request is handled. You can save this object for later use and invoke `respond` again in
1509 * order to change how a matched request is handled.
1511 createShortMethods('expect');
1516 * @name $httpBackend#flush
1518 * Flushes all pending requests using the trained responses.
1520 * @param {number=} count Number of responses to flush (in the order they arrived). If undefined,
1521 * all pending requests will be flushed. If there are no pending requests when the flush method
1522 * is called an exception is thrown (as this typically a sign of programming error).
1524 $httpBackend.flush = function(count, digest) {
1525 if (digest !== false) $rootScope.$digest();
1526 if (!responses.length) throw new Error('No pending request to flush !');
1528 if (angular.isDefined(count) && count !== null) {
1530 if (!responses.length) throw new Error('No more pending request to flush !');
1531 responses.shift()();
1534 while (responses.length) {
1535 responses.shift()();
1538 $httpBackend.verifyNoOutstandingExpectation(digest);
1544 * @name $httpBackend#verifyNoOutstandingExpectation
1546 * Verifies that all of the requests defined via the `expect` api were made. If any of the
1547 * requests were not made, verifyNoOutstandingExpectation throws an exception.
1549 * Typically, you would call this method following each test case that asserts requests using an
1550 * "afterEach" clause.
1553 * afterEach($httpBackend.verifyNoOutstandingExpectation);
1556 $httpBackend.verifyNoOutstandingExpectation = function(digest) {
1557 if (digest !== false) $rootScope.$digest();
1558 if (expectations.length) {
1559 throw new Error('Unsatisfied requests: ' + expectations.join(', '));
1566 * @name $httpBackend#verifyNoOutstandingRequest
1568 * Verifies that there are no outstanding requests that need to be flushed.
1570 * Typically, you would call this method following each test case that asserts requests using an
1571 * "afterEach" clause.
1574 * afterEach($httpBackend.verifyNoOutstandingRequest);
1577 $httpBackend.verifyNoOutstandingRequest = function() {
1578 if (responses.length) {
1579 throw new Error('Unflushed requests: ' + responses.length);
1586 * @name $httpBackend#resetExpectations
1588 * Resets all request expectations, but preserves all backend definitions. Typically, you would
1589 * call resetExpectations during a multiple-phase test when you want to reuse the same instance of
1590 * $httpBackend mock.
1592 $httpBackend.resetExpectations = function() {
1593 expectations.length = 0;
1594 responses.length = 0;
1597 return $httpBackend;
1600 function createShortMethods(prefix) {
1601 angular.forEach(['GET', 'DELETE', 'JSONP', 'HEAD'], function(method) {
1602 $httpBackend[prefix + method] = function(url, headers) {
1603 return $httpBackend[prefix](method, url, undefined, headers);
1607 angular.forEach(['PUT', 'POST', 'PATCH'], function(method) {
1608 $httpBackend[prefix + method] = function(url, data, headers) {
1609 return $httpBackend[prefix](method, url, data, headers);
1615 function MockHttpExpectation(method, url, data, headers) {
1618 this.headers = headers;
1620 this.match = function(m, u, d, h) {
1621 if (method != m) return false;
1622 if (!this.matchUrl(u)) return false;
1623 if (angular.isDefined(d) && !this.matchData(d)) return false;
1624 if (angular.isDefined(h) && !this.matchHeaders(h)) return false;
1628 this.matchUrl = function(u) {
1629 if (!url) return true;
1630 if (angular.isFunction(url.test)) return url.test(u);
1631 if (angular.isFunction(url)) return url(u);
1635 this.matchHeaders = function(h) {
1636 if (angular.isUndefined(headers)) return true;
1637 if (angular.isFunction(headers)) return headers(h);
1638 return angular.equals(headers, h);
1641 this.matchData = function(d) {
1642 if (angular.isUndefined(data)) return true;
1643 if (data && angular.isFunction(data.test)) return data.test(d);
1644 if (data && angular.isFunction(data)) return data(d);
1645 if (data && !angular.isString(data)) {
1646 return angular.equals(angular.fromJson(angular.toJson(data)), angular.fromJson(d));
1651 this.toString = function() {
1652 return method + ' ' + url;
1656 function createMockXhr() {
1657 return new MockXhr();
1660 function MockXhr() {
1662 // hack for testing $http, $httpBackend
1663 MockXhr.$$lastInstance = this;
1665 this.open = function(method, url, async) {
1666 this.$$method = method;
1668 this.$$async = async;
1669 this.$$reqHeaders = {};
1670 this.$$respHeaders = {};
1673 this.send = function(data) {
1677 this.setRequestHeader = function(key, value) {
1678 this.$$reqHeaders[key] = value;
1681 this.getResponseHeader = function(name) {
1682 // the lookup must be case insensitive,
1683 // that's why we try two quick lookups first and full scan last
1684 var header = this.$$respHeaders[name];
1685 if (header) return header;
1687 name = angular.lowercase(name);
1688 header = this.$$respHeaders[name];
1689 if (header) return header;
1692 angular.forEach(this.$$respHeaders, function(headerVal, headerName) {
1693 if (!header && angular.lowercase(headerName) == name) header = headerVal;
1698 this.getAllResponseHeaders = function() {
1701 angular.forEach(this.$$respHeaders, function(value, key) {
1702 lines.push(key + ': ' + value);
1704 return lines.join('\n');
1707 this.abort = angular.noop;
1716 * This service is just a simple decorator for {@link ng.$timeout $timeout} service
1717 * that adds a "flush" and "verifyNoPendingTasks" methods.
1720 angular.mock.$TimeoutDecorator = ['$delegate', '$browser', function($delegate, $browser) {
1724 * @name $timeout#flush
1727 * Flushes the queue of pending tasks.
1729 * @param {number=} delay maximum timeout amount to flush up until
1731 $delegate.flush = function(delay) {
1732 $browser.defer.flush(delay);
1737 * @name $timeout#verifyNoPendingTasks
1740 * Verifies that there are no pending tasks that need to be flushed.
1742 $delegate.verifyNoPendingTasks = function() {
1743 if ($browser.deferredFns.length) {
1744 throw new Error('Deferred tasks to flush (' + $browser.deferredFns.length + '): ' +
1745 formatPendingTasksAsString($browser.deferredFns));
1749 function formatPendingTasksAsString(tasks) {
1751 angular.forEach(tasks, function(task) {
1752 result.push('{id: ' + task.id + ', ' + 'time: ' + task.time + '}');
1755 return result.join(', ');
1761 angular.mock.$RAFDecorator = ['$delegate', function($delegate) {
1763 var rafFn = function(fn) {
1764 var index = queue.length;
1767 queue.splice(index, 1);
1771 rafFn.supported = $delegate.supported;
1773 rafFn.flush = function() {
1774 if (queue.length === 0) {
1775 throw new Error('No rAF callbacks present');
1778 var length = queue.length;
1779 for (var i = 0; i < length; i++) {
1789 angular.mock.$AsyncCallbackDecorator = ['$delegate', function($delegate) {
1791 var addFn = function(fn) {
1794 addFn.flush = function() {
1795 angular.forEach(callbacks, function(fn) {
1806 angular.mock.$RootElementProvider = function() {
1807 this.$get = function() {
1808 return angular.element('<div ng-app></div>');
1816 * A decorator for {@link ng.$controller} with additional `bindings` parameter, useful when testing
1817 * controllers of directives that use {@link $compile#-bindtocontroller- `bindToController`}.
1824 * // Directive definition ...
1826 * myMod.directive('myDirective', {
1827 * controller: 'MyDirectiveController',
1828 * bindToController: {
1834 * // Controller definition ...
1836 * myMod.controller('MyDirectiveController', ['log', function($log) {
1837 * $log.info(this.name);
1843 * describe('myDirectiveController', function() {
1844 * it('should write the bound name to the log', inject(function($controller, $log) {
1845 * var ctrl = $controller('MyDirective', { /* no locals */ }, { name: 'Clark Kent' });
1846 * expect(ctrl.name).toEqual('Clark Kent');
1847 * expect($log.info.logs).toEqual(['Clark Kent']);
1853 * @param {Function|string} constructor If called with a function then it's considered to be the
1854 * controller constructor function. Otherwise it's considered to be a string which is used
1855 * to retrieve the controller constructor using the following steps:
1857 * * check if a controller with given name is registered via `$controllerProvider`
1858 * * check if evaluating the string on the current scope returns a constructor
1859 * * if $controllerProvider#allowGlobals, check `window[constructor]` on the global
1860 * `window` object (not recommended)
1862 * The string can use the `controller as property` syntax, where the controller instance is published
1863 * as the specified property on the `scope`; the `scope` must be injected into `locals` param for this
1864 * to work correctly.
1866 * @param {Object} locals Injection locals for Controller.
1867 * @param {Object=} bindings Properties to add to the controller before invoking the constructor. This is used
1868 * to simulate the `bindToController` feature and simplify certain kinds of tests.
1869 * @return {Object} Instance of given controller.
1871 angular.mock.$ControllerDecorator = ['$delegate', function($delegate) {
1872 return function(expression, locals, later, ident) {
1873 if (later && typeof later === 'object') {
1874 var create = $delegate(expression, locals, true, ident);
1875 angular.extend(create.instance, later);
1878 return $delegate(expression, locals, later, ident);
1886 * @packageName angular-mocks
1891 * The `ngMock` module provides support to inject and mock Angular services into unit tests.
1892 * In addition, ngMock also extends various core ng services such that they can be
1893 * inspected and controlled in a synchronous manner within test code.
1896 * <div doc-module-components="ngMock"></div>
1899 angular.module('ngMock', ['ng']).provider({
1900 $browser: angular.mock.$BrowserProvider,
1901 $exceptionHandler: angular.mock.$ExceptionHandlerProvider,
1902 $log: angular.mock.$LogProvider,
1903 $interval: angular.mock.$IntervalProvider,
1904 $httpBackend: angular.mock.$HttpBackendProvider,
1905 $rootElement: angular.mock.$RootElementProvider
1906 }).config(['$provide', function($provide) {
1907 $provide.decorator('$timeout', angular.mock.$TimeoutDecorator);
1908 $provide.decorator('$$rAF', angular.mock.$RAFDecorator);
1909 $provide.decorator('$$asyncCallback', angular.mock.$AsyncCallbackDecorator);
1910 $provide.decorator('$rootScope', angular.mock.$RootScopeDecorator);
1911 $provide.decorator('$controller', angular.mock.$ControllerDecorator);
1918 * @packageName angular-mocks
1921 * The `ngMockE2E` is an angular module which contains mocks suitable for end-to-end testing.
1922 * Currently there is only one mock present in this module -
1923 * the {@link ngMockE2E.$httpBackend e2e $httpBackend} mock.
1925 angular.module('ngMockE2E', ['ng']).config(['$provide', function($provide) {
1926 $provide.decorator('$httpBackend', angular.mock.e2e.$httpBackendDecorator);
1931 * @name $httpBackend
1934 * Fake HTTP backend implementation suitable for end-to-end testing or backend-less development of
1935 * applications that use the {@link ng.$http $http service}.
1937 * *Note*: For fake http backend implementation suitable for unit testing please see
1938 * {@link ngMock.$httpBackend unit-testing $httpBackend mock}.
1940 * This implementation can be used to respond with static or dynamic responses via the `when` api
1941 * and its shortcuts (`whenGET`, `whenPOST`, etc) and optionally pass through requests to the
1942 * real $httpBackend for specific requests (e.g. to interact with certain remote apis or to fetch
1943 * templates from a webserver).
1945 * As opposed to unit-testing, in an end-to-end testing scenario or in scenario when an application
1946 * is being developed with the real backend api replaced with a mock, it is often desirable for
1947 * certain category of requests to bypass the mock and issue a real http request (e.g. to fetch
1948 * templates or static files from the webserver). To configure the backend with this behavior
1949 * use the `passThrough` request handler of `when` instead of `respond`.
1951 * Additionally, we don't want to manually have to flush mocked out requests like we do during unit
1952 * testing. For this reason the e2e $httpBackend flushes mocked out requests
1953 * automatically, closely simulating the behavior of the XMLHttpRequest object.
1955 * To setup the application to run with this http backend, you have to create a module that depends
1956 * on the `ngMockE2E` and your application modules and defines the fake backend:
1959 * myAppDev = angular.module('myAppDev', ['myApp', 'ngMockE2E']);
1960 * myAppDev.run(function($httpBackend) {
1961 * phones = [{name: 'phone1'}, {name: 'phone2'}];
1963 * // returns the current list of phones
1964 * $httpBackend.whenGET('/phones').respond(phones);
1966 * // adds a new phone to the phones array
1967 * $httpBackend.whenPOST('/phones').respond(function(method, url, data) {
1968 * var phone = angular.fromJson(data);
1969 * phones.push(phone);
1970 * return [200, phone, {}];
1972 * $httpBackend.whenGET(/^\/templates\//).passThrough();
1977 * Afterwards, bootstrap your app with this new module.
1982 * @name $httpBackend#when
1985 * Creates a new backend definition.
1987 * @param {string} method HTTP method.
1988 * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
1989 * and returns true if the url match the current definition.
1990 * @param {(string|RegExp)=} data HTTP request body.
1991 * @param {(Object|function(Object))=} headers HTTP headers or function that receives http header
1992 * object and returns true if the headers match the current definition.
1993 * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
1994 * control how a matched request is handled. You can save this object for later use and invoke
1995 * `respond` or `passThrough` again in order to change how a matched request is handled.
1998 * `{function([status,] data[, headers, statusText])
1999 * | function(function(method, url, data, headers)}`
2000 * – The respond method takes a set of static data to be returned or a function that can return
2001 * an array containing response status (number), response data (string), response headers
2002 * (Object), and the text for the status (string).
2003 * - passThrough – `{function()}` – Any request matching a backend definition with
2004 * `passThrough` handler will be passed through to the real backend (an XHR request will be made
2006 * - Both methods return the `requestHandler` object for possible overrides.
2011 * @name $httpBackend#whenGET
2014 * Creates a new backend definition for GET requests. For more info see `when()`.
2016 * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
2017 * and returns true if the url match the current definition.
2018 * @param {(Object|function(Object))=} headers HTTP headers.
2019 * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
2020 * control how a matched request is handled. You can save this object for later use and invoke
2021 * `respond` or `passThrough` again in order to change how a matched request is handled.
2026 * @name $httpBackend#whenHEAD
2029 * Creates a new backend definition for HEAD requests. For more info see `when()`.
2031 * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
2032 * and returns true if the url match the current definition.
2033 * @param {(Object|function(Object))=} headers HTTP headers.
2034 * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
2035 * control how a matched request is handled. You can save this object for later use and invoke
2036 * `respond` or `passThrough` again in order to change how a matched request is handled.
2041 * @name $httpBackend#whenDELETE
2044 * Creates a new backend definition for DELETE requests. For more info see `when()`.
2046 * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
2047 * and returns true if the url match the current definition.
2048 * @param {(Object|function(Object))=} headers HTTP headers.
2049 * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
2050 * control how a matched request is handled. You can save this object for later use and invoke
2051 * `respond` or `passThrough` again in order to change how a matched request is handled.
2056 * @name $httpBackend#whenPOST
2059 * Creates a new backend definition for POST requests. For more info see `when()`.
2061 * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
2062 * and returns true if the url match the current definition.
2063 * @param {(string|RegExp)=} data HTTP request body.
2064 * @param {(Object|function(Object))=} headers HTTP headers.
2065 * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
2066 * control how a matched request is handled. You can save this object for later use and invoke
2067 * `respond` or `passThrough` again in order to change how a matched request is handled.
2072 * @name $httpBackend#whenPUT
2075 * Creates a new backend definition for PUT requests. For more info see `when()`.
2077 * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
2078 * and returns true if the url match the current definition.
2079 * @param {(string|RegExp)=} data HTTP request body.
2080 * @param {(Object|function(Object))=} headers HTTP headers.
2081 * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
2082 * control how a matched request is handled. You can save this object for later use and invoke
2083 * `respond` or `passThrough` again in order to change how a matched request is handled.
2088 * @name $httpBackend#whenPATCH
2091 * Creates a new backend definition for PATCH requests. For more info see `when()`.
2093 * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
2094 * and returns true if the url match the current definition.
2095 * @param {(string|RegExp)=} data HTTP request body.
2096 * @param {(Object|function(Object))=} headers HTTP headers.
2097 * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
2098 * control how a matched request is handled. You can save this object for later use and invoke
2099 * `respond` or `passThrough` again in order to change how a matched request is handled.
2104 * @name $httpBackend#whenJSONP
2107 * Creates a new backend definition for JSONP requests. For more info see `when()`.
2109 * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
2110 * and returns true if the url match the current definition.
2111 * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
2112 * control how a matched request is handled. You can save this object for later use and invoke
2113 * `respond` or `passThrough` again in order to change how a matched request is handled.
2115 angular.mock.e2e = {};
2116 angular.mock.e2e.$httpBackendDecorator =
2117 ['$rootScope', '$timeout', '$delegate', '$browser', createHttpBackendMock];
2122 * @name $rootScope.Scope
2125 * {@link ng.$rootScope.Scope Scope} type decorated with helper methods useful for testing. These
2126 * methods are automatically available on any {@link ng.$rootScope.Scope Scope} instance when
2127 * `ngMock` module is loaded.
2129 * In addition to all the regular `Scope` methods, the following helper methods are available:
2131 angular.mock.$RootScopeDecorator = ['$delegate', function($delegate) {
2133 var $rootScopePrototype = Object.getPrototypeOf($delegate);
2135 $rootScopePrototype.$countChildScopes = countChildScopes;
2136 $rootScopePrototype.$countWatchers = countWatchers;
2140 // ------------------------------------------------------------------------------------------ //
2144 * @name $rootScope.Scope#$countChildScopes
2147 * Counts all the direct and indirect child scopes of the current scope.
2149 * The current scope is excluded from the count. The count includes all isolate child scopes.
2151 * @returns {number} Total number of child scopes.
2153 function countChildScopes() {
2154 // jshint validthis: true
2155 var count = 0; // exclude the current scope
2156 var pendingChildHeads = [this.$$childHead];
2159 while (pendingChildHeads.length) {
2160 currentScope = pendingChildHeads.shift();
2162 while (currentScope) {
2164 pendingChildHeads.push(currentScope.$$childHead);
2165 currentScope = currentScope.$$nextSibling;
2175 * @name $rootScope.Scope#$countWatchers
2178 * Counts all the watchers of direct and indirect child scopes of the current scope.
2180 * The watchers of the current scope are included in the count and so are all the watchers of
2181 * isolate child scopes.
2183 * @returns {number} Total number of watchers.
2185 function countWatchers() {
2186 // jshint validthis: true
2187 var count = this.$$watchers ? this.$$watchers.length : 0; // include the current scope
2188 var pendingChildHeads = [this.$$childHead];
2191 while (pendingChildHeads.length) {
2192 currentScope = pendingChildHeads.shift();
2194 while (currentScope) {
2195 count += currentScope.$$watchers ? currentScope.$$watchers.length : 0;
2196 pendingChildHeads.push(currentScope.$$childHead);
2197 currentScope = currentScope.$$nextSibling;
2206 if (window.jasmine || window.mocha) {
2208 var currentSpec = null,
2209 annotatedFunctions = [],
2210 isSpecRunning = function() {
2211 return !!currentSpec;
2214 angular.mock.$$annotate = angular.injector.$$annotate;
2215 angular.injector.$$annotate = function(fn) {
2216 if (typeof fn === 'function' && !fn.$inject) {
2217 annotatedFunctions.push(fn);
2219 return angular.mock.$$annotate.apply(this, arguments);
2223 (window.beforeEach || window.setup)(function() {
2224 annotatedFunctions = [];
2228 (window.afterEach || window.teardown)(function() {
2229 var injector = currentSpec.$injector;
2231 annotatedFunctions.forEach(function(fn) {
2235 angular.forEach(currentSpec.$modules, function(module) {
2236 if (module && module.$$hashKey) {
2237 module.$$hashKey = undefined;
2241 currentSpec.$injector = null;
2242 currentSpec.$modules = null;
2246 injector.get('$rootElement').off();
2247 injector.get('$browser').pollFns.length = 0;
2250 // clean up jquery's fragment cache
2251 angular.forEach(angular.element.fragments, function(val, key) {
2252 delete angular.element.fragments[key];
2255 MockXhr.$$lastInstance = null;
2257 angular.forEach(angular.callbacks, function(val, key) {
2258 delete angular.callbacks[key];
2260 angular.callbacks.counter = 0;
2265 * @name angular.mock.module
2268 * *NOTE*: This function is also published on window for easy access.<br>
2269 * *NOTE*: This function is declared ONLY WHEN running tests with jasmine or mocha
2271 * This function registers a module configuration code. It collects the configuration information
2272 * which will be used when the injector is created by {@link angular.mock.inject inject}.
2274 * See {@link angular.mock.inject inject} for usage example
2276 * @param {...(string|Function|Object)} fns any number of modules which are represented as string
2277 * aliases or as anonymous module initialization functions. The modules are used to
2278 * configure the injector. The 'ng' and 'ngMock' modules are automatically loaded. If an
2279 * object literal is passed they will be registered as values in the module, the key being
2280 * the module name and the value being what is returned.
2282 window.module = angular.mock.module = function() {
2283 var moduleFns = Array.prototype.slice.call(arguments, 0);
2284 return isSpecRunning() ? workFn() : workFn;
2285 /////////////////////
2287 if (currentSpec.$injector) {
2288 throw new Error('Injector already created, can not register a module!');
2290 var modules = currentSpec.$modules || (currentSpec.$modules = []);
2291 angular.forEach(moduleFns, function(module) {
2292 if (angular.isObject(module) && !angular.isArray(module)) {
2293 modules.push(function($provide) {
2294 angular.forEach(module, function(value, key) {
2295 $provide.value(key, value);
2299 modules.push(module);
2308 * @name angular.mock.inject
2311 * *NOTE*: This function is also published on window for easy access.<br>
2312 * *NOTE*: This function is declared ONLY WHEN running tests with jasmine or mocha
2314 * The inject function wraps a function into an injectable function. The inject() creates new
2315 * instance of {@link auto.$injector $injector} per test, which is then used for
2316 * resolving references.
2319 * ## Resolving References (Underscore Wrapping)
2320 * Often, we would like to inject a reference once, in a `beforeEach()` block and reuse this
2321 * in multiple `it()` clauses. To be able to do this we must assign the reference to a variable
2322 * that is declared in the scope of the `describe()` block. Since we would, most likely, want
2323 * the variable to have the same name of the reference we have a problem, since the parameter
2324 * to the `inject()` function would hide the outer variable.
2326 * To help with this, the injected parameters can, optionally, be enclosed with underscores.
2327 * These are ignored by the injector when the reference name is resolved.
2329 * For example, the parameter `_myService_` would be resolved as the reference `myService`.
2330 * Since it is available in the function body as _myService_, we can then assign it to a variable
2331 * defined in an outer scope.
2334 * // Defined out reference variable outside
2337 * // Wrap the parameter in underscores
2338 * beforeEach( inject( function(_myService_){
2339 * myService = _myService_;
2342 * // Use myService in a series of tests.
2343 * it('makes use of myService', function() {
2344 * myService.doStuff();
2349 * See also {@link angular.mock.module angular.mock.module}
2352 * Example of what a typical jasmine tests looks like with the inject method.
2355 * angular.module('myApplicationModule', [])
2356 * .value('mode', 'app')
2357 * .value('version', 'v1.0.1');
2360 * describe('MyApp', function() {
2362 * // You need to load modules that you want to test,
2363 * // it loads only the "ng" module by default.
2364 * beforeEach(module('myApplicationModule'));
2367 * // inject() is used to inject arguments of all given functions
2368 * it('should provide a version', inject(function(mode, version) {
2369 * expect(version).toEqual('v1.0.1');
2370 * expect(mode).toEqual('app');
2374 * // The inject and module method can also be used inside of the it or beforeEach
2375 * it('should override a version and test the new version is injected', function() {
2376 * // module() takes functions or strings (module aliases)
2377 * module(function($provide) {
2378 * $provide.value('version', 'overridden'); // override version here
2381 * inject(function(version) {
2382 * expect(version).toEqual('overridden');
2389 * @param {...Function} fns any number of functions which will be injected using the injector.
2394 var ErrorAddingDeclarationLocationStack = function(e, errorForStack) {
2395 this.message = e.message;
2397 if (e.line) this.line = e.line;
2398 if (e.sourceId) this.sourceId = e.sourceId;
2399 if (e.stack && errorForStack)
2400 this.stack = e.stack + '\n' + errorForStack.stack;
2401 if (e.stackArray) this.stackArray = e.stackArray;
2403 ErrorAddingDeclarationLocationStack.prototype.toString = Error.prototype.toString;
2405 window.inject = angular.mock.inject = function() {
2406 var blockFns = Array.prototype.slice.call(arguments, 0);
2407 var errorForStack = new Error('Declaration Location');
2408 return isSpecRunning() ? workFn.call(currentSpec) : workFn;
2409 /////////////////////
2411 var modules = currentSpec.$modules || [];
2412 var strictDi = !!currentSpec.$injectorStrict;
2413 modules.unshift('ngMock');
2414 modules.unshift('ng');
2415 var injector = currentSpec.$injector;
2418 // If strictDi is enabled, annotate the providerInjector blocks
2419 angular.forEach(modules, function(moduleFn) {
2420 if (typeof moduleFn === "function") {
2421 angular.injector.$$annotate(moduleFn);
2425 injector = currentSpec.$injector = angular.injector(modules, strictDi);
2426 currentSpec.$injectorStrict = strictDi;
2428 for (var i = 0, ii = blockFns.length; i < ii; i++) {
2429 if (currentSpec.$injectorStrict) {
2430 // If the injector is strict / strictDi, and the spec wants to inject using automatic
2431 // annotation, then annotate the function here.
2432 injector.annotate(blockFns[i]);
2435 /* jshint -W040 *//* Jasmine explicitly provides a `this` object when calling functions */
2436 injector.invoke(blockFns[i] || angular.noop, this);
2439 if (e.stack && errorForStack) {
2440 throw new ErrorAddingDeclarationLocationStack(e, errorForStack);
2444 errorForStack = null;
2451 angular.mock.inject.strictDi = function(value) {
2452 value = arguments.length ? !!value : true;
2453 return isSpecRunning() ? workFn() : workFn;
2456 if (value !== currentSpec.$injectorStrict) {
2457 if (currentSpec.$injector) {
2458 throw new Error('Injector already created, can not modify strict annotations');
2460 currentSpec.$injectorStrict = value;
2468 })(window, window.angular);