/** * @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.origDate.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($http) {
     var scope = this;
     $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']).service({ $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);
  };
})(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('myTestsModule', [], function($provide) {
   *     $provide.value('mode', 'test');
   *   });
   *
   *   describe('MyApp', function() {
   *
   *     // you can list multiple module function or aliases
   *     // which will be used in creating the injector
   *     beforeEach(module('myTestModule', function($provide) {
   *       // $provide service is configured as needed
   *       $provide.value('version', 'v1.0.1');
   *     });
   *
   *     // The inject() is used to get references.
   *     it('should provide a version', inject(function(mode, version) {
   *       expect(version).toEqual('v1.0.1');
   *       expect(mode).toEqual('test');
   *     });
   *
   *     // 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(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);