From 2430f52bb97fa9d682e5f028c977c5bf94c5ec38 Mon Sep 17 00:00:00 2001 From: Misko Hevery Date: Fri, 23 Mar 2012 14:03:24 -0700 Subject: chore(module): move files around in preparation for more modules --- src/ngMock/angular-mocks.js | 1591 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1591 insertions(+) create mode 100644 src/ngMock/angular-mocks.js (limited to 'src/ngMock/angular-mocks.js') diff --git a/src/ngMock/angular-mocks.js b/src/ngMock/angular-mocks.js new file mode 100644 index 00000000..306ca77b --- /dev/null +++ b/src/ngMock/angular-mocks.js @@ -0,0 +1,1591 @@ + +/** + * @license AngularJS v"NG_VERSION_FULL" + * (c) 2010-2011 AngularJS http://angularjs.org + * License: MIT + * + * TODO(vojta): wrap whole file into closure during build + */ + +/** + * @ngdoc overview + * @name angular.mock + * @description + * + * Namespace from 'angular-mocks.js' which contains testing related code. + */ +angular.mock = {}; + +/** + * @ngdoc object + * @name angular.module.ngMock.$browser + * + * @description + * This service is a mock implementation of {@link angular.module.ng.$browser}. It provides fake + * implementation for commonly used browser apis that are hard to test, e.g. setTimeout, xhr, + * cookies, etc... + * + * The api of this service is the same as that of the real {@link angular.module.ng.$browser $browser}, except + * that there are several helper methods available which can be used in tests. + * + * The following apis can be used in tests: + * + * - $browser.defer — enables testing of code that uses + * {@link angular.module.ng.$defer $defer} for executing functions via the `setTimeout` api. + */ +angular.mock.$BrowserProvider = function() { + this.$get = function(){ + return new angular.mock.$Browser(); + }; +}; + +angular.mock.$Browser = function() { + var self = this; + + this.isMock = true; + self.$$url = "http://server"; + self.$$lastUrl = self.$$url; // used by url polling fn + self.pollFns = []; + + // TODO(vojta): remove this temporary api + self.$$completeOutstandingRequest = angular.noop; + self.$$incOutstandingRequestCount = angular.noop; + + + // register url polling fn + + self.onUrlChange = function(listener) { + self.pollFns.push( + function() { + if (self.$$lastUrl != self.$$url) { + self.$$lastUrl = self.$$url; + listener(self.$$url); + } + } + ); + + return listener; + }; + + self.cookieHash = {}; + self.lastCookieHash = {}; + self.deferredFns = []; + self.deferredNextId = 0; + + self.defer = function(fn, delay) { + delay = delay || 0; + self.deferredFns.push({time:(self.defer.now + delay), fn:fn, id: self.deferredNextId}); + self.deferredFns.sort(function(a,b){ return a.time - b.time;}); + return self.deferredNextId++; + }; + + + self.defer.now = 0; + + + self.defer.cancel = function(deferId) { + var fnIndex; + + angular.forEach(self.deferredFns, function(fn, index) { + if (fn.id === deferId) fnIndex = index; + }); + + if (fnIndex !== undefined) { + self.deferredFns.splice(fnIndex, 1); + return true; + } + + return false; + }; + + + /** + * @ngdoc method + * @name angular.module.ngMock.$browser#defer.flush + * @methodOf angular.module.ngMock.$browser + * + * @description + * Flushes all pending requests and executes the defer callbacks. + * + * @param {number=} number of milliseconds to flush. See {@link #defer.now} + */ + self.defer.flush = function(delay) { + if (angular.isDefined(delay)) { + self.defer.now += delay; + } else { + if (self.deferredFns.length) { + self.defer.now = self.deferredFns[self.deferredFns.length-1].time; + } else { + throw Error('No deferred tasks to be flushed'); + } + } + + while (self.deferredFns.length && self.deferredFns[0].time <= self.defer.now) { + self.deferredFns.shift().fn(); + } + }; + /** + * @ngdoc property + * @name angular.module.ngMock.$browser#defer.now + * @propertyOf angular.module.ngMock.$browser + * + * @description + * Current milliseconds mock time. + */ + + self.$$baseHref = ''; + self.baseHref = function() { + return this.$$baseHref; + }; + + self.$$scripts = []; + self.addJs = function(url, done) { + var script = {url: url, done: done}; + self.$$scripts.push(script); + return script; + }; +}; +angular.mock.$Browser.prototype = { + +/** + * @name angular.module.ngMock.$browser#poll + * @methodOf angular.module.ngMock.$browser + * + * @description + * run all fns in pollFns + */ + poll: function poll() { + angular.forEach(this.pollFns, function(pollFn){ + pollFn(); + }); + }, + + addPollFn: function(pollFn) { + this.pollFns.push(pollFn); + return pollFn; + }, + + url: function(url, replace) { + if (url) { + this.$$url = url; + return this; + } + + return this.$$url; + }, + + cookies: function(name, value) { + if (name) { + if (value == undefined) { + delete this.cookieHash[name]; + } else { + if (angular.isString(value) && //strings only + value.length <= 4096) { //strict cookie storage limits + this.cookieHash[name] = value; + } + } + } else { + if (!angular.equals(this.cookieHash, this.lastCookieHash)) { + this.lastCookieHash = angular.copy(this.cookieHash); + this.cookieHash = angular.copy(this.cookieHash); + } + return this.cookieHash; + } + }, + + notifyWhenNoOutstandingRequests: function(fn) { + fn(); + } +}; + + +/** + * @ngdoc object + * @name angular.module.ngMock.$exceptionHandlerProvider + * + * @description + * Configures the mock implementation of {@link angular.module.ng.$exceptionHandler} to rethrow or to log errors passed + * into the `$exceptionHandler`. + */ + +/** + * @ngdoc object + * @name angular.module.ngMock.$exceptionHandler + * + * @description + * Mock implementation of {@link angular.module.ng.$exceptionHandler} that rethrows or logs errors passed + * into it. See {@link angular.module.ngMock.$exceptionHandlerProvider $exceptionHandlerProvider} for configuration + * information. + */ + +angular.mock.$ExceptionHandlerProvider = function() { + var handler; + + /** + * @ngdoc method + * @name angular.module.ngMock.$exceptionHandlerProvider#mode + * @methodOf angular.module.ngMock.$exceptionHandlerProvider + * + * @description + * Sets the logging mode. + * + * @param {string} mode Mode of operation, defaults to `rethrow`. + * + * - `rethrow`: If any errors are are passed into the handler in tests, it typically + * means that there is a bug in the application or test, so this mock will + * make these tests fail. + * - `log`: Sometimes it is desirable to test that an error is throw, for this case the `log` mode stores the + * error and allows later assertion of it. + * See {@link angular.module.ngMock.$log#assertEmpty assertEmpty()} and + * {@link angular.module.ngMock.$log#reset reset()} + */ + this.mode = function(mode) { + switch(mode) { + case 'rethrow': + handler = function(e) { + throw e; + }; + break; + case 'log': + var errors = []; + handler = function(e) { + if (arguments.length == 1) { + errors.push(e); + } else { + errors.push([].slice.call(arguments, 0)); + } + } + handler.errors = errors; + break; + default: + throw Error("Unknown mode '" + mode + "', only 'log'/'rethrow' modes are allowed!"); + } + }; + + this.$get = function() { + return handler; + }; + + this.mode('rethrow'); +}; + + +/** + * @ngdoc service + * @name angular.module.ngMock.$log + * + * @description + * Mock implementation of {@link angular.module.ng.$log} that gathers all logged messages in arrays + * (one array per logging level). These arrays are exposed as `logs` property of each of the + * level-specific log function, e.g. for level `error` the array is exposed as `$log.error.logs`. + * + */ +angular.mock.$LogProvider = function() { + + function concat(array1, array2, index) { + return array1.concat(Array.prototype.slice.call(array2, index)); + } + + + this.$get = function () { + var $log = { + log: function() { $log.log.logs.push(concat([], arguments, 0)); }, + warn: function() { $log.warn.logs.push(concat([], arguments, 0)); }, + info: function() { $log.info.logs.push(concat([], arguments, 0)); }, + error: function() { $log.error.logs.push(concat([], arguments, 0)); } + }; + + /** + * @ngdoc method + * @name angular.module.ngMock.$log#reset + * @methodOf angular.module.ngMock.$log + * + * @description + * Reset all of the logging arrays to empty. + */ + $log.reset = function () { + /** + * @ngdoc property + * @name angular.module.ngMock.$log#log.logs + * @propertyOf angular.module.ngMock.$log + * + * @description + * Array of logged messages. + */ + $log.log.logs = []; + /** + * @ngdoc property + * @name angular.module.ngMock.$log#warn.logs + * @propertyOf angular.module.ngMock.$log + * + * @description + * Array of logged messages. + */ + $log.warn.logs = []; + /** + * @ngdoc property + * @name angular.module.ngMock.$log#info.logs + * @propertyOf angular.module.ngMock.$log + * + * @description + * Array of logged messages. + */ + $log.info.logs = []; + /** + * @ngdoc property + * @name angular.module.ngMock.$log#error.logs + * @propertyOf angular.module.ngMock.$log + * + * @description + * Array of logged messages. + */ + $log.error.logs = []; + }; + + /** + * @ngdoc method + * @name angular.module.ngMock.$log#assertEmpty + * @methodOf angular.module.ngMock.$log + * + * @description + * Assert that the all of the logging methods have no logged messages. If messages present, an exception is thrown. + */ + $log.assertEmpty = function() { + var errors = []; + angular.forEach(['error', 'warn', 'info', 'log'], function(logLevel) { + angular.forEach($log[logLevel].logs, function(log) { + angular.forEach(log, function (logItem) { + errors.push('MOCK $log (' + logLevel + '): ' + String(logItem) + '\n' + (logItem.stack || '')); + }); + }); + }); + if (errors.length) { + errors.unshift("Expected $log to be empty! Either a message was logged unexpectedly, or an expected " + + "log message was not checked and removed:"); + errors.push(''); + throw new Error(errors.join('\n---------\n')); + } + }; + + $log.reset(); + return $log; + }; +}; + + +/** + * @ngdoc object + * @name angular.mock.TzDate + * @description + * + * *NOTE*: this is not an injectable instance, just a globally available mock class of `Date`. + * + * Mock of the Date type which has its timezone specified via constroctor arg. + * + * The main purpose is to create Date-like instances with timezone fixed to the specified timezone + * offset, so that we can test code that depends on local timezone settings without dependency on + * the time zone settings of the machine where the code is running. + * + * @param {number} offset Offset of the *desired* timezone in hours (fractions will be honored) + * @param {(number|string)} timestamp Timestamp representing the desired time in *UTC* + * + * @example + * !!!! WARNING !!!!! + * This is not a complete Date object so only methods that were implemented can be called safely. + * To make matters worse, TzDate instances inherit stuff from Date via a prototype. + * + * We do our best to intercept calls to "unimplemented" methods, but since the list of methods is + * incomplete we might be missing some non-standard methods. This can result in errors like: + * "Date.prototype.foo called on incompatible Object". + * + *
+ * var newYearInBratislava = new TzDate(-1, '2009-12-31T23:00:00Z'); + * newYearInBratislava.getTimezoneOffset() => -60; + * newYearInBratislava.getFullYear() => 2010; + * newYearInBratislava.getMonth() => 0; + * newYearInBratislava.getDate() => 1; + * newYearInBratislava.getHours() => 0; + * newYearInBratislava.getMinutes() => 0; + *+ * + */ +angular.mock.TzDate = function (offset, timestamp) { + var self = new Date(0); + if (angular.isString(timestamp)) { + var tsStr = timestamp; + + self.origDate = angular.fromJson(angular.toJson({date:timestamp})).date; + + timestamp = self.origDate.getTime(); + if (isNaN(timestamp)) + throw { + name: "Illegal Argument", + message: "Arg '" + tsStr + "' passed into TzDate constructor is not a valid date string" + }; + } else { + self.origDate = new Date(timestamp); + } + + var localOffset = new Date(timestamp).getTimezoneOffset(); + self.offsetDiff = localOffset*60*1000 - offset*1000*60*60; + self.date = new Date(timestamp + self.offsetDiff); + + self.getTime = function() { + return self.date.getTime() - self.offsetDiff; + }; + + self.toLocaleDateString = function() { + return self.date.toLocaleDateString(); + }; + + self.getFullYear = function() { + return self.date.getFullYear(); + }; + + self.getMonth = function() { + return self.date.getMonth(); + }; + + self.getDate = function() { + return self.date.getDate(); + }; + + self.getHours = function() { + return self.date.getHours(); + }; + + self.getMinutes = function() { + return self.date.getMinutes(); + }; + + self.getSeconds = function() { + return self.date.getSeconds(); + }; + + self.getTimezoneOffset = function() { + return offset * 60; + }; + + self.getUTCFullYear = function() { + return self.origDate.getUTCFullYear(); + }; + + self.getUTCMonth = function() { + return self.origDate.getUTCMonth(); + }; + + self.getUTCDate = function() { + return self.origDate.getUTCDate(); + }; + + self.getUTCHours = function() { + return self.origDate.getUTCHours(); + }; + + self.getUTCMinutes = function() { + return self.origDate.getUTCMinutes(); + }; + + self.getUTCSeconds = function() { + return self.origDate.getUTCSeconds(); + }; + + self.getDay = function() { + return self.date.getDay(); + }; + + //hide all methods not implemented in this mock that the Date prototype exposes + var unimplementedMethods = ['getMilliseconds', 'getUTCDay', + 'getUTCMilliseconds', 'getYear', 'setDate', 'setFullYear', 'setHours', 'setMilliseconds', + 'setMinutes', 'setMonth', 'setSeconds', 'setTime', 'setUTCDate', 'setUTCFullYear', + 'setUTCHours', 'setUTCMilliseconds', 'setUTCMinutes', 'setUTCMonth', 'setUTCSeconds', + 'setYear', 'toDateString', 'toJSON', 'toGMTString', 'toLocaleFormat', 'toLocaleString', + 'toLocaleTimeString', 'toSource', 'toString', 'toTimeString', 'toUTCString', 'valueOf']; + + angular.forEach(unimplementedMethods, function(methodName) { + self[methodName] = function() { + throw Error("Method '" + methodName + "' is not implemented in the TzDate mock"); + }; + }); + + return self; +}; + +//make "tzDateInstance instanceof Date" return true +angular.mock.TzDate.prototype = Date.prototype; + + +/** + * @ngdoc function + * @name angular.mock.debug + * @description + * + * *NOTE*: this is not an injectable instance, just a globally available function. + * + * Method for serializing common angular objects (scope, elements, etc..) into strings, useful for debugging. + * + * This method is also available on window, where it can be used to display objects on debug console. + * + * @param {*} object - any object to turn into string. + * @return a serialized string of the argument + */ +angular.mock.dump = function(object) { + return serialize(object); + + function serialize(object) { + var out; + + if (angular.isElement(object)) { + object = angular.element(object); + out = angular.element(''); + angular.forEach(object, function(element) { + out.append(angular.element(element).clone()); + }); + out = out.html(); + } else if (angular.isArray(object)) { + out = []; + angular.forEach(object, function(o) { + out.push(serialize(o)); + }); + out = '[ ' + out.join(', ') + ' ]'; + } else if (angular.isObject(object)) { + if (angular.isFunction(object.$eval) && angular.isFunction(object.$apply)) { + out = serializeScope(object); + } else if (object instanceof Error) { + out = object.stack || ('' + object.name + ': ' + object.message); + } else { + out = angular.toJson(object, true); + } + } else { + out = String(object); + } + + return out; + } + + function serializeScope(scope, offset) { + offset = offset || ' '; + var log = [offset + 'Scope(' + scope.$id + '): {']; + for ( var key in scope ) { + if (scope.hasOwnProperty(key) && !key.match(/^(\$|this)/)) { + log.push(' ' + key + ': ' + angular.toJson(scope[key])); + } + } + var child = scope.$$childHead; + while(child) { + log.push(serializeScope(child, offset + ' ')); + child = child.$$nextSibling; + } + log.push('}'); + return log.join('\n' + offset); + } +}; + +/** + * @ngdoc object + * @name angular.module.ngMock.$httpBackend + * @description + * Fake HTTP backend implementation suitable for unit testing application that use the + * {@link angular.module.ng.$http $http service}. + * + * *Note*: For fake http backend implementation suitable for end-to-end testing or backend-less + * development please see {@link angular.module.ngMockE2E.$httpBackend e2e $httpBackend mock}. + * + * During unit testing, we want our unit tests to run quickly and have no external dependencies so + * we don’t want to send {@link https://developer.mozilla.org/en/xmlhttprequest XHR} or + * {@link http://en.wikipedia.org/wiki/JSONP JSONP} requests to a real server. All we really need is + * to verify whether a certain request has been sent or not, or alternatively just let the + * application make requests, respond with pre-trained responses and assert that the end result is + * what we expect it to be. + * + * This mock implementation can be used to respond with static or dynamic responses via the + * `expect` and `when` apis and their shortcuts (`expectGET`, `whenPOST`, etc). + * + * When an Angular application needs some data from a server, it calls the $http service, which + * sends the request to a real server using $httpBackend service. With dependency injection, it is + * easy to inject $httpBackend mock (which has the same API as $httpBackend) and use it to verify + * the requests and respond with some testing data without sending a request to real server. + * + * There are two ways to specify what test data should be returned as http responses by the mock + * backend when the code under test makes http requests: + * + * - `$httpBackend.expect` - specifies a request expectation + * - `$httpBackend.when` - specifies a backend definition + * + * + * # Request Expectations vs Backend Definitions + * + * Request expectations provide a way to make assertions about requests made by the application and + * to define responses for those requests. The test will fail if the expected requests are not made + * or they are made in the wrong order. + * + * Backend definitions allow you to define a fake backend for your application which doesn't assert + * if a particular request was made or not, it just returns a trained response if a request is made. + * The test will pass whether or not the request gets made during testing. + * + * + *
| Request expectations | Backend definitions | |
|---|---|---|
| Syntax | + *.expect(...).respond(...) | + *.when(...).respond(...) | + *
| Typical usage | + *strict unit tests | + *loose (black-box) unit testing | + *
| Fulfills multiple requests | + *NO | + *YES | + *
| Order of requests matters | + *YES | + *NO | + *
| Request required | + *YES | + *NO | + *
| Response required | + *optional (see below) | + *YES | + *
+ // controller
+ function MyController($scope, $http) {
+ $http.get('/auth.py').success(function(data) {
+ $scope.user = data;
+ });
+
+ this.saveMessage = function(message) {
+ $scope.status = 'Saving...';
+ $http.post('/add-msg.py', message).success(function(response) {
+ $scope.status = '';
+ }).error(function() {
+ $scope.status = 'ERROR!';
+ });
+ };
+ }
+
+ // testing controller
+ var $http;
+
+ beforeEach(inject(function($injector) {
+ $httpBackend = $injector.get('$httpBackend');
+
+ // backend definition common for all tests
+ $httpBackend.when('GET', '/auth.py').respond({userId: 'userX'}, {'A-Token': 'xxx'});
+ }));
+
+
+ afterEach(function() {
+ $httpBackend.verifyNoOutstandingExpectation();
+ $httpBackend.verifyNoOutstandingRequest();
+ });
+
+
+ it('should fetch authentication token', function() {
+ $httpBackend.expectGET('/auth.py');
+ var controller = scope.$new(MyController);
+ $httpBackend.flush();
+ });
+
+
+ it('should send msg to server', function() {
+ // now you don’t care about the authentication, but
+ // the controller will still send the request and
+ // $httpBackend will respond without you having to
+ // specify the expectation and response for this request
+ $httpBackend.expectPOST('/add-msg.py', 'message content').respond(201, '');
+
+ var controller = scope.$new(MyController);
+ $httpBackend.flush();
+ controller.saveMessage('message content');
+ expect(controller.status).toBe('Saving...');
+ $httpBackend.flush();
+ expect(controller.status).toBe('');
+ });
+
+
+ it('should send auth header', function() {
+ $httpBackend.expectPOST('/add-msg.py', undefined, function(headers) {
+ // check if the header was send, if it wasn't the expectation won't
+ // match the request and the test will fail
+ return headers['Authorization'] == 'xxx';
+ }).respond(201, '');
+
+ var controller = scope.$new(MyController);
+ controller.saveMessage('whatever');
+ $httpBackend.flush();
+ });
+
+ */
+angular.mock.$HttpBackendProvider = function() {
+ this.$get = [createHttpBackendMock];
+};
+
+/**
+ * General factory function for $httpBackend mock.
+ * Returns instance for unit testing (when no arguments specified):
+ * - passing through is disabled
+ * - auto flushing is disabled
+ *
+ * Returns instance for e2e testing (when `$delegate` and `$browser` specified):
+ * - passing through (delegating request to real backend) is enabled
+ * - auto flushing is enabled
+ *
+ * @param {Object=} $delegate Real $httpBackend instance (allow passing through if specified)
+ * @param {Object=} $browser Auto-flushing enabled if specified
+ * @return {Object} Instance of $httpBackend mock
+ */
+function createHttpBackendMock($delegate, $browser) {
+ var definitions = [],
+ expectations = [],
+ responses = [],
+ responsesPush = angular.bind(responses, responses.push);
+
+ function createResponse(status, data, headers) {
+ if (angular.isFunction(status)) return status;
+
+ return function() {
+ return angular.isNumber(status)
+ ? [status, data, headers]
+ : [200, status, data];
+ };
+ }
+
+ // TODO(vojta): change params to: method, url, data, headers, callback
+ function $httpBackend(method, url, data, callback, headers) {
+ var xhr = new MockXhr(),
+ expectation = expectations[0],
+ wasExpected = false;
+
+ function prettyPrint(data) {
+ return (angular.isString(data) || angular.isFunction(data) || data instanceof RegExp)
+ ? data
+ : angular.toJson(data);
+ }
+
+ if (expectation && expectation.match(method, url)) {
+ if (!expectation.matchData(data))
+ throw Error('Expected ' + expectation + ' with different data\n' +
+ 'EXPECTED: ' + prettyPrint(expectation.data) + '\nGOT: ' + data);
+
+ if (!expectation.matchHeaders(headers))
+ throw Error('Expected ' + expectation + ' with different headers\n' +
+ 'EXPECTED: ' + prettyPrint(expectation.headers) + '\nGOT: ' +
+ prettyPrint(headers));
+
+ expectations.shift();
+
+ if (expectation.response) {
+ responses.push(function() {
+ var response = expectation.response(method, url, data, headers);
+ xhr.$$respHeaders = response[2];
+ callback(response[0], response[1], xhr.getAllResponseHeaders());
+ });
+ return;
+ }
+ wasExpected = true;
+ }
+
+ var i = -1, definition;
+ while ((definition = definitions[++i])) {
+ if (definition.match(method, url, data, headers || {})) {
+ if (definition.response) {
+ // if $browser specified, we do auto flush all requests
+ ($browser ? $browser.defer : responsesPush)(function() {
+ var response = definition.response(method, url, data, headers);
+ xhr.$$respHeaders = response[2];
+ callback(response[0], response[1], xhr.getAllResponseHeaders());
+ });
+ } else if (definition.passThrough) {
+ $delegate(method, url, data, callback, headers);
+ } else throw Error('No response defined !');
+ return;
+ }
+ }
+ throw wasExpected ?
+ Error('No response defined !') :
+ Error('Unexpected request: ' + method + ' ' + url + '\n' +
+ (expectation ? 'Expected ' + expectation : 'No more request expected'));
+ }
+
+ /**
+ * @ngdoc method
+ * @name angular.module.ngMock.$httpBackend#when
+ * @methodOf angular.module.ngMock.$httpBackend
+ * @description
+ * Creates a new backend definition.
+ *
+ * @param {string} method HTTP method.
+ * @param {string|RegExp} url HTTP url.
+ * @param {(string|RegExp)=} data HTTP request body.
+ * @param {(Object|function(Object))=} headers HTTP headers or function that receives http header
+ * object and returns true if the headers match the current definition.
+ * @returns {requestHandler} Returns an object with `respond` method that control how a matched
+ * request is handled.
+ *
+ * - respond – `{function([status,] data[, headers])|function(function(method, url, data, headers)}`
+ * – The respond method takes a set of static data to be returned or a function that can return
+ * an array containing response status (number), response data (string) and response headers
+ * (Object).
+ */
+ $httpBackend.when = function(method, url, data, headers) {
+ var definition = new MockHttpExpectation(method, url, data, headers),
+ chain = {
+ respond: function(status, data, headers) {
+ definition.response = createResponse(status, data, headers);
+ }
+ };
+
+ if ($browser) {
+ chain.passThrough = function() {
+ definition.passThrough = true;
+ };
+ }
+
+ definitions.push(definition);
+ return chain;
+ };
+
+ /**
+ * @ngdoc method
+ * @name angular.module.ngMock.$httpBackend#whenGET
+ * @methodOf angular.module.ngMock.$httpBackend
+ * @description
+ * Creates a new backend definition for GET requests. For more info see `when()`.
+ *
+ * @param {string|RegExp} url HTTP url.
+ * @param {(Object|function(Object))=} headers HTTP headers.
+ * @returns {requestHandler} Returns an object with `respond` method that control how a matched
+ * request is handled.
+ */
+
+ /**
+ * @ngdoc method
+ * @name angular.module.ngMock.$httpBackend#whenHEAD
+ * @methodOf angular.module.ngMock.$httpBackend
+ * @description
+ * Creates a new backend definition for HEAD requests. For more info see `when()`.
+ *
+ * @param {string|RegExp} url HTTP url.
+ * @param {(Object|function(Object))=} headers HTTP headers.
+ * @returns {requestHandler} Returns an object with `respond` method that control how a matched
+ * request is handled.
+ */
+
+ /**
+ * @ngdoc method
+ * @name angular.module.ngMock.$httpBackend#whenDELETE
+ * @methodOf angular.module.ngMock.$httpBackend
+ * @description
+ * Creates a new backend definition for DELETE requests. For more info see `when()`.
+ *
+ * @param {string|RegExp} url HTTP url.
+ * @param {(Object|function(Object))=} headers HTTP headers.
+ * @returns {requestHandler} Returns an object with `respond` method that control how a matched
+ * request is handled.
+ */
+
+ /**
+ * @ngdoc method
+ * @name angular.module.ngMock.$httpBackend#whenPOST
+ * @methodOf angular.module.ngMock.$httpBackend
+ * @description
+ * Creates a new backend definition for POST requests. For more info see `when()`.
+ *
+ * @param {string|RegExp} url HTTP url.
+ * @param {(string|RegExp)=} data HTTP request body.
+ * @param {(Object|function(Object))=} headers HTTP headers.
+ * @returns {requestHandler} Returns an object with `respond` method that control how a matched
+ * request is handled.
+ */
+
+ /**
+ * @ngdoc method
+ * @name angular.module.ngMock.$httpBackend#whenPUT
+ * @methodOf angular.module.ngMock.$httpBackend
+ * @description
+ * Creates a new backend definition for PUT requests. For more info see `when()`.
+ *
+ * @param {string|RegExp} url HTTP url.
+ * @param {(string|RegExp)=} data HTTP request body.
+ * @param {(Object|function(Object))=} headers HTTP headers.
+ * @returns {requestHandler} Returns an object with `respond` method that control how a matched
+ * request is handled.
+ */
+
+ /**
+ * @ngdoc method
+ * @name angular.module.ngMock.$httpBackend#whenJSONP
+ * @methodOf angular.module.ngMock.$httpBackend
+ * @description
+ * Creates a new backend definition for JSONP requests. For more info see `when()`.
+ *
+ * @param {string|RegExp} url HTTP url.
+ * @returns {requestHandler} Returns an object with `respond` method that control how a matched
+ * request is handled.
+ */
+ createShortMethods('when');
+
+
+ /**
+ * @ngdoc method
+ * @name angular.module.ngMock.$httpBackend#expect
+ * @methodOf angular.module.ngMock.$httpBackend
+ * @description
+ * Creates a new request expectation.
+ *
+ * @param {string} method HTTP method.
+ * @param {string|RegExp} url HTTP url.
+ * @param {(string|RegExp)=} data HTTP request body.
+ * @param {(Object|function(Object))=} headers HTTP headers or function that receives http header
+ * object and returns true if the headers match the current expectation.
+ * @returns {requestHandler} Returns an object with `respond` method that control how a matched
+ * request is handled.
+ *
+ * - respond – `{function([status,] data[, headers])|function(function(method, url, data, headers)}`
+ * – The respond method takes a set of static data to be returned or a function that can return
+ * an array containing response status (number), response data (string) and response headers
+ * (Object).
+ */
+ $httpBackend.expect = function(method, url, data, headers) {
+ var expectation = new MockHttpExpectation(method, url, data, headers);
+ expectations.push(expectation);
+ return {
+ respond: function(status, data, headers) {
+ expectation.response = createResponse(status, data, headers);
+ }
+ };
+ };
+
+
+ /**
+ * @ngdoc method
+ * @name angular.module.ngMock.$httpBackend#expectGET
+ * @methodOf angular.module.ngMock.$httpBackend
+ * @description
+ * Creates a new request expectation for GET requests. For more info see `expect()`.
+ *
+ * @param {string|RegExp} url HTTP url.
+ * @param {Object=} headers HTTP headers.
+ * @returns {requestHandler} Returns an object with `respond` method that control how a matched
+ * request is handled. See #expect for more info.
+ */
+
+ /**
+ * @ngdoc method
+ * @name angular.module.ngMock.$httpBackend#expectHEAD
+ * @methodOf angular.module.ngMock.$httpBackend
+ * @description
+ * Creates a new request expectation for HEAD requests. For more info see `expect()`.
+ *
+ * @param {string|RegExp} url HTTP url.
+ * @param {Object=} headers HTTP headers.
+ * @returns {requestHandler} Returns an object with `respond` method that control how a matched
+ * request is handled.
+ */
+
+ /**
+ * @ngdoc method
+ * @name angular.module.ngMock.$httpBackend#expectDELETE
+ * @methodOf angular.module.ngMock.$httpBackend
+ * @description
+ * Creates a new request expectation for DELETE requests. For more info see `expect()`.
+ *
+ * @param {string|RegExp} url HTTP url.
+ * @param {Object=} headers HTTP headers.
+ * @returns {requestHandler} Returns an object with `respond` method that control how a matched
+ * request is handled.
+ */
+
+ /**
+ * @ngdoc method
+ * @name angular.module.ngMock.$httpBackend#expectPOST
+ * @methodOf angular.module.ngMock.$httpBackend
+ * @description
+ * Creates a new request expectation for POST requests. For more info see `expect()`.
+ *
+ * @param {string|RegExp} url HTTP url.
+ * @param {(string|RegExp)=} data HTTP request body.
+ * @param {Object=} headers HTTP headers.
+ * @returns {requestHandler} Returns an object with `respond` method that control how a matched
+ * request is handled.
+ */
+
+ /**
+ * @ngdoc method
+ * @name angular.module.ngMock.$httpBackend#expectPUT
+ * @methodOf angular.module.ngMock.$httpBackend
+ * @description
+ * Creates a new request expectation for PUT requests. For more info see `expect()`.
+ *
+ * @param {string|RegExp} url HTTP url.
+ * @param {(string|RegExp)=} data HTTP request body.
+ * @param {Object=} headers HTTP headers.
+ * @returns {requestHandler} Returns an object with `respond` method that control how a matched
+ * request is handled.
+ */
+
+ /**
+ * @ngdoc method
+ * @name angular.module.ngMock.$httpBackend#expectJSONP
+ * @methodOf angular.module.ngMock.$httpBackend
+ * @description
+ * Creates a new request expectation for JSONP requests. For more info see `expect()`.
+ *
+ * @param {string|RegExp} url HTTP url.
+ * @returns {requestHandler} Returns an object with `respond` method that control how a matched
+ * request is handled.
+ */
+ createShortMethods('expect');
+
+
+ /**
+ * @ngdoc method
+ * @name angular.module.ngMock.$httpBackend#flush
+ * @methodOf angular.module.ngMock.$httpBackend
+ * @description
+ * Flushes all pending requests using the trained responses.
+ *
+ * @param {number=} count Number of responses to flush (in the order they arrived). If undefined,
+ * all pending requests will be flushed. If there are no pending requests when the flush method
+ * is called an exception is thrown (as this typically a sign of programming error).
+ */
+ $httpBackend.flush = function(count) {
+ if (!responses.length) throw Error('No pending request to flush !');
+
+ if (angular.isDefined(count)) {
+ while (count--) {
+ if (!responses.length) throw Error('No more pending request to flush !');
+ responses.shift()();
+ }
+ } else {
+ while (responses.length) {
+ responses.shift()();
+ }
+ }
+ $httpBackend.verifyNoOutstandingExpectation();
+ };
+
+
+ /**
+ * @ngdoc method
+ * @name angular.module.ngMock.$httpBackend#verifyNoOutstandingExpectation
+ * @methodOf angular.module.ngMock.$httpBackend
+ * @description
+ * Verifies that all of the requests defined via the `expect` api were made. If any of the
+ * requests were not made, verifyNoOutstandingExpectation throws an exception.
+ *
+ * Typically, you would call this method following each test case that asserts requests using an
+ * "afterEach" clause.
+ *
+ * + * afterEach($httpBackend.verifyExpectations); + *+ */ + $httpBackend.verifyNoOutstandingExpectation = function() { + if (expectations.length) { + throw Error('Unsatisfied requests: ' + expectations.join(', ')); + } + }; + + + /** + * @ngdoc method + * @name angular.module.ngMock.$httpBackend#verifyNoOutstandingRequest + * @methodOf angular.module.ngMock.$httpBackend + * @description + * Verifies that there are no outstanding requests that need to be flushed. + * + * Typically, you would call this method following each test case that asserts requests using an + * "afterEach" clause. + * + *
+ * afterEach($httpBackend.verifyNoOutstandingRequest); + *+ */ + $httpBackend.verifyNoOutstandingRequest = function() { + if (responses.length) { + throw Error('Unflushed requests: ' + responses.length); + } + }; + + + /** + * @ngdoc method + * @name angular.module.ngMock.$httpBackend#resetExpectations + * @methodOf angular.module.ngMock.$httpBackend + * @description + * Resets all request expectations, but preserves all backend definitions. Typically, you would + * call resetExpectations during a multiple-phase test when you want to reuse the same instance of + * $httpBackend mock. + */ + $httpBackend.resetExpectations = function() { + expectations.length = 0; + responses.length = 0; + }; + + return $httpBackend; + + + function createShortMethods(prefix) { + angular.forEach(['GET', 'DELETE', 'JSONP'], function(method) { + $httpBackend[prefix + method] = function(url, headers) { + return $httpBackend[prefix](method, url, undefined, headers) + } + }); + + angular.forEach(['PUT', 'POST'], function(method) { + $httpBackend[prefix + method] = function(url, data, headers) { + return $httpBackend[prefix](method, url, data, headers) + } + }); + } +}; + +function MockHttpExpectation(method, url, data, headers) { + + this.data = data; + this.headers = headers; + + this.match = function(m, u, d, h) { + if (method != m) return false; + if (!this.matchUrl(u)) return false; + if (angular.isDefined(d) && !this.matchData(d)) return false; + if (angular.isDefined(h) && !this.matchHeaders(h)) return false; + return true; + }; + + this.matchUrl = function(u) { + if (!url) return true; + if (angular.isFunction(url.test)) return url.test(u); + return url == u; + }; + + this.matchHeaders = function(h) { + if (angular.isUndefined(headers)) return true; + if (angular.isFunction(headers)) return headers(h); + return angular.equals(headers, h); + }; + + this.matchData = function(d) { + if (angular.isUndefined(data)) return true; + if (data && angular.isFunction(data.test)) return data.test(d); + if (data && !angular.isString(data)) return angular.toJson(data) == d; + return data == d; + }; + + this.toString = function() { + return method + ' ' + url; + }; +} + +function MockXhr() { + + // hack for testing $http, $httpBackend + MockXhr.$$lastInstance = this; + + this.open = function(method, url, async) { + this.$$method = method; + this.$$url = url; + this.$$async = async; + this.$$reqHeaders = {}; + this.$$respHeaders = {}; + }; + + this.send = function(data) { + this.$$data = data; + }; + + this.setRequestHeader = function(key, value) { + this.$$reqHeaders[key] = value; + }; + + this.getResponseHeader = function(name) { + // the lookup must be case insensitive, that's why we try two quick lookups and full scan at last + var header = this.$$respHeaders[name]; + if (header) return header; + + name = angular.lowercase(name); + header = this.$$respHeaders[name]; + if (header) return header; + + header = undefined; + angular.forEach(this.$$respHeaders, function(headerVal, headerName) { + if (!header && angular.lowercase(headerName) == name) header = headerVal; + }); + return header; + }; + + this.getAllResponseHeaders = function() { + var lines = []; + + angular.forEach(this.$$respHeaders, function(value, key) { + lines.push(key + ': ' + value); + }); + return lines.join('\n'); + }; + + this.abort = angular.noop; +} + +/** + * @ngdoc overview + * @name angular.module.ngMock + * @description + * + * The `ngMock` is an angular module which is used with `ng` module and adds unit-test configuration as well as useful + * mocks to the {@link angular.module.AUTO.$injector $injector}. + */ +angular.module('ngMock', ['ng']).provider({ + $browser: angular.mock.$BrowserProvider, + $exceptionHandler: angular.mock.$ExceptionHandlerProvider, + $log: angular.mock.$LogProvider, + $httpBackend: angular.mock.$HttpBackendProvider +}); + + + +/** + * @ngdoc overview + * @name angular.module.ngMockE2E + * @description + * + * The `ngMockE2E` is an angular module which contains mocks suitable for end-to-end testing. + * Currently there is only one mock present in this module - + * the {@link angular.module.ngMockE2E.$httpBackend e2e $httpBackend} mock. + */ +angular.module('ngMockE2E', ['ng']).config(function($provide) { + $provide.decorator('$httpBackend', angular.mock.e2e.$httpBackendDecorator); +}); + +/** + * @ngdoc object + * @name angular.module.ngMockE2E.$httpBackend + * @description + * Fake HTTP backend implementation suitable for end-to-end testing or backend-less development of + * applications that use the {@link angular.module.ng.$http $http service}. + * + * *Note*: For fake http backend implementation suitable for unit testing please see + * {@link angular.module.ngMock.$httpBackend unit-testing $httpBackend mock}. + * + * This implementation can be used to respond with static or dynamic responses via the `when` api + * and its shortcuts (`whenGET`, `whenPOST`, etc) and optionally pass through requests to the + * real $httpBackend for specific requests (e.g. to interact with certain remote apis or to fetch + * templates from a webserver). + * + * As opposed to unit-testing, in an end-to-end testing scenario or in scenario when an application + * is being developed with the real backend api replaced with a mock, it is often desirable for + * certain category of requests to bypass the mock and issue a real http request (e.g. to fetch + * templates or static files from the webserver). To configure the backend with this behavior + * use the `passThrough` request handler of `when` instead of `respond`. + * + * Additionally, we don't want to manually have to flush mocked out requests like we do during unit + * testing. For this reason the e2e $httpBackend automatically flushes mocked out requests + * automatically, closely simulating the behavior of the XMLHttpRequest object. + * + * To setup the application to run with this http backend, you have to create a module that depends + * on the `ngMockE2E` and your application modules and defines the fake backend: + * + *
+ * myAppDev = angular.module('myAppDev', ['myApp', 'ngMockE2E']);
+ * myAppDev.run(function($httpBackend) {
+ * phones = [{name: 'phone1'}, {name: 'phone2'}];
+ *
+ * // returns the current list of phones
+ * $httpBackend.whenGET('/phones').respond(phones);
+ *
+ * // adds a new phone to the phones array
+ * $httpBackend.whenPOST('/phones').respond(function(method, url, data) {
+ * phones.push(angular.fromJSON(data));
+ * });
+ * $httpBackend.whenGET(/^\/templates\//).passThrough();
+ * //...
+ * });
+ *
+ *
+ * Afterwards, bootstrap your app with this new module.
+ */
+
+/**
+ * @ngdoc method
+ * @name angular.module.ngMockE2E.$httpBackend#when
+ * @methodOf angular.module.ngMockE2E.$httpBackend
+ * @description
+ * Creates a new backend definition.
+ *
+ * @param {string} method HTTP method.
+ * @param {string|RegExp} url HTTP url.
+ * @param {(string|RegExp)=} data HTTP request body.
+ * @param {(Object|function(Object))=} headers HTTP headers or function that receives http header
+ * object and returns true if the headers match the current definition.
+ * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
+ * control how a matched request is handled.
+ *
+ * - respond – `{function([status,] data[, headers])|function(function(method, url, data, headers)}`
+ * – The respond method takes a set of static data to be returned or a function that can return
+ * an array containing response status (number), response data (string) and response headers
+ * (Object).
+ * - passThrough – `{function()}` – Any request matching a backend definition with `passThrough`
+ * handler, will be pass through to the real backend (an XHR request will be made to the
+ * server.
+ */
+
+/**
+ * @ngdoc method
+ * @name angular.module.ngMockE2E.$httpBackend#whenGET
+ * @methodOf angular.module.ngMockE2E.$httpBackend
+ * @description
+ * Creates a new backend definition for GET requests. For more info see `when()`.
+ *
+ * @param {string|RegExp} url HTTP url.
+ * @param {(Object|function(Object))=} headers HTTP headers.
+ * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
+ * control how a matched request is handled.
+ */
+
+/**
+ * @ngdoc method
+ * @name angular.module.ngMockE2E.$httpBackend#whenHEAD
+ * @methodOf angular.module.ngMockE2E.$httpBackend
+ * @description
+ * Creates a new backend definition for HEAD requests. For more info see `when()`.
+ *
+ * @param {string|RegExp} url HTTP url.
+ * @param {(Object|function(Object))=} headers HTTP headers.
+ * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
+ * control how a matched request is handled.
+ */
+
+/**
+ * @ngdoc method
+ * @name angular.module.ngMockE2E.$httpBackend#whenDELETE
+ * @methodOf angular.module.ngMockE2E.$httpBackend
+ * @description
+ * Creates a new backend definition for DELETE requests. For more info see `when()`.
+ *
+ * @param {string|RegExp} url HTTP url.
+ * @param {(Object|function(Object))=} headers HTTP headers.
+ * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
+ * control how a matched request is handled.
+ */
+
+/**
+ * @ngdoc method
+ * @name angular.module.ngMockE2E.$httpBackend#whenPOST
+ * @methodOf angular.module.ngMockE2E.$httpBackend
+ * @description
+ * Creates a new backend definition for POST requests. For more info see `when()`.
+ *
+ * @param {string|RegExp} url HTTP url.
+ * @param {(string|RegExp)=} data HTTP request body.
+ * @param {(Object|function(Object))=} headers HTTP headers.
+ * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
+ * control how a matched request is handled.
+ */
+
+/**
+ * @ngdoc method
+ * @name angular.module.ngMockE2E.$httpBackend#whenPUT
+ * @methodOf angular.module.ngMockE2E.$httpBackend
+ * @description
+ * Creates a new backend definition for PUT requests. For more info see `when()`.
+ *
+ * @param {string|RegExp} url HTTP url.
+ * @param {(string|RegExp)=} data HTTP request body.
+ * @param {(Object|function(Object))=} headers HTTP headers.
+ * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
+ * control how a matched request is handled.
+ */
+
+/**
+ * @ngdoc method
+ * @name angular.module.ngMockE2E.$httpBackend#whenJSONP
+ * @methodOf angular.module.ngMockE2E.$httpBackend
+ * @description
+ * Creates a new backend definition for JSONP requests. For more info see `when()`.
+ *
+ * @param {string|RegExp} url HTTP url.
+ * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
+ * control how a matched request is handled.
+ */
+angular.mock.e2e = {};
+angular.mock.e2e.$httpBackendDecorator = ['$delegate', '$browser', createHttpBackendMock];
+
+
+
+window.jstestdriver && (function(window) {
+ /**
+ * Global method to output any number of objects into JSTD console. Useful for debugging.
+ */
+ window.dump = function() {
+ var args = [];
+ angular.forEach(arguments, function(arg) {
+ args.push(angular.mock.dump(arg));
+ });
+ jstestdriver.console.log.apply(jstestdriver.console, args);
+ if (window.console) {
+ window.console.log.apply(window.console, args);
+ }
+ };
+})(window);
+
+
+window.jasmine && (function(window) {
+
+ function getCurrentSpec() {
+ return jasmine.getEnv().currentSpec;
+ }
+
+ function isSpecRunning() {
+ var spec = getCurrentSpec();
+ return spec && spec.queue.running;
+ }
+
+ /**
+ * @ngdoc function
+ * @name angular.mock.module
+ * @description
+ *
+ * *NOTE*: This is function is also published on window for easy access.
+ *
+ * angular.module('myApplicationModule', [])
+ * .value('mode', 'app')
+ * .value('version', 'v1.0.1');
+ *
+ *
+ * describe('MyApp', function() {
+ *
+ * // You need to load modules that you want to test,
+ * // it loads only the "ng" module by default.
+ * beforeEach(module('myApplicationModule'));
+ *
+ *
+ * // inject() is used to inject arguments of all given functions
+ * it('should provide a version', inject(function(mode, version) {
+ * expect(version).toEqual('v1.0.1');
+ * expect(mode).toEqual('app');
+ * }));
+ *
+ *
+ * // The inject and module method can also be used inside of the it or beforeEach
+ * it('should override a version and test the new version is injected', function() {
+ * // module() takes functions or strings (module aliases)
+ * module(function($provide) {
+ * $provide.value('version', 'overridden'); // override version here
+ * });
+ *
+ * inject(function(version) {
+ * expect(version).toEqual('overridden');
+ * });
+ * ));
+ * });
+ *
+ *
+ *
+ * @param {...Function} fns any number of functions which will be injected using the injector.
+ */
+ window.inject = angular.mock.inject = function() {
+ var blockFns = Array.prototype.slice.call(arguments, 0);
+ var stack = new Error('Declaration Location').stack;
+ return isSpecRunning() ? workFn() : workFn;
+ /////////////////////
+ function workFn() {
+ var spec = getCurrentSpec();
+ var modules = spec.$modules || [];
+ modules.unshift('ngMock');
+ modules.unshift('ng');
+ var injector = spec.$injector;
+ if (!injector) {
+ injector = spec.$injector = angular.injector(modules);
+ }
+ for(var i = 0, ii = blockFns.length; i < ii; i++) {
+ try {
+ injector.invoke(blockFns[i] || angular.noop, this);
+ } catch (e) {
+ if(e.stack) e.stack += '\n' + stack;
+ throw e;
+ }
+ }
+ }
+ }
+})(window);
--
cgit v1.2.3