3 * @license AngularJS v1.0.0rc7
4 * (c) 2010-2012 Google, Inc. http://angularjs.org
7 * TODO(vojta): wrap whole file into closure during build
15 * Namespace from 'angular-mocks.js' which contains testing related code.
21 * @name angular.module.ngMock.$browser
24 * This service is a mock implementation of {@link angular.module.ng.$browser}. It provides fake
25 * implementation for commonly used browser apis that are hard to test, e.g. setTimeout, xhr,
28 * The api of this service is the same as that of the real {@link angular.module.ng.$browser $browser}, except
29 * that there are several helper methods available which can be used in tests.
31 * The following apis can be used in tests:
33 * - $browser.defer — enables testing of code that uses
34 * {@link angular.module.ng.$defer $defer} for executing functions via the `setTimeout` api.
36 angular.mock.$BrowserProvider = function() {
37 this.$get = function(){
38 return new angular.mock.$Browser();
42 angular.mock.$Browser = function() {
46 self.$$url = "http://server";
47 self.$$lastUrl = self.$$url; // used by url polling fn
50 // TODO(vojta): remove this temporary api
51 self.$$completeOutstandingRequest = angular.noop;
52 self.$$incOutstandingRequestCount = angular.noop;
55 // register url polling fn
57 self.onUrlChange = function(listener) {
60 if (self.$$lastUrl != self.$$url) {
61 self.$$lastUrl = self.$$url;
71 self.lastCookieHash = {};
72 self.deferredFns = [];
73 self.deferredNextId = 0;
75 self.defer = function(fn, delay) {
77 self.deferredFns.push({time:(self.defer.now + delay), fn:fn, id: self.deferredNextId});
78 self.deferredFns.sort(function(a,b){ return a.time - b.time;});
79 return self.deferredNextId++;
86 self.defer.cancel = function(deferId) {
89 angular.forEach(self.deferredFns, function(fn, index) {
90 if (fn.id === deferId) fnIndex = index;
93 if (fnIndex !== undefined) {
94 self.deferredFns.splice(fnIndex, 1);
104 * @name angular.module.ngMock.$browser#defer.flush
105 * @methodOf angular.module.ngMock.$browser
108 * Flushes all pending requests and executes the defer callbacks.
110 * @param {number=} number of milliseconds to flush. See {@link #defer.now}
112 self.defer.flush = function(delay) {
113 if (angular.isDefined(delay)) {
114 self.defer.now += delay;
116 if (self.deferredFns.length) {
117 self.defer.now = self.deferredFns[self.deferredFns.length-1].time;
119 throw Error('No deferred tasks to be flushed');
123 while (self.deferredFns.length && self.deferredFns[0].time <= self.defer.now) {
124 self.deferredFns.shift().fn();
129 * @name angular.module.ngMock.$browser#defer.now
130 * @propertyOf angular.module.ngMock.$browser
133 * Current milliseconds mock time.
136 self.$$baseHref = '';
137 self.baseHref = function() {
138 return this.$$baseHref;
141 angular.mock.$Browser.prototype = {
144 * @name angular.module.ngMock.$browser#poll
145 * @methodOf angular.module.ngMock.$browser
148 * run all fns in pollFns
150 poll: function poll() {
151 angular.forEach(this.pollFns, function(pollFn){
156 addPollFn: function(pollFn) {
157 this.pollFns.push(pollFn);
161 url: function(url, replace) {
170 cookies: function(name, value) {
172 if (value == undefined) {
173 delete this.cookieHash[name];
175 if (angular.isString(value) && //strings only
176 value.length <= 4096) { //strict cookie storage limits
177 this.cookieHash[name] = value;
181 if (!angular.equals(this.cookieHash, this.lastCookieHash)) {
182 this.lastCookieHash = angular.copy(this.cookieHash);
183 this.cookieHash = angular.copy(this.cookieHash);
185 return this.cookieHash;
189 notifyWhenNoOutstandingRequests: function(fn) {
197 * @name angular.module.ngMock.$exceptionHandlerProvider
200 * Configures the mock implementation of {@link angular.module.ng.$exceptionHandler} to rethrow or to log errors passed
201 * into the `$exceptionHandler`.
206 * @name angular.module.ngMock.$exceptionHandler
209 * Mock implementation of {@link angular.module.ng.$exceptionHandler} that rethrows or logs errors passed
210 * into it. See {@link angular.module.ngMock.$exceptionHandlerProvider $exceptionHandlerProvider} for configuration
214 angular.mock.$ExceptionHandlerProvider = function() {
219 * @name angular.module.ngMock.$exceptionHandlerProvider#mode
220 * @methodOf angular.module.ngMock.$exceptionHandlerProvider
223 * Sets the logging mode.
225 * @param {string} mode Mode of operation, defaults to `rethrow`.
227 * - `rethrow`: If any errors are are passed into the handler in tests, it typically
228 * means that there is a bug in the application or test, so this mock will
229 * make these tests fail.
230 * - `log`: Sometimes it is desirable to test that an error is throw, for this case the `log` mode stores the
231 * error and allows later assertion of it.
232 * See {@link angular.module.ngMock.$log#assertEmpty assertEmpty()} and
233 * {@link angular.module.ngMock.$log#reset reset()}
235 this.mode = function(mode) {
238 handler = function(e) {
245 handler = function(e) {
246 if (arguments.length == 1) {
249 errors.push([].slice.call(arguments, 0));
253 handler.errors = errors;
256 throw Error("Unknown mode '" + mode + "', only 'log'/'rethrow' modes are allowed!");
260 this.$get = function() {
264 this.mode('rethrow');
270 * @name angular.module.ngMock.$log
273 * Mock implementation of {@link angular.module.ng.$log} that gathers all logged messages in arrays
274 * (one array per logging level). These arrays are exposed as `logs` property of each of the
275 * level-specific log function, e.g. for level `error` the array is exposed as `$log.error.logs`.
278 angular.mock.$LogProvider = function() {
280 function concat(array1, array2, index) {
281 return array1.concat(Array.prototype.slice.call(array2, index));
285 this.$get = function () {
287 log: function() { $log.log.logs.push(concat([], arguments, 0)); },
288 warn: function() { $log.warn.logs.push(concat([], arguments, 0)); },
289 info: function() { $log.info.logs.push(concat([], arguments, 0)); },
290 error: function() { $log.error.logs.push(concat([], arguments, 0)); }
295 * @name angular.module.ngMock.$log#reset
296 * @methodOf angular.module.ngMock.$log
299 * Reset all of the logging arrays to empty.
301 $log.reset = function () {
304 * @name angular.module.ngMock.$log#log.logs
305 * @propertyOf angular.module.ngMock.$log
308 * Array of logged messages.
313 * @name angular.module.ngMock.$log#warn.logs
314 * @propertyOf angular.module.ngMock.$log
317 * Array of logged messages.
322 * @name angular.module.ngMock.$log#info.logs
323 * @propertyOf angular.module.ngMock.$log
326 * Array of logged messages.
331 * @name angular.module.ngMock.$log#error.logs
332 * @propertyOf angular.module.ngMock.$log
335 * Array of logged messages.
337 $log.error.logs = [];
342 * @name angular.module.ngMock.$log#assertEmpty
343 * @methodOf angular.module.ngMock.$log
346 * Assert that the all of the logging methods have no logged messages. If messages present, an exception is thrown.
348 $log.assertEmpty = function() {
350 angular.forEach(['error', 'warn', 'info', 'log'], function(logLevel) {
351 angular.forEach($log[logLevel].logs, function(log) {
352 angular.forEach(log, function (logItem) {
353 errors.push('MOCK $log (' + logLevel + '): ' + String(logItem) + '\n' + (logItem.stack || ''));
358 errors.unshift("Expected $log to be empty! Either a message was logged unexpectedly, or an expected " +
359 "log message was not checked and removed:");
361 throw new Error(errors.join('\n---------\n'));
372 var R_ISO8061_STR = /^(\d{4})-?(\d\d)-?(\d\d)(?:T(\d\d)(?:\:?(\d\d)(?:\:?(\d\d)(?:\.(\d{3}))?)?)?(Z|([+-])(\d\d):?(\d\d)))?$/;
374 function jsonStringToDate(string){
376 if (match = string.match(R_ISO8061_STR)) {
377 var date = new Date(0),
381 tzHour = int(match[9] + match[10]);
382 tzMin = int(match[9] + match[11]);
384 date.setUTCFullYear(int(match[1]), int(match[2]) - 1, int(match[3]));
385 date.setUTCHours(int(match[4]||0) - tzHour, int(match[5]||0) - tzMin, int(match[6]||0), int(match[7]||0));
392 return parseInt(str, 10);
395 function padNumber(num, digits, trim) {
402 while(num.length < digits) num = '0' + num;
404 num = num.substr(num.length - digits);
411 * @name angular.mock.TzDate
414 * *NOTE*: this is not an injectable instance, just a globally available mock class of `Date`.
416 * Mock of the Date type which has its timezone specified via constroctor arg.
418 * The main purpose is to create Date-like instances with timezone fixed to the specified timezone
419 * offset, so that we can test code that depends on local timezone settings without dependency on
420 * the time zone settings of the machine where the code is running.
422 * @param {number} offset Offset of the *desired* timezone in hours (fractions will be honored)
423 * @param {(number|string)} timestamp Timestamp representing the desired time in *UTC*
427 * This is not a complete Date object so only methods that were implemented can be called safely.
428 * To make matters worse, TzDate instances inherit stuff from Date via a prototype.
430 * We do our best to intercept calls to "unimplemented" methods, but since the list of methods is
431 * incomplete we might be missing some non-standard methods. This can result in errors like:
432 * "Date.prototype.foo called on incompatible Object".
435 * var newYearInBratislava = new TzDate(-1, '2009-12-31T23:00:00Z');
436 * newYearInBratislava.getTimezoneOffset() => -60;
437 * newYearInBratislava.getFullYear() => 2010;
438 * newYearInBratislava.getMonth() => 0;
439 * newYearInBratislava.getDate() => 1;
440 * newYearInBratislava.getHours() => 0;
441 * newYearInBratislava.getMinutes() => 0;
445 angular.mock.TzDate = function (offset, timestamp) {
446 var self = new Date(0);
447 if (angular.isString(timestamp)) {
448 var tsStr = timestamp;
450 self.origDate = jsonStringToDate(timestamp);
452 timestamp = self.origDate.getTime();
453 if (isNaN(timestamp))
455 name: "Illegal Argument",
456 message: "Arg '" + tsStr + "' passed into TzDate constructor is not a valid date string"
459 self.origDate = new Date(timestamp);
462 var localOffset = new Date(timestamp).getTimezoneOffset();
463 self.offsetDiff = localOffset*60*1000 - offset*1000*60*60;
464 self.date = new Date(timestamp + self.offsetDiff);
466 self.getTime = function() {
467 return self.date.getTime() - self.offsetDiff;
470 self.toLocaleDateString = function() {
471 return self.date.toLocaleDateString();
474 self.getFullYear = function() {
475 return self.date.getFullYear();
478 self.getMonth = function() {
479 return self.date.getMonth();
482 self.getDate = function() {
483 return self.date.getDate();
486 self.getHours = function() {
487 return self.date.getHours();
490 self.getMinutes = function() {
491 return self.date.getMinutes();
494 self.getSeconds = function() {
495 return self.date.getSeconds();
498 self.getTimezoneOffset = function() {
502 self.getUTCFullYear = function() {
503 return self.origDate.getUTCFullYear();
506 self.getUTCMonth = function() {
507 return self.origDate.getUTCMonth();
510 self.getUTCDate = function() {
511 return self.origDate.getUTCDate();
514 self.getUTCHours = function() {
515 return self.origDate.getUTCHours();
518 self.getUTCMinutes = function() {
519 return self.origDate.getUTCMinutes();
522 self.getUTCSeconds = function() {
523 return self.origDate.getUTCSeconds();
526 self.getUTCMilliseconds = function() {
527 return self.origDate.getUTCMilliseconds();
530 self.getDay = function() {
531 return self.date.getDay();
534 // provide this method only on browsers that already have it
535 if (self.toISOString) {
536 self.toISOString = function() {
537 return padNumber(self.origDate.getUTCFullYear(), 4) + '-' +
538 padNumber(self.origDate.getUTCMonth() + 1, 2) + '-' +
539 padNumber(self.origDate.getUTCDate(), 2) + 'T' +
540 padNumber(self.origDate.getUTCHours(), 2) + ':' +
541 padNumber(self.origDate.getUTCMinutes(), 2) + ':' +
542 padNumber(self.origDate.getUTCSeconds(), 2) + '.' +
543 padNumber(self.origDate.getUTCMilliseconds(), 3) + 'Z'
547 //hide all methods not implemented in this mock that the Date prototype exposes
548 var unimplementedMethods = ['getMilliseconds', 'getUTCDay',
549 'getYear', 'setDate', 'setFullYear', 'setHours', 'setMilliseconds',
550 'setMinutes', 'setMonth', 'setSeconds', 'setTime', 'setUTCDate', 'setUTCFullYear',
551 'setUTCHours', 'setUTCMilliseconds', 'setUTCMinutes', 'setUTCMonth', 'setUTCSeconds',
552 'setYear', 'toDateString', 'toGMTString', 'toJSON', 'toLocaleFormat', 'toLocaleString',
553 'toLocaleTimeString', 'toSource', 'toString', 'toTimeString', 'toUTCString', 'valueOf'];
555 angular.forEach(unimplementedMethods, function(methodName) {
556 self[methodName] = function() {
557 throw Error("Method '" + methodName + "' is not implemented in the TzDate mock");
564 //make "tzDateInstance instanceof Date" return true
565 angular.mock.TzDate.prototype = Date.prototype;
571 * @name angular.mock.debug
574 * *NOTE*: this is not an injectable instance, just a globally available function.
576 * Method for serializing common angular objects (scope, elements, etc..) into strings, useful for debugging.
578 * This method is also available on window, where it can be used to display objects on debug console.
580 * @param {*} object - any object to turn into string.
581 * @return a serialized string of the argument
583 angular.mock.dump = function(object) {
584 return serialize(object);
586 function serialize(object) {
589 if (angular.isElement(object)) {
590 object = angular.element(object);
591 out = angular.element('<div></div>');
592 angular.forEach(object, function(element) {
593 out.append(angular.element(element).clone());
596 } else if (angular.isArray(object)) {
598 angular.forEach(object, function(o) {
599 out.push(serialize(o));
601 out = '[ ' + out.join(', ') + ' ]';
602 } else if (angular.isObject(object)) {
603 if (angular.isFunction(object.$eval) && angular.isFunction(object.$apply)) {
604 out = serializeScope(object);
605 } else if (object instanceof Error) {
606 out = object.stack || ('' + object.name + ': ' + object.message);
608 out = angular.toJson(object, true);
611 out = String(object);
617 function serializeScope(scope, offset) {
618 offset = offset || ' ';
619 var log = [offset + 'Scope(' + scope.$id + '): {'];
620 for ( var key in scope ) {
621 if (scope.hasOwnProperty(key) && !key.match(/^(\$|this)/)) {
622 log.push(' ' + key + ': ' + angular.toJson(scope[key]));
625 var child = scope.$$childHead;
627 log.push(serializeScope(child, offset + ' '));
628 child = child.$$nextSibling;
631 return log.join('\n' + offset);
637 * @name angular.module.ngMock.$httpBackend
639 * Fake HTTP backend implementation suitable for unit testing application that use the
640 * {@link angular.module.ng.$http $http service}.
642 * *Note*: For fake http backend implementation suitable for end-to-end testing or backend-less
643 * development please see {@link angular.module.ngMockE2E.$httpBackend e2e $httpBackend mock}.
645 * During unit testing, we want our unit tests to run quickly and have no external dependencies so
646 * we don’t want to send {@link https://developer.mozilla.org/en/xmlhttprequest XHR} or
647 * {@link http://en.wikipedia.org/wiki/JSONP JSONP} requests to a real server. All we really need is
648 * to verify whether a certain request has been sent or not, or alternatively just let the
649 * application make requests, respond with pre-trained responses and assert that the end result is
650 * what we expect it to be.
652 * This mock implementation can be used to respond with static or dynamic responses via the
653 * `expect` and `when` apis and their shortcuts (`expectGET`, `whenPOST`, etc).
655 * When an Angular application needs some data from a server, it calls the $http service, which
656 * sends the request to a real server using $httpBackend service. With dependency injection, it is
657 * easy to inject $httpBackend mock (which has the same API as $httpBackend) and use it to verify
658 * the requests and respond with some testing data without sending a request to real server.
660 * There are two ways to specify what test data should be returned as http responses by the mock
661 * backend when the code under test makes http requests:
663 * - `$httpBackend.expect` - specifies a request expectation
664 * - `$httpBackend.when` - specifies a backend definition
667 * # Request Expectations vs Backend Definitions
669 * Request expectations provide a way to make assertions about requests made by the application and
670 * to define responses for those requests. The test will fail if the expected requests are not made
671 * or they are made in the wrong order.
673 * Backend definitions allow you to define a fake backend for your application which doesn't assert
674 * if a particular request was made or not, it just returns a trained response if a request is made.
675 * The test will pass whether or not the request gets made during testing.
678 * <table class="table">
679 * <tr><th width="220px"></th><th>Request expectations</th><th>Backend definitions</th></tr>
682 * <td>.expect(...).respond(...)</td>
683 * <td>.when(...).respond(...)</td>
686 * <th>Typical usage</th>
687 * <td>strict unit tests</td>
688 * <td>loose (black-box) unit testing</td>
691 * <th>Fulfills multiple requests</th>
696 * <th>Order of requests matters</th>
701 * <th>Request required</th>
706 * <th>Response required</th>
707 * <td>optional (see below)</td>
712 * In cases where both backend definitions and request expectations are specified during unit
713 * testing, the request expectations are evaluated first.
715 * If a request expectation has no response specified, the algorithm will search your backend
716 * definitions for an appropriate response.
718 * If a request didn't match any expectation or if the expectation doesn't have the response
719 * defined, the backend definitions are evaluated in sequential order to see if any of them match
720 * the request. The response from the first matched definition is returned.
723 * # Flushing HTTP requests
725 * The $httpBackend used in production, always responds to requests with responses asynchronously.
726 * If we preserved this behavior in unit testing, we'd have to create async unit tests, which are
727 * hard to write, follow and maintain. At the same time the testing mock, can't respond
728 * synchronously because that would change the execution of the code under test. For this reason the
729 * mock $httpBackend has a `flush()` method, which allows the test to explicitly flush pending
730 * requests and thus preserving the async api of the backend, while allowing the test to execute
734 * # Unit testing with mock $httpBackend
738 function MyController($scope, $http) {
739 $http.get('/auth.py').success(function(data) {
743 this.saveMessage = function(message) {
744 $scope.status = 'Saving...';
745 $http.post('/add-msg.py', message).success(function(response) {
747 }).error(function() {
748 $scope.status = 'ERROR!';
753 // testing controller
756 beforeEach(inject(function($injector) {
757 $httpBackend = $injector.get('$httpBackend');
759 // backend definition common for all tests
760 $httpBackend.when('GET', '/auth.py').respond({userId: 'userX'}, {'A-Token': 'xxx'});
764 afterEach(function() {
765 $httpBackend.verifyNoOutstandingExpectation();
766 $httpBackend.verifyNoOutstandingRequest();
770 it('should fetch authentication token', function() {
771 $httpBackend.expectGET('/auth.py');
772 var controller = scope.$new(MyController);
773 $httpBackend.flush();
777 it('should send msg to server', function() {
778 // now you don’t care about the authentication, but
779 // the controller will still send the request and
780 // $httpBackend will respond without you having to
781 // specify the expectation and response for this request
782 $httpBackend.expectPOST('/add-msg.py', 'message content').respond(201, '');
784 var controller = scope.$new(MyController);
785 $httpBackend.flush();
786 controller.saveMessage('message content');
787 expect(controller.status).toBe('Saving...');
788 $httpBackend.flush();
789 expect(controller.status).toBe('');
793 it('should send auth header', function() {
794 $httpBackend.expectPOST('/add-msg.py', undefined, function(headers) {
795 // check if the header was send, if it wasn't the expectation won't
796 // match the request and the test will fail
797 return headers['Authorization'] == 'xxx';
800 var controller = scope.$new(MyController);
801 controller.saveMessage('whatever');
802 $httpBackend.flush();
806 angular.mock.$HttpBackendProvider = function() {
807 this.$get = [createHttpBackendMock];
811 * General factory function for $httpBackend mock.
812 * Returns instance for unit testing (when no arguments specified):
813 * - passing through is disabled
814 * - auto flushing is disabled
816 * Returns instance for e2e testing (when `$delegate` and `$browser` specified):
817 * - passing through (delegating request to real backend) is enabled
818 * - auto flushing is enabled
820 * @param {Object=} $delegate Real $httpBackend instance (allow passing through if specified)
821 * @param {Object=} $browser Auto-flushing enabled if specified
822 * @return {Object} Instance of $httpBackend mock
824 function createHttpBackendMock($delegate, $browser) {
825 var definitions = [],
828 responsesPush = angular.bind(responses, responses.push);
830 function createResponse(status, data, headers) {
831 if (angular.isFunction(status)) return status;
834 return angular.isNumber(status)
835 ? [status, data, headers]
836 : [200, status, data];
840 // TODO(vojta): change params to: method, url, data, headers, callback
841 function $httpBackend(method, url, data, callback, headers) {
842 var xhr = new MockXhr(),
843 expectation = expectations[0],
846 function prettyPrint(data) {
847 return (angular.isString(data) || angular.isFunction(data) || data instanceof RegExp)
849 : angular.toJson(data);
852 if (expectation && expectation.match(method, url)) {
853 if (!expectation.matchData(data))
854 throw Error('Expected ' + expectation + ' with different data\n' +
855 'EXPECTED: ' + prettyPrint(expectation.data) + '\nGOT: ' + data);
857 if (!expectation.matchHeaders(headers))
858 throw Error('Expected ' + expectation + ' with different headers\n' +
859 'EXPECTED: ' + prettyPrint(expectation.headers) + '\nGOT: ' +
860 prettyPrint(headers));
862 expectations.shift();
864 if (expectation.response) {
865 responses.push(function() {
866 var response = expectation.response(method, url, data, headers);
867 xhr.$$respHeaders = response[2];
868 callback(response[0], response[1], xhr.getAllResponseHeaders());
875 var i = -1, definition;
876 while ((definition = definitions[++i])) {
877 if (definition.match(method, url, data, headers || {})) {
878 if (definition.response) {
879 // if $browser specified, we do auto flush all requests
880 ($browser ? $browser.defer : responsesPush)(function() {
881 var response = definition.response(method, url, data, headers);
882 xhr.$$respHeaders = response[2];
883 callback(response[0], response[1], xhr.getAllResponseHeaders());
885 } else if (definition.passThrough) {
886 $delegate(method, url, data, callback, headers);
887 } else throw Error('No response defined !');
892 Error('No response defined !') :
893 Error('Unexpected request: ' + method + ' ' + url + '\n' +
894 (expectation ? 'Expected ' + expectation : 'No more request expected'));
899 * @name angular.module.ngMock.$httpBackend#when
900 * @methodOf angular.module.ngMock.$httpBackend
902 * Creates a new backend definition.
904 * @param {string} method HTTP method.
905 * @param {string|RegExp} url HTTP url.
906 * @param {(string|RegExp)=} data HTTP request body.
907 * @param {(Object|function(Object))=} headers HTTP headers or function that receives http header
908 * object and returns true if the headers match the current definition.
909 * @returns {requestHandler} Returns an object with `respond` method that control how a matched
910 * request is handled.
912 * - respond – `{function([status,] data[, headers])|function(function(method, url, data, headers)}`
913 * – The respond method takes a set of static data to be returned or a function that can return
914 * an array containing response status (number), response data (string) and response headers
917 $httpBackend.when = function(method, url, data, headers) {
918 var definition = new MockHttpExpectation(method, url, data, headers),
920 respond: function(status, data, headers) {
921 definition.response = createResponse(status, data, headers);
926 chain.passThrough = function() {
927 definition.passThrough = true;
931 definitions.push(definition);
937 * @name angular.module.ngMock.$httpBackend#whenGET
938 * @methodOf angular.module.ngMock.$httpBackend
940 * Creates a new backend definition for GET requests. For more info see `when()`.
942 * @param {string|RegExp} url HTTP url.
943 * @param {(Object|function(Object))=} headers HTTP headers.
944 * @returns {requestHandler} Returns an object with `respond` method that control how a matched
945 * request is handled.
950 * @name angular.module.ngMock.$httpBackend#whenHEAD
951 * @methodOf angular.module.ngMock.$httpBackend
953 * Creates a new backend definition for HEAD requests. For more info see `when()`.
955 * @param {string|RegExp} url HTTP url.
956 * @param {(Object|function(Object))=} headers HTTP headers.
957 * @returns {requestHandler} Returns an object with `respond` method that control how a matched
958 * request is handled.
963 * @name angular.module.ngMock.$httpBackend#whenDELETE
964 * @methodOf angular.module.ngMock.$httpBackend
966 * Creates a new backend definition for DELETE requests. For more info see `when()`.
968 * @param {string|RegExp} url HTTP url.
969 * @param {(Object|function(Object))=} headers HTTP headers.
970 * @returns {requestHandler} Returns an object with `respond` method that control how a matched
971 * request is handled.
976 * @name angular.module.ngMock.$httpBackend#whenPOST
977 * @methodOf angular.module.ngMock.$httpBackend
979 * Creates a new backend definition for POST requests. For more info see `when()`.
981 * @param {string|RegExp} url HTTP url.
982 * @param {(string|RegExp)=} data HTTP request body.
983 * @param {(Object|function(Object))=} headers HTTP headers.
984 * @returns {requestHandler} Returns an object with `respond` method that control how a matched
985 * request is handled.
990 * @name angular.module.ngMock.$httpBackend#whenPUT
991 * @methodOf angular.module.ngMock.$httpBackend
993 * Creates a new backend definition for PUT requests. For more info see `when()`.
995 * @param {string|RegExp} url HTTP url.
996 * @param {(string|RegExp)=} data HTTP request body.
997 * @param {(Object|function(Object))=} headers HTTP headers.
998 * @returns {requestHandler} Returns an object with `respond` method that control how a matched
999 * request is handled.
1004 * @name angular.module.ngMock.$httpBackend#whenJSONP
1005 * @methodOf angular.module.ngMock.$httpBackend
1007 * Creates a new backend definition for JSONP requests. For more info see `when()`.
1009 * @param {string|RegExp} url HTTP url.
1010 * @returns {requestHandler} Returns an object with `respond` method that control how a matched
1011 * request is handled.
1013 createShortMethods('when');
1018 * @name angular.module.ngMock.$httpBackend#expect
1019 * @methodOf angular.module.ngMock.$httpBackend
1021 * Creates a new request expectation.
1023 * @param {string} method HTTP method.
1024 * @param {string|RegExp} url HTTP url.
1025 * @param {(string|RegExp)=} data HTTP request body.
1026 * @param {(Object|function(Object))=} headers HTTP headers or function that receives http header
1027 * object and returns true if the headers match the current expectation.
1028 * @returns {requestHandler} Returns an object with `respond` method that control how a matched
1029 * request is handled.
1031 * - respond – `{function([status,] data[, headers])|function(function(method, url, data, headers)}`
1032 * – The respond method takes a set of static data to be returned or a function that can return
1033 * an array containing response status (number), response data (string) and response headers
1036 $httpBackend.expect = function(method, url, data, headers) {
1037 var expectation = new MockHttpExpectation(method, url, data, headers);
1038 expectations.push(expectation);
1040 respond: function(status, data, headers) {
1041 expectation.response = createResponse(status, data, headers);
1049 * @name angular.module.ngMock.$httpBackend#expectGET
1050 * @methodOf angular.module.ngMock.$httpBackend
1052 * Creates a new request expectation for GET requests. For more info see `expect()`.
1054 * @param {string|RegExp} url HTTP url.
1055 * @param {Object=} headers HTTP headers.
1056 * @returns {requestHandler} Returns an object with `respond` method that control how a matched
1057 * request is handled. See #expect for more info.
1062 * @name angular.module.ngMock.$httpBackend#expectHEAD
1063 * @methodOf angular.module.ngMock.$httpBackend
1065 * Creates a new request expectation for HEAD requests. For more info see `expect()`.
1067 * @param {string|RegExp} url HTTP url.
1068 * @param {Object=} headers HTTP headers.
1069 * @returns {requestHandler} Returns an object with `respond` method that control how a matched
1070 * request is handled.
1075 * @name angular.module.ngMock.$httpBackend#expectDELETE
1076 * @methodOf angular.module.ngMock.$httpBackend
1078 * Creates a new request expectation for DELETE requests. For more info see `expect()`.
1080 * @param {string|RegExp} url HTTP url.
1081 * @param {Object=} headers HTTP headers.
1082 * @returns {requestHandler} Returns an object with `respond` method that control how a matched
1083 * request is handled.
1088 * @name angular.module.ngMock.$httpBackend#expectPOST
1089 * @methodOf angular.module.ngMock.$httpBackend
1091 * Creates a new request expectation for POST requests. For more info see `expect()`.
1093 * @param {string|RegExp} url HTTP url.
1094 * @param {(string|RegExp)=} data HTTP request body.
1095 * @param {Object=} headers HTTP headers.
1096 * @returns {requestHandler} Returns an object with `respond` method that control how a matched
1097 * request is handled.
1102 * @name angular.module.ngMock.$httpBackend#expectPUT
1103 * @methodOf angular.module.ngMock.$httpBackend
1105 * Creates a new request expectation for PUT requests. For more info see `expect()`.
1107 * @param {string|RegExp} url HTTP url.
1108 * @param {(string|RegExp)=} data HTTP request body.
1109 * @param {Object=} headers HTTP headers.
1110 * @returns {requestHandler} Returns an object with `respond` method that control how a matched
1111 * request is handled.
1116 * @name angular.module.ngMock.$httpBackend#expectPATCH
1117 * @methodOf angular.module.ngMock.$httpBackend
1119 * Creates a new request expectation for PATCH requests. For more info see `expect()`.
1121 * @param {string|RegExp} url HTTP url.
1122 * @param {(string|RegExp)=} data HTTP request body.
1123 * @param {Object=} headers HTTP headers.
1124 * @returns {requestHandler} Returns an object with `respond` method that control how a matched
1125 * request is handled.
1130 * @name angular.module.ngMock.$httpBackend#expectJSONP
1131 * @methodOf angular.module.ngMock.$httpBackend
1133 * Creates a new request expectation for JSONP requests. For more info see `expect()`.
1135 * @param {string|RegExp} url HTTP url.
1136 * @returns {requestHandler} Returns an object with `respond` method that control how a matched
1137 * request is handled.
1139 createShortMethods('expect');
1144 * @name angular.module.ngMock.$httpBackend#flush
1145 * @methodOf angular.module.ngMock.$httpBackend
1147 * Flushes all pending requests using the trained responses.
1149 * @param {number=} count Number of responses to flush (in the order they arrived). If undefined,
1150 * all pending requests will be flushed. If there are no pending requests when the flush method
1151 * is called an exception is thrown (as this typically a sign of programming error).
1153 $httpBackend.flush = function(count) {
1154 if (!responses.length) throw Error('No pending request to flush !');
1156 if (angular.isDefined(count)) {
1158 if (!responses.length) throw Error('No more pending request to flush !');
1159 responses.shift()();
1162 while (responses.length) {
1163 responses.shift()();
1166 $httpBackend.verifyNoOutstandingExpectation();
1172 * @name angular.module.ngMock.$httpBackend#verifyNoOutstandingExpectation
1173 * @methodOf angular.module.ngMock.$httpBackend
1175 * Verifies that all of the requests defined via the `expect` api were made. If any of the
1176 * requests were not made, verifyNoOutstandingExpectation throws an exception.
1178 * Typically, you would call this method following each test case that asserts requests using an
1179 * "afterEach" clause.
1182 * afterEach($httpBackend.verifyExpectations);
1185 $httpBackend.verifyNoOutstandingExpectation = function() {
1186 if (expectations.length) {
1187 throw Error('Unsatisfied requests: ' + expectations.join(', '));
1194 * @name angular.module.ngMock.$httpBackend#verifyNoOutstandingRequest
1195 * @methodOf angular.module.ngMock.$httpBackend
1197 * Verifies that there are no outstanding requests that need to be flushed.
1199 * Typically, you would call this method following each test case that asserts requests using an
1200 * "afterEach" clause.
1203 * afterEach($httpBackend.verifyNoOutstandingRequest);
1206 $httpBackend.verifyNoOutstandingRequest = function() {
1207 if (responses.length) {
1208 throw Error('Unflushed requests: ' + responses.length);
1215 * @name angular.module.ngMock.$httpBackend#resetExpectations
1216 * @methodOf angular.module.ngMock.$httpBackend
1218 * Resets all request expectations, but preserves all backend definitions. Typically, you would
1219 * call resetExpectations during a multiple-phase test when you want to reuse the same instance of
1220 * $httpBackend mock.
1222 $httpBackend.resetExpectations = function() {
1223 expectations.length = 0;
1224 responses.length = 0;
1227 return $httpBackend;
1230 function createShortMethods(prefix) {
1231 angular.forEach(['GET', 'DELETE', 'JSONP'], function(method) {
1232 $httpBackend[prefix + method] = function(url, headers) {
1233 return $httpBackend[prefix](method, url, undefined, headers)
1237 angular.forEach(['PUT', 'POST', 'PATCH'], function(method) {
1238 $httpBackend[prefix + method] = function(url, data, headers) {
1239 return $httpBackend[prefix](method, url, data, headers)
1245 function MockHttpExpectation(method, url, data, headers) {
1248 this.headers = headers;
1250 this.match = function(m, u, d, h) {
1251 if (method != m) return false;
1252 if (!this.matchUrl(u)) return false;
1253 if (angular.isDefined(d) && !this.matchData(d)) return false;
1254 if (angular.isDefined(h) && !this.matchHeaders(h)) return false;
1258 this.matchUrl = function(u) {
1259 if (!url) return true;
1260 if (angular.isFunction(url.test)) return url.test(u);
1264 this.matchHeaders = function(h) {
1265 if (angular.isUndefined(headers)) return true;
1266 if (angular.isFunction(headers)) return headers(h);
1267 return angular.equals(headers, h);
1270 this.matchData = function(d) {
1271 if (angular.isUndefined(data)) return true;
1272 if (data && angular.isFunction(data.test)) return data.test(d);
1273 if (data && !angular.isString(data)) return angular.toJson(data) == d;
1277 this.toString = function() {
1278 return method + ' ' + url;
1282 function MockXhr() {
1284 // hack for testing $http, $httpBackend
1285 MockXhr.$$lastInstance = this;
1287 this.open = function(method, url, async) {
1288 this.$$method = method;
1290 this.$$async = async;
1291 this.$$reqHeaders = {};
1292 this.$$respHeaders = {};
1295 this.send = function(data) {
1299 this.setRequestHeader = function(key, value) {
1300 this.$$reqHeaders[key] = value;
1303 this.getResponseHeader = function(name) {
1304 // the lookup must be case insensitive, that's why we try two quick lookups and full scan at last
1305 var header = this.$$respHeaders[name];
1306 if (header) return header;
1308 name = angular.lowercase(name);
1309 header = this.$$respHeaders[name];
1310 if (header) return header;
1313 angular.forEach(this.$$respHeaders, function(headerVal, headerName) {
1314 if (!header && angular.lowercase(headerName) == name) header = headerVal;
1319 this.getAllResponseHeaders = function() {
1322 angular.forEach(this.$$respHeaders, function(value, key) {
1323 lines.push(key + ': ' + value);
1325 return lines.join('\n');
1328 this.abort = angular.noop;
1333 * @name angular.module.ngMock
1336 * The `ngMock` is an angular module which is used with `ng` module and adds unit-test configuration as well as useful
1337 * mocks to the {@link angular.module.AUTO.$injector $injector}.
1339 angular.module('ngMock', ['ng']).provider({
1340 $browser: angular.mock.$BrowserProvider,
1341 $exceptionHandler: angular.mock.$ExceptionHandlerProvider,
1342 $log: angular.mock.$LogProvider,
1343 $httpBackend: angular.mock.$HttpBackendProvider
1350 * @name angular.module.ngMockE2E
1353 * The `ngMockE2E` is an angular module which contains mocks suitable for end-to-end testing.
1354 * Currently there is only one mock present in this module -
1355 * the {@link angular.module.ngMockE2E.$httpBackend e2e $httpBackend} mock.
1357 angular.module('ngMockE2E', ['ng']).config(function($provide) {
1358 $provide.decorator('$httpBackend', angular.mock.e2e.$httpBackendDecorator);
1363 * @name angular.module.ngMockE2E.$httpBackend
1365 * Fake HTTP backend implementation suitable for end-to-end testing or backend-less development of
1366 * applications that use the {@link angular.module.ng.$http $http service}.
1368 * *Note*: For fake http backend implementation suitable for unit testing please see
1369 * {@link angular.module.ngMock.$httpBackend unit-testing $httpBackend mock}.
1371 * This implementation can be used to respond with static or dynamic responses via the `when` api
1372 * and its shortcuts (`whenGET`, `whenPOST`, etc) and optionally pass through requests to the
1373 * real $httpBackend for specific requests (e.g. to interact with certain remote apis or to fetch
1374 * templates from a webserver).
1376 * As opposed to unit-testing, in an end-to-end testing scenario or in scenario when an application
1377 * is being developed with the real backend api replaced with a mock, it is often desirable for
1378 * certain category of requests to bypass the mock and issue a real http request (e.g. to fetch
1379 * templates or static files from the webserver). To configure the backend with this behavior
1380 * use the `passThrough` request handler of `when` instead of `respond`.
1382 * Additionally, we don't want to manually have to flush mocked out requests like we do during unit
1383 * testing. For this reason the e2e $httpBackend automatically flushes mocked out requests
1384 * automatically, closely simulating the behavior of the XMLHttpRequest object.
1386 * To setup the application to run with this http backend, you have to create a module that depends
1387 * on the `ngMockE2E` and your application modules and defines the fake backend:
1390 * myAppDev = angular.module('myAppDev', ['myApp', 'ngMockE2E']);
1391 * myAppDev.run(function($httpBackend) {
1392 * phones = [{name: 'phone1'}, {name: 'phone2'}];
1394 * // returns the current list of phones
1395 * $httpBackend.whenGET('/phones').respond(phones);
1397 * // adds a new phone to the phones array
1398 * $httpBackend.whenPOST('/phones').respond(function(method, url, data) {
1399 * phones.push(angular.fromJSON(data));
1401 * $httpBackend.whenGET(/^\/templates\//).passThrough();
1406 * Afterwards, bootstrap your app with this new module.
1411 * @name angular.module.ngMockE2E.$httpBackend#when
1412 * @methodOf angular.module.ngMockE2E.$httpBackend
1414 * Creates a new backend definition.
1416 * @param {string} method HTTP method.
1417 * @param {string|RegExp} url HTTP url.
1418 * @param {(string|RegExp)=} data HTTP request body.
1419 * @param {(Object|function(Object))=} headers HTTP headers or function that receives http header
1420 * object and returns true if the headers match the current definition.
1421 * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
1422 * control how a matched request is handled.
1424 * - respond – `{function([status,] data[, headers])|function(function(method, url, data, headers)}`
1425 * – The respond method takes a set of static data to be returned or a function that can return
1426 * an array containing response status (number), response data (string) and response headers
1428 * - passThrough – `{function()}` – Any request matching a backend definition with `passThrough`
1429 * handler, will be pass through to the real backend (an XHR request will be made to the
1435 * @name angular.module.ngMockE2E.$httpBackend#whenGET
1436 * @methodOf angular.module.ngMockE2E.$httpBackend
1438 * Creates a new backend definition for GET requests. For more info see `when()`.
1440 * @param {string|RegExp} url HTTP url.
1441 * @param {(Object|function(Object))=} headers HTTP headers.
1442 * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
1443 * control how a matched request is handled.
1448 * @name angular.module.ngMockE2E.$httpBackend#whenHEAD
1449 * @methodOf angular.module.ngMockE2E.$httpBackend
1451 * Creates a new backend definition for HEAD requests. For more info see `when()`.
1453 * @param {string|RegExp} url HTTP url.
1454 * @param {(Object|function(Object))=} headers HTTP headers.
1455 * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
1456 * control how a matched request is handled.
1461 * @name angular.module.ngMockE2E.$httpBackend#whenDELETE
1462 * @methodOf angular.module.ngMockE2E.$httpBackend
1464 * Creates a new backend definition for DELETE requests. For more info see `when()`.
1466 * @param {string|RegExp} url HTTP url.
1467 * @param {(Object|function(Object))=} headers HTTP headers.
1468 * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
1469 * control how a matched request is handled.
1474 * @name angular.module.ngMockE2E.$httpBackend#whenPOST
1475 * @methodOf angular.module.ngMockE2E.$httpBackend
1477 * Creates a new backend definition for POST requests. For more info see `when()`.
1479 * @param {string|RegExp} url HTTP url.
1480 * @param {(string|RegExp)=} data HTTP request body.
1481 * @param {(Object|function(Object))=} headers HTTP headers.
1482 * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
1483 * control how a matched request is handled.
1488 * @name angular.module.ngMockE2E.$httpBackend#whenPUT
1489 * @methodOf angular.module.ngMockE2E.$httpBackend
1491 * Creates a new backend definition for PUT requests. For more info see `when()`.
1493 * @param {string|RegExp} url HTTP url.
1494 * @param {(string|RegExp)=} data HTTP request body.
1495 * @param {(Object|function(Object))=} headers HTTP headers.
1496 * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
1497 * control how a matched request is handled.
1502 * @name angular.module.ngMockE2E.$httpBackend#whenPATCH
1503 * @methodOf angular.module.ngMockE2E.$httpBackend
1505 * Creates a new backend definition for PATCH requests. For more info see `when()`.
1507 * @param {string|RegExp} url HTTP url.
1508 * @param {(string|RegExp)=} data HTTP request body.
1509 * @param {(Object|function(Object))=} headers HTTP headers.
1510 * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
1511 * control how a matched request is handled.
1516 * @name angular.module.ngMockE2E.$httpBackend#whenJSONP
1517 * @methodOf angular.module.ngMockE2E.$httpBackend
1519 * Creates a new backend definition for JSONP requests. For more info see `when()`.
1521 * @param {string|RegExp} url HTTP url.
1522 * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
1523 * control how a matched request is handled.
1525 angular.mock.e2e = {};
1526 angular.mock.e2e.$httpBackendDecorator = ['$delegate', '$browser', createHttpBackendMock];
1530 window.jstestdriver && (function(window) {
1532 * Global method to output any number of objects into JSTD console. Useful for debugging.
1534 window.dump = function() {
1536 angular.forEach(arguments, function(arg) {
1537 args.push(angular.mock.dump(arg));
1539 jstestdriver.console.log.apply(jstestdriver.console, args);
1540 if (window.console) {
1541 window.console.log.apply(window.console, args);
1547 window.jasmine && (function(window) {
1549 function getCurrentSpec() {
1550 return jasmine.getEnv().currentSpec;
1553 function isSpecRunning() {
1554 var spec = getCurrentSpec();
1555 return spec && spec.queue.running;
1560 * @name angular.mock.module
1563 * *NOTE*: This is function is also published on window for easy access.<br>
1564 * *NOTE*: Only available with {@link http://pivotal.github.com/jasmine/ jasmine}.
1566 * This function registers a module configuration code. It collects the configuration information
1567 * which will be used when the injector is created by {@link angular.mock.inject inject}.
1569 * See {@link angular.mock.inject inject} for usage example
1571 * @param {...(string|Function)} fns any number of modules which are represented as string
1572 * aliases or as anonymous module initialization functions. The modules are used to
1573 * configure the injector. The 'ng' and 'ngMock' modules are automatically loaded.
1575 window.module = angular.mock.module = function() {
1576 var moduleFns = Array.prototype.slice.call(arguments, 0);
1577 return isSpecRunning() ? workFn() : workFn;
1578 /////////////////////
1580 var spec = getCurrentSpec();
1581 if (spec.$injector) {
1582 throw Error('Injector already created, can not register a module!');
1584 var modules = spec.$modules || (spec.$modules = []);
1585 angular.forEach(moduleFns, function(module) {
1586 modules.push(module);
1594 * @name angular.mock.inject
1597 * *NOTE*: This is function is also published on window for easy access.<br>
1598 * *NOTE*: Only available with {@link http://pivotal.github.com/jasmine/ jasmine}.
1600 * The inject function wraps a function into an injectable function. The inject() creates new
1601 * instance of {@link angular.module.AUTO.$injector $injector} per test, which is then used for
1602 * resolving references.
1604 * See also {@link angular.mock.module module}
1606 * Example of what a typical jasmine tests looks like with the inject method.
1609 * angular.module('myApplicationModule', [])
1610 * .value('mode', 'app')
1611 * .value('version', 'v1.0.1');
1614 * describe('MyApp', function() {
1616 * // You need to load modules that you want to test,
1617 * // it loads only the "ng" module by default.
1618 * beforeEach(module('myApplicationModule'));
1621 * // inject() is used to inject arguments of all given functions
1622 * it('should provide a version', inject(function(mode, version) {
1623 * expect(version).toEqual('v1.0.1');
1624 * expect(mode).toEqual('app');
1628 * // The inject and module method can also be used inside of the it or beforeEach
1629 * it('should override a version and test the new version is injected', function() {
1630 * // module() takes functions or strings (module aliases)
1631 * module(function($provide) {
1632 * $provide.value('version', 'overridden'); // override version here
1635 * inject(function(version) {
1636 * expect(version).toEqual('overridden');
1643 * @param {...Function} fns any number of functions which will be injected using the injector.
1645 window.inject = angular.mock.inject = function() {
1646 var blockFns = Array.prototype.slice.call(arguments, 0);
1647 var stack = new Error('Declaration Location').stack;
1648 return isSpecRunning() ? workFn() : workFn;
1649 /////////////////////
1651 var spec = getCurrentSpec();
1652 var modules = spec.$modules || [];
1653 modules.unshift('ngMock');
1654 modules.unshift('ng');
1655 var injector = spec.$injector;
1657 injector = spec.$injector = angular.injector(modules);
1659 for(var i = 0, ii = blockFns.length; i < ii; i++) {
1661 injector.invoke(blockFns[i] || angular.noop, this);
1663 if(e.stack) e.stack += '\n' + stack;