/**
* @license AngularJS v"NG_VERSION_FULL"
* (c) 2010-2012 Google, Inc. 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 = {};
/**
* ! This is a private undocumented service !
*
* @name ngMock.$browser
*
* @description
* This service is a mock implementation of {@link 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 ng.$browser $browser}, except
* that there are several helper methods available which can be used in tests.
*/
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;
};
/**
* @name ngMock.$browser#defer.flush
* @methodOf 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();
}
};
/**
* @name ngMock.$browser#defer.flushNext
* @methodOf ngMock.$browser
*
* @description
* Flushes next pending request and compares it to the provided delay
*
* @param {number=} expectedDelay the delay value that will be asserted against the delay of the next timeout function
*/
self.defer.flushNext = function(expectedDelay) {
var tick = self.deferredFns.shift();
expect(tick.time).toEqual(expectedDelay);
tick.fn();
};
/**
* @name ngMock.$browser#defer.now
* @propertyOf ngMock.$browser
*
* @description
* Current milliseconds mock time.
*/
self.$$baseHref = '';
self.baseHref = function() {
return this.$$baseHref;
};
};
angular.mock.$Browser.prototype = {
/**
* @name ngMock.$browser#poll
* @methodOf 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 ngMock.$exceptionHandlerProvider
*
* @description
* Configures the mock implementation of {@link ng.$exceptionHandler} to rethrow or to log errors passed
* into the `$exceptionHandler`.
*/
/**
* @ngdoc object
* @name ngMock.$exceptionHandler
*
* @description
* Mock implementation of {@link ng.$exceptionHandler} that rethrows or logs errors passed
* into it. See {@link ngMock.$exceptionHandlerProvider $exceptionHandlerProvider} for configuration
* information.
*
*
* <pre>
* describe('$exceptionHandlerProvider', function() {
*
* it('should capture log messages and exceptions', function() {
*
* module(function($exceptionHandlerProvider) {
* $exceptionHandlerProvider.mode('log');
* });
*
* inject(function($log, $exceptionHandler, $timeout) {
* $timeout(function() { $log.log(1); });
* $timeout(function() { $log.log(2); throw 'banana peel'; });
* $timeout(function() { $log.log(3); });
* expect($exceptionHandler.errors).toEqual([]);
* expect($log.assertEmpty());
* $timeout.flush();
* expect($exceptionHandler.errors).toEqual(['banana peel']);
* expect($log.log.logs).toEqual([[1], [2], [3]]);
* });
* });
* });
* </pre>
*/
angular.mock.$ExceptionHandlerProvider = function() {
var handler;
/**
* @ngdoc method
* @name ngMock.$exceptionHandlerProvider#mode
* @methodOf ngMock.$exceptionHandlerProvider
*
* @description
* Sets the logging mode.
*
* @param {string} mode Mode of operation, defaults to `rethrow`.
*
* - `rethrow`: If any errors 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 thrown, for this case the `log` mode stores an
* array of errors in `$exceptionHandler.errors`, to allow later assertion of them.
* See {@link ngMock.$log#assertEmpty assertEmpty()} and
* {@link 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 ngMock.$log
*
* @description
* Mock implementation of {@link 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() {
var debug = true;
function concat(array1, array2, index) {
return array1.concat(Array.prototype.slice.call(array2, index));
}
this.debugEnabled = function(flag) {
if (isDefined(flag)) {
debug = flag;
return this;
} else {
return debug;
}
};
this.$get = function () {
var $log = {
log: function() { $log.log.logs.push(concat([], arguments, 0));
|