vendor/assets/javascripts/unstable/angular-mocks.js in angularjs-rails-1.2.14 vs vendor/assets/javascripts/unstable/angular-mocks.js in angularjs-rails-1.2.15
- old
+ new
@@ -1,37 +1,38 @@
/**
- * @license AngularJS v1.1.5
- * (c) 2010-2012 Google, Inc. http://angularjs.org
+ * @license AngularJS v1.3.0-beta.3
+ * (c) 2010-2014 Google, Inc. http://angularjs.org
* License: MIT
- *
- * TODO(vojta): wrap whole file into closure during build
*/
+(function(window, angular, undefined) {
+'use strict';
+
/**
- * @ngdoc overview
+ * @ngdoc object
* @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
+ * @name $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(){
+ this.$get = function() {
return new angular.mock.$Browser();
};
};
angular.mock.$Browser = function() {
@@ -73,10 +74,16 @@
self.deferredFns.sort(function(a,b){ return a.time - b.time;});
return self.deferredNextId++;
};
+ /**
+ * @name $browser#defer.now
+ *
+ * @description
+ * Current milliseconds mock time.
+ */
self.defer.now = 0;
self.defer.cancel = function(deferId) {
var fnIndex;
@@ -93,12 +100,11 @@
return false;
};
/**
- * @name ngMock.$browser#defer.flush
- * @methodOf ngMock.$browser
+ * @name $browser#defer.flush
*
* @description
* Flushes all pending requests and executes the defer callbacks.
*
* @param {number=} number of milliseconds to flush. See {@link #defer.now}
@@ -108,36 +114,28 @@
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');
+ throw new 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.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
+ * @name $browser#poll
*
* @description
* run all fns in pollFns
*/
poll: function poll() {
@@ -160,11 +158,11 @@
return this.$$url;
},
cookies: function(name, value) {
if (name) {
- if (value == undefined) {
+ if (angular.isUndefined(value)) {
delete this.cookieHash[name];
} else {
if (angular.isString(value) && //strings only
value.length <= 4096) { //strict cookie storage limits
this.cookieHash[name] = value;
@@ -184,29 +182,29 @@
}
};
/**
- * @ngdoc object
- * @name ngMock.$exceptionHandlerProvider
+ * @ngdoc provider
+ * @name $exceptionHandlerProvider
*
* @description
- * Configures the mock implementation of {@link ng.$exceptionHandler} to rethrow or to log errors passed
- * into the `$exceptionHandler`.
+ * Configures the mock implementation of {@link ng.$exceptionHandler} to rethrow or to log errors
+ * passed into the `$exceptionHandler`.
*/
/**
- * @ngdoc object
- * @name ngMock.$exceptionHandler
+ * @ngdoc service
+ * @name $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>
+ * ```js
* describe('$exceptionHandlerProvider', function() {
*
* it('should capture log messages and exceptions', function() {
*
* module(function($exceptionHandlerProvider) {
@@ -223,33 +221,32 @@
* 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
+ * @name $exceptionHandlerProvider#mode
*
* @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()}
+ * - `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) {
@@ -268,11 +265,11 @@
};
handler.errors = errors;
break;
default:
- throw Error("Unknown mode '" + mode + "', only 'log'/'rethrow' modes are allowed!");
+ throw new Error("Unknown mode '" + mode + "', only 'log'/'rethrow' modes are allowed!");
}
};
this.$get = function() {
return handler;
@@ -282,124 +279,148 @@
};
/**
* @ngdoc service
- * @name ngMock.$log
+ * @name $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 (angular.isDefined(flag)) {
+ debug = flag;
+ return this;
+ } else {
+ return debug;
+ }
+ };
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)); }
+ error: function() { $log.error.logs.push(concat([], arguments, 0)); },
+ debug: function() {
+ if (debug) {
+ $log.debug.logs.push(concat([], arguments, 0));
+ }
+ }
};
/**
* @ngdoc method
- * @name ngMock.$log#reset
- * @methodOf ngMock.$log
+ * @name $log#reset
*
* @description
* Reset all of the logging arrays to empty.
*/
$log.reset = function () {
/**
* @ngdoc property
- * @name ngMock.$log#log.logs
- * @propertyOf ngMock.$log
+ * @name $log#log.logs
*
* @description
* Array of messages logged using {@link ngMock.$log#log}.
*
* @example
- * <pre>
+ * ```js
* $log.log('Some Log');
* var first = $log.log.logs.unshift();
- * </pre>
+ * ```
*/
$log.log.logs = [];
/**
* @ngdoc property
- * @name ngMock.$log#warn.logs
- * @propertyOf ngMock.$log
+ * @name $log#info.logs
*
* @description
- * Array of messages logged using {@link ngMock.$log#warn}.
+ * Array of messages logged using {@link ngMock.$log#info}.
*
* @example
- * <pre>
- * $log.warn('Some Warning');
- * var first = $log.warn.logs.unshift();
- * </pre>
+ * ```js
+ * $log.info('Some Info');
+ * var first = $log.info.logs.unshift();
+ * ```
*/
- $log.warn.logs = [];
+ $log.info.logs = [];
/**
* @ngdoc property
- * @name ngMock.$log#info.logs
- * @propertyOf ngMock.$log
+ * @name $log#warn.logs
*
* @description
- * Array of messages logged using {@link ngMock.$log#info}.
+ * Array of messages logged using {@link ngMock.$log#warn}.
*
* @example
- * <pre>
- * $log.info('Some Info');
- * var first = $log.info.logs.unshift();
- * </pre>
+ * ```js
+ * $log.warn('Some Warning');
+ * var first = $log.warn.logs.unshift();
+ * ```
*/
- $log.info.logs = [];
+ $log.warn.logs = [];
/**
* @ngdoc property
- * @name ngMock.$log#error.logs
- * @propertyOf ngMock.$log
+ * @name $log#error.logs
*
* @description
* Array of messages logged using {@link ngMock.$log#error}.
*
* @example
- * <pre>
- * $log.log('Some Error');
+ * ```js
+ * $log.error('Some Error');
* var first = $log.error.logs.unshift();
- * </pre>
+ * ```
*/
$log.error.logs = [];
+ /**
+ * @ngdoc property
+ * @name $log#debug.logs
+ *
+ * @description
+ * Array of messages logged using {@link ngMock.$log#debug}.
+ *
+ * @example
+ * ```js
+ * $log.debug('Some Error');
+ * var first = $log.debug.logs.unshift();
+ * ```
+ */
+ $log.debug.logs = [];
};
/**
* @ngdoc method
- * @name ngMock.$log#assertEmpty
- * @methodOf ngMock.$log
+ * @name $log#assertEmpty
*
* @description
- * Assert that the all of the logging methods have no logged messages. If messages present, an exception is thrown.
+ * 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(['error', 'warn', 'info', 'log', 'debug'], function(logLevel) {
angular.forEach($log[logLevel].logs, function(log) {
angular.forEach(log, function (logItem) {
- errors.push('MOCK $log (' + logLevel + '): ' + String(logItem) + '\n' + (logItem.stack || ''));
+ 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.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'));
}
};
@@ -407,276 +428,399 @@
return $log;
};
};
-(function() {
- var R_ISO8061_STR = /^(\d{4})-?(\d\d)-?(\d\d)(?:T(\d\d)(?:\:?(\d\d)(?:\:?(\d\d)(?:\.(\d{3}))?)?)?(Z|([+-])(\d\d):?(\d\d)))?$/;
+/**
+ * @ngdoc service
+ * @name $interval
+ *
+ * @description
+ * Mock implementation of the $interval service.
+ *
+ * Use {@link ngMock.$interval#flush `$interval.flush(millis)`} to
+ * move forward by `millis` milliseconds and trigger any functions scheduled to run in that
+ * time.
+ *
+ * @param {function()} fn A function that should be called repeatedly.
+ * @param {number} delay Number of milliseconds between each function call.
+ * @param {number=} [count=0] Number of times to repeat. If not set, or 0, will repeat
+ * indefinitely.
+ * @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise
+ * will invoke `fn` within the {@link ng.$rootScope.Scope#$apply $apply} block.
+ * @returns {promise} A promise which will be notified on each iteration.
+ */
+angular.mock.$IntervalProvider = function() {
+ this.$get = ['$rootScope', '$q',
+ function($rootScope, $q) {
+ var repeatFns = [],
+ nextRepeatId = 0,
+ now = 0;
- function jsonStringToDate(string){
- var match;
- if (match = string.match(R_ISO8061_STR)) {
- var date = new Date(0),
- tzHour = 0,
- tzMin = 0;
- if (match[9]) {
- tzHour = int(match[9] + match[10]);
- tzMin = int(match[9] + match[11]);
+ var $interval = function(fn, delay, count, invokeApply) {
+ var deferred = $q.defer(),
+ promise = deferred.promise,
+ iteration = 0,
+ skipApply = (angular.isDefined(invokeApply) && !invokeApply);
+
+ count = (angular.isDefined(count)) ? count : 0,
+ promise.then(null, null, fn);
+
+ promise.$$intervalId = nextRepeatId;
+
+ function tick() {
+ deferred.notify(iteration++);
+
+ if (count > 0 && iteration >= count) {
+ var fnIndex;
+ deferred.resolve(iteration);
+
+ angular.forEach(repeatFns, function(fn, index) {
+ if (fn.id === promise.$$intervalId) fnIndex = index;
+ });
+
+ if (fnIndex !== undefined) {
+ repeatFns.splice(fnIndex, 1);
+ }
+ }
+
+ if (!skipApply) $rootScope.$apply();
}
- date.setUTCFullYear(int(match[1]), int(match[2]) - 1, int(match[3]));
- date.setUTCHours(int(match[4]||0) - tzHour, int(match[5]||0) - tzMin, int(match[6]||0), int(match[7]||0));
- return date;
+
+ repeatFns.push({
+ nextTime:(now + delay),
+ delay: delay,
+ fn: tick,
+ id: nextRepeatId,
+ deferred: deferred
+ });
+ repeatFns.sort(function(a,b){ return a.nextTime - b.nextTime;});
+
+ nextRepeatId++;
+ return promise;
+ };
+ /**
+ * @ngdoc method
+ * @name $interval#cancel
+ *
+ * @description
+ * Cancels a task associated with the `promise`.
+ *
+ * @param {promise} promise A promise from calling the `$interval` function.
+ * @returns {boolean} Returns `true` if the task was successfully cancelled.
+ */
+ $interval.cancel = function(promise) {
+ if(!promise) return false;
+ var fnIndex;
+
+ angular.forEach(repeatFns, function(fn, index) {
+ if (fn.id === promise.$$intervalId) fnIndex = index;
+ });
+
+ if (fnIndex !== undefined) {
+ repeatFns[fnIndex].deferred.reject('canceled');
+ repeatFns.splice(fnIndex, 1);
+ return true;
+ }
+
+ return false;
+ };
+
+ /**
+ * @ngdoc method
+ * @name $interval#flush
+ * @description
+ *
+ * Runs interval tasks scheduled to be run in the next `millis` milliseconds.
+ *
+ * @param {number=} millis maximum timeout amount to flush up until.
+ *
+ * @return {number} The amount of time moved forward.
+ */
+ $interval.flush = function(millis) {
+ now += millis;
+ while (repeatFns.length && repeatFns[0].nextTime <= now) {
+ var task = repeatFns[0];
+ task.fn();
+ task.nextTime += task.delay;
+ repeatFns.sort(function(a,b){ return a.nextTime - b.nextTime;});
+ }
+ return millis;
+ };
+
+ return $interval;
+ }];
+};
+
+
+/* jshint -W101 */
+/* The R_ISO8061_STR regex is never going to fit into the 100 char limit!
+ * This directive should go inside the anonymous function but a bug in JSHint means that it would
+ * not be enacted early enough to prevent the warning.
+ */
+var R_ISO8061_STR = /^(\d{4})-?(\d\d)-?(\d\d)(?:T(\d\d)(?:\:?(\d\d)(?:\:?(\d\d)(?:\.(\d{3}))?)?)?(Z|([+-])(\d\d):?(\d\d)))?$/;
+
+function jsonStringToDate(string) {
+ var match;
+ if (match = string.match(R_ISO8061_STR)) {
+ var date = new Date(0),
+ tzHour = 0,
+ tzMin = 0;
+ if (match[9]) {
+ tzHour = int(match[9] + match[10]);
+ tzMin = int(match[9] + match[11]);
}
- return string;
+ date.setUTCFullYear(int(match[1]), int(match[2]) - 1, int(match[3]));
+ date.setUTCHours(int(match[4]||0) - tzHour,
+ int(match[5]||0) - tzMin,
+ int(match[6]||0),
+ int(match[7]||0));
+ return date;
}
+ return string;
+}
- function int(str) {
- return parseInt(str, 10);
+function int(str) {
+ return parseInt(str, 10);
+}
+
+function padNumber(num, digits, trim) {
+ var neg = '';
+ if (num < 0) {
+ neg = '-';
+ num = -num;
}
+ num = '' + num;
+ while(num.length < digits) num = '0' + num;
+ if (trim)
+ num = num.substr(num.length - digits);
+ return neg + num;
+}
- function padNumber(num, digits, trim) {
- var neg = '';
- if (num < 0) {
- neg = '-';
- num = -num;
- }
- num = '' + num;
- while(num.length < digits) num = '0' + num;
- if (trim)
- num = num.substr(num.length - digits);
- return neg + num;
+
+/**
+ * @ngdoc type
+ * @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 constructor 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".
+ *
+ * ```js
+ * 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;
+ * newYearInBratislava.getSeconds() => 0;
+ * ```
+ *
+ */
+angular.mock.TzDate = function (offset, timestamp) {
+ var self = new Date(0);
+ if (angular.isString(timestamp)) {
+ var tsStr = timestamp;
+
+ self.origDate = jsonStringToDate(timestamp);
+
+ 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);
- /**
- * @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 constructor 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".
- *
- * <pre>
- * 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;
- * newYearInBratislava.getSeconds() => 0;
- * </pre>
- *
- */
- angular.mock.TzDate = function (offset, timestamp) {
- var self = new Date(0);
- if (angular.isString(timestamp)) {
- var tsStr = timestamp;
+ self.getTime = function() {
+ return self.date.getTime() - self.offsetDiff;
+ };
- self.origDate = jsonStringToDate(timestamp);
+ self.toLocaleDateString = function() {
+ return self.date.toLocaleDateString();
+ };
- 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);
- }
+ self.getFullYear = function() {
+ return self.date.getFullYear();
+ };
- var localOffset = new Date(timestamp).getTimezoneOffset();
- self.offsetDiff = localOffset*60*1000 - offset*1000*60*60;
- self.date = new Date(timestamp + self.offsetDiff);
+ self.getMonth = function() {
+ return self.date.getMonth();
+ };
- self.getTime = function() {
- return self.date.getTime() - self.offsetDiff;
- };
+ self.getDate = function() {
+ return self.date.getDate();
+ };
- self.toLocaleDateString = function() {
- return self.date.toLocaleDateString();
- };
+ self.getHours = function() {
+ return self.date.getHours();
+ };
- self.getFullYear = function() {
- return self.date.getFullYear();
- };
+ self.getMinutes = function() {
+ return self.date.getMinutes();
+ };
- self.getMonth = function() {
- return self.date.getMonth();
- };
+ self.getSeconds = function() {
+ return self.date.getSeconds();
+ };
- self.getDate = function() {
- return self.date.getDate();
- };
+ self.getMilliseconds = function() {
+ return self.date.getMilliseconds();
+ };
- self.getHours = function() {
- return self.date.getHours();
- };
+ self.getTimezoneOffset = function() {
+ return offset * 60;
+ };
- self.getMinutes = function() {
- return self.date.getMinutes();
- };
+ self.getUTCFullYear = function() {
+ return self.origDate.getUTCFullYear();
+ };
- self.getSeconds = function() {
- return self.date.getSeconds();
- };
+ self.getUTCMonth = function() {
+ return self.origDate.getUTCMonth();
+ };
- self.getMilliseconds = function() {
- return self.date.getMilliseconds();
- };
+ self.getUTCDate = function() {
+ return self.origDate.getUTCDate();
+ };
- self.getTimezoneOffset = function() {
- return offset * 60;
- };
+ self.getUTCHours = function() {
+ return self.origDate.getUTCHours();
+ };
- self.getUTCFullYear = function() {
- return self.origDate.getUTCFullYear();
- };
+ self.getUTCMinutes = function() {
+ return self.origDate.getUTCMinutes();
+ };
- self.getUTCMonth = function() {
- return self.origDate.getUTCMonth();
- };
+ self.getUTCSeconds = function() {
+ return self.origDate.getUTCSeconds();
+ };
- self.getUTCDate = function() {
- return self.origDate.getUTCDate();
- };
+ self.getUTCMilliseconds = function() {
+ return self.origDate.getUTCMilliseconds();
+ };
- self.getUTCHours = function() {
- return self.origDate.getUTCHours();
- };
+ self.getDay = function() {
+ return self.date.getDay();
+ };
- self.getUTCMinutes = function() {
- return self.origDate.getUTCMinutes();
+ // provide this method only on browsers that already have it
+ if (self.toISOString) {
+ self.toISOString = function() {
+ return padNumber(self.origDate.getUTCFullYear(), 4) + '-' +
+ padNumber(self.origDate.getUTCMonth() + 1, 2) + '-' +
+ padNumber(self.origDate.getUTCDate(), 2) + 'T' +
+ padNumber(self.origDate.getUTCHours(), 2) + ':' +
+ padNumber(self.origDate.getUTCMinutes(), 2) + ':' +
+ padNumber(self.origDate.getUTCSeconds(), 2) + '.' +
+ padNumber(self.origDate.getUTCMilliseconds(), 3) + 'Z';
};
+ }
- self.getUTCSeconds = function() {
- return self.origDate.getUTCSeconds();
- };
+ //hide all methods not implemented in this mock that the Date prototype exposes
+ var unimplementedMethods = ['getUTCDay',
+ 'getYear', 'setDate', 'setFullYear', 'setHours', 'setMilliseconds',
+ 'setMinutes', 'setMonth', 'setSeconds', 'setTime', 'setUTCDate', 'setUTCFullYear',
+ 'setUTCHours', 'setUTCMilliseconds', 'setUTCMinutes', 'setUTCMonth', 'setUTCSeconds',
+ 'setYear', 'toDateString', 'toGMTString', 'toJSON', 'toLocaleFormat', 'toLocaleString',
+ 'toLocaleTimeString', 'toSource', 'toString', 'toTimeString', 'toUTCString', 'valueOf'];
- self.getUTCMilliseconds = function() {
- return self.origDate.getUTCMilliseconds();
+ angular.forEach(unimplementedMethods, function(methodName) {
+ self[methodName] = function() {
+ throw new Error("Method '" + methodName + "' is not implemented in the TzDate mock");
};
+ });
- self.getDay = function() {
- return self.date.getDay();
- };
+ return self;
+};
- // provide this method only on browsers that already have it
- if (self.toISOString) {
- self.toISOString = function() {
- return padNumber(self.origDate.getUTCFullYear(), 4) + '-' +
- padNumber(self.origDate.getUTCMonth() + 1, 2) + '-' +
- padNumber(self.origDate.getUTCDate(), 2) + 'T' +
- padNumber(self.origDate.getUTCHours(), 2) + ':' +
- padNumber(self.origDate.getUTCMinutes(), 2) + ':' +
- padNumber(self.origDate.getUTCSeconds(), 2) + '.' +
- padNumber(self.origDate.getUTCMilliseconds(), 3) + 'Z'
- }
- }
+//make "tzDateInstance instanceof Date" return true
+angular.mock.TzDate.prototype = Date.prototype;
+/* jshint +W101 */
- //hide all methods not implemented in this mock that the Date prototype exposes
- var unimplementedMethods = ['getUTCDay',
- 'getYear', 'setDate', 'setFullYear', 'setHours', 'setMilliseconds',
- 'setMinutes', 'setMonth', 'setSeconds', 'setTime', 'setUTCDate', 'setUTCFullYear',
- 'setUTCHours', 'setUTCMilliseconds', 'setUTCMinutes', 'setUTCMonth', 'setUTCSeconds',
- 'setYear', 'toDateString', 'toGMTString', 'toJSON', 'toLocaleFormat', 'toLocaleString',
- 'toLocaleTimeString', 'toSource', 'toString', 'toTimeString', 'toUTCString', 'valueOf'];
+angular.mock.animate = angular.module('ngAnimateMock', ['ng'])
- angular.forEach(unimplementedMethods, function(methodName) {
- self[methodName] = function() {
- throw Error("Method '" + methodName + "' is not implemented in the TzDate mock");
+ .config(['$provide', function($provide) {
+
+ var reflowQueue = [];
+ $provide.value('$$animateReflow', function(fn) {
+ var index = reflowQueue.length;
+ reflowQueue.push(fn);
+ return function cancel() {
+ reflowQueue.splice(index, 1);
};
});
- return self;
- };
+ $provide.decorator('$animate', function($delegate, $$asyncCallback) {
+ var animate = {
+ queue : [],
+ enabled : $delegate.enabled,
+ triggerCallbacks : function() {
+ $$asyncCallback.flush();
+ },
+ triggerReflow : function() {
+ angular.forEach(reflowQueue, function(fn) {
+ fn();
+ });
+ reflowQueue = [];
+ }
+ };
- //make "tzDateInstance instanceof Date" return true
- angular.mock.TzDate.prototype = Date.prototype;
-})();
+ angular.forEach(
+ ['enter','leave','move','addClass','removeClass','setClass'], function(method) {
+ animate[method] = function() {
+ animate.queue.push({
+ event : method,
+ element : arguments[0],
+ args : arguments
+ });
+ $delegate[method].apply($delegate, arguments);
+ };
+ });
-/**
- * @ngdoc function
- * @name angular.mock.createMockWindow
- * @description
- *
- * This function creates a mock window object useful for controlling access ot setTimeout, but mocking out
- * sufficient window's properties to allow Angular to execute.
- *
- * @example
- *
- * <pre>
- beforeEach(module(function($provide) {
- $provide.value('$window', window = angular.mock.createMockWindow());
- }));
-
- it('should do something', inject(function($window) {
- var val = null;
- $window.setTimeout(function() { val = 123; }, 10);
- expect(val).toEqual(null);
- window.setTimeout.expect(10).process();
- expect(val).toEqual(123);
+ return animate;
});
- * </pre>
- *
- */
-angular.mock.createMockWindow = function() {
- var mockWindow = {};
- var setTimeoutQueue = [];
- mockWindow.document = window.document;
- mockWindow.getComputedStyle = angular.bind(window, window.getComputedStyle);
- mockWindow.scrollTo = angular.bind(window, window.scrollTo);
- mockWindow.navigator = window.navigator;
- mockWindow.setTimeout = function(fn, delay) {
- setTimeoutQueue.push({fn: fn, delay: delay});
- };
- mockWindow.setTimeout.queue = setTimeoutQueue;
- mockWindow.setTimeout.expect = function(delay) {
- if (setTimeoutQueue.length > 0) {
- return {
- process: function() {
- var tick = setTimeoutQueue.shift();
- expect(tick.delay).toEqual(delay);
- tick.fn();
- }
- };
- } else {
- expect('SetTimoutQueue empty. Expecting delay of ').toEqual(delay);
- }
- };
+ }]);
- return mockWindow;
-};
/**
* @ngdoc function
* @name angular.mock.dump
* @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.
+ * 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.
+ * 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 {string} a serialized string of the argument
*/
angular.mock.dump = function(object) {
@@ -702,10 +846,12 @@
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 {
+ // TODO(i): this prevents methods being logged,
+ // we should have a better way to serialize objects
out = angular.toJson(object, true);
}
} else {
out = String(object);
}
@@ -715,11 +861,11 @@
function serializeScope(scope, offset) {
offset = offset || ' ';
var log = [offset + 'Scope(' + scope.$id + '): {'];
for ( var key in scope ) {
- if (scope.hasOwnProperty(key) && !key.match(/^(\$|this)/)) {
+ if (Object.prototype.hasOwnProperty.call(scope, key) && !key.match(/^(\$|this)/)) {
log.push(' ' + key + ': ' + angular.toJson(scope[key]));
}
}
var child = scope.$$childHead;
while(child) {
@@ -730,22 +876,22 @@
return log.join('\n' + offset);
}
};
/**
- * @ngdoc object
- * @name ngMock.$httpBackend
+ * @ngdoc service
+ * @name $httpBackend
* @description
* Fake HTTP backend implementation suitable for unit testing applications that use the
* {@link ng.$http $http service}.
*
* *Note*: For fake HTTP backend implementation suitable for end-to-end testing or backend-less
* development please see {@link 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
+ * we don’t want to send [XHR](https://developer.mozilla.org/en/xmlhttprequest) or
+ * [JSONP](http://en.wikipedia.org/wiki/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
@@ -819,90 +965,114 @@
* the request. The response from the first matched definition is returned.
*
*
* # Flushing HTTP requests
*
- * The $httpBackend used in production, always responds to requests with responses asynchronously.
- * If we preserved this behavior in unit testing, we'd have to create async unit tests, which are
- * hard to write, follow and maintain. At the same time the testing mock, can't respond
- * synchronously because that would change the execution of the code under test. For this reason the
- * mock $httpBackend has a `flush()` method, which allows the test to explicitly flush pending
- * requests and thus preserving the async api of the backend, while allowing the test to execute
- * synchronously.
+ * The $httpBackend used in production always responds to requests asynchronously. If we preserved
+ * this behavior in unit testing, we'd have to create async unit tests, which are hard to write,
+ * to follow and to maintain. But neither can the testing mock respond synchronously; that would
+ * change the execution of the code under test. For this reason, the mock $httpBackend has a
+ * `flush()` method, which allows the test to explicitly flush pending requests. This preserves
+ * the async api of the backend, while allowing the test to execute synchronously.
*
*
* # Unit testing with mock $httpBackend
+ * The following code shows how to setup and use the mock backend when unit testing a controller.
+ * First we create the controller under test:
*
- * <pre>
- // controller
- function MyController($scope, $http) {
- $http.get('/auth.py').success(function(data) {
- $scope.user = data;
- });
+ ```js
+ // The controller code
+ function MyController($scope, $http) {
+ var authToken;
- this.saveMessage = function(message) {
- $scope.status = 'Saving...';
- $http.post('/add-msg.py', message).success(function(response) {
- $scope.status = '';
- }).error(function() {
- $scope.status = 'ERROR!';
- });
- };
- }
+ $http.get('/auth.py').success(function(data, status, headers) {
+ authToken = headers('A-Token');
+ $scope.user = data;
+ });
- // testing controller
- var $httpBackend;
+ $scope.saveMessage = function(message) {
+ var headers = { 'Authorization': authToken };
+ $scope.status = 'Saving...';
- beforeEach(inject(function($injector) {
- $httpBackend = $injector.get('$httpBackend');
+ $http.post('/add-msg.py', message, { headers: headers } ).success(function(response) {
+ $scope.status = '';
+ }).error(function() {
+ $scope.status = 'ERROR!';
+ });
+ };
+ }
+ ```
+ *
+ * Now we setup the mock backend and create the test specs:
+ *
+ ```js
+ // testing controller
+ describe('MyController', function() {
+ var $httpBackend, $rootScope, createController;
- // backend definition common for all tests
- $httpBackend.when('GET', '/auth.py').respond({userId: 'userX'}, {'A-Token': 'xxx'});
- }));
+ beforeEach(inject(function($injector) {
+ // Set up the mock http service responses
+ $httpBackend = $injector.get('$httpBackend');
+ // backend definition common for all tests
+ $httpBackend.when('GET', '/auth.py').respond({userId: 'userX'}, {'A-Token': 'xxx'});
+ // Get hold of a scope (i.e. the root scope)
+ $rootScope = $injector.get('$rootScope');
+ // The $controller service is used to create instances of controllers
+ var $controller = $injector.get('$controller');
- afterEach(function() {
- $httpBackend.verifyNoOutstandingExpectation();
- $httpBackend.verifyNoOutstandingRequest();
- });
+ createController = function() {
+ return $controller('MyController', {'$scope' : $rootScope });
+ };
+ }));
- it('should fetch authentication token', function() {
- $httpBackend.expectGET('/auth.py');
- var controller = scope.$new(MyController);
- $httpBackend.flush();
- });
+ afterEach(function() {
+ $httpBackend.verifyNoOutstandingExpectation();
+ $httpBackend.verifyNoOutstandingRequest();
+ });
- 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, '');
+ it('should fetch authentication token', function() {
+ $httpBackend.expectGET('/auth.py');
+ var controller = createController();
+ $httpBackend.flush();
+ });
- 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 msg to server', function() {
+ var controller = createController();
+ $httpBackend.flush();
- 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, '');
+ // 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
- var controller = scope.$new(MyController);
- controller.saveMessage('whatever');
- $httpBackend.flush();
- });
- </pre>
+ $httpBackend.expectPOST('/add-msg.py', 'message content').respond(201, '');
+ $rootScope.saveMessage('message content');
+ expect($rootScope.status).toBe('Saving...');
+ $httpBackend.flush();
+ expect($rootScope.status).toBe('');
+ });
+
+
+ it('should send auth header', function() {
+ var controller = createController();
+ $httpBackend.flush();
+
+ $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, '');
+
+ $rootScope.saveMessage('whatever');
+ $httpBackend.flush();
+ });
+ });
+ ```
*/
angular.mock.$HttpBackendProvider = function() {
this.$get = ['$rootScope', createHttpBackendMock];
};
@@ -922,11 +1092,12 @@
*/
function createHttpBackendMock($rootScope, $delegate, $browser) {
var definitions = [],
expectations = [],
responses = [],
- responsesPush = angular.bind(responses, responses.push);
+ responsesPush = angular.bind(responses, responses.push),
+ copy = angular.copy;
function createResponse(status, data, headers) {
if (angular.isFunction(status)) return status;
return function() {
@@ -935,11 +1106,11 @@
: [200, status, data];
};
}
// TODO(vojta): change params to: method, url, data, headers, callback
- function $httpBackend(method, url, data, callback, headers, timeout) {
+ function $httpBackend(method, url, data, callback, headers, timeout, withCredentials) {
var xhr = new MockXhr(),
expectation = expectations[0],
wasExpected = false;
function prettyPrint(data) {
@@ -954,11 +1125,11 @@
return handleResponse;
function handleResponse() {
var response = wrapped.response(method, url, data, headers);
xhr.$$respHeaders = response[2];
- callback(response[0], response[1], xhr.getAllResponseHeaders());
+ callback(copy(response[0]), copy(response[1]), xhr.getAllResponseHeaders());
}
function handleTimeout() {
for (var i = 0, ii = responses.length; i < ii; i++) {
if (responses[i] === handleResponse) {
@@ -970,17 +1141,17 @@
}
}
if (expectation && expectation.match(method, url)) {
if (!expectation.matchData(data))
- throw Error('Expected ' + expectation + ' with different data\n' +
+ throw new 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));
+ throw new Error('Expected ' + expectation + ' with different headers\n' +
+ 'EXPECTED: ' + prettyPrint(expectation.headers) + '\nGOT: ' +
+ prettyPrint(headers));
expectations.shift();
if (expectation.response) {
responses.push(wrapResponse(expectation));
@@ -994,37 +1165,39 @@
if (definition.match(method, url, data, headers || {})) {
if (definition.response) {
// if $browser specified, we do auto flush all requests
($browser ? $browser.defer : responsesPush)(wrapResponse(definition));
} else if (definition.passThrough) {
- $delegate(method, url, data, callback, headers, timeout);
- } else throw Error('No response defined !');
+ $delegate(method, url, data, callback, headers, timeout, withCredentials);
+ } else throw new Error('No response defined !');
return;
}
}
throw wasExpected ?
- Error('No response defined !') :
- Error('Unexpected request: ' + method + ' ' + url + '\n' +
- (expectation ? 'Expected ' + expectation : 'No more request expected'));
+ new Error('No response defined !') :
+ new Error('Unexpected request: ' + method + ' ' + url + '\n' +
+ (expectation ? 'Expected ' + expectation : 'No more request expected'));
}
/**
* @ngdoc method
- * @name ngMock.$httpBackend#when
- * @methodOf ngMock.$httpBackend
+ * @name $httpBackend#when
* @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 {string|RegExp|function(string)} url HTTP url or function that receives the url
+ * and returns true if the url match the current definition.
+ * @param {(string|RegExp|function(string))=} data HTTP request body or function that receives
+ * data string and returns true if the data is as expected.
* @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
+ * @returns {requestHandler} Returns an object with `respond` method that controls how a matched
* request is handled.
*
- * - respond – `{function([status,] data[, headers])|function(function(method, url, data, headers)}`
+ * - 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) {
@@ -1045,105 +1218,110 @@
return chain;
};
/**
* @ngdoc method
- * @name ngMock.$httpBackend#whenGET
- * @methodOf ngMock.$httpBackend
+ * @name $httpBackend#whenGET
* @description
* Creates a new backend definition for GET requests. For more info see `when()`.
*
- * @param {string|RegExp} url HTTP url.
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
+ * and returns true if the url match the current definition.
* @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 ngMock.$httpBackend#whenHEAD
- * @methodOf ngMock.$httpBackend
+ * @name $httpBackend#whenHEAD
* @description
* Creates a new backend definition for HEAD requests. For more info see `when()`.
*
- * @param {string|RegExp} url HTTP url.
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
+ * and returns true if the url match the current definition.
* @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 ngMock.$httpBackend#whenDELETE
- * @methodOf ngMock.$httpBackend
+ * @name $httpBackend#whenDELETE
* @description
* Creates a new backend definition for DELETE requests. For more info see `when()`.
*
- * @param {string|RegExp} url HTTP url.
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
+ * and returns true if the url match the current definition.
* @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 ngMock.$httpBackend#whenPOST
- * @methodOf ngMock.$httpBackend
+ * @name $httpBackend#whenPOST
* @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 {string|RegExp|function(string)} url HTTP url or function that receives the url
+ * and returns true if the url match the current definition.
+ * @param {(string|RegExp|function(string))=} data HTTP request body or function that receives
+ * data string and returns true if the data is as expected.
* @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 ngMock.$httpBackend#whenPUT
- * @methodOf ngMock.$httpBackend
+ * @name $httpBackend#whenPUT
* @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 {string|RegExp|function(string)} url HTTP url or function that receives the url
+ * and returns true if the url match the current definition.
+ * @param {(string|RegExp|function(string))=} data HTTP request body or function that receives
+ * data string and returns true if the data is as expected.
* @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 ngMock.$httpBackend#whenJSONP
- * @methodOf ngMock.$httpBackend
+ * @name $httpBackend#whenJSONP
* @description
* Creates a new backend definition for JSONP requests. For more info see `when()`.
*
- * @param {string|RegExp} url HTTP url.
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
+ * and returns true if the url match the current definition.
* @returns {requestHandler} Returns an object with `respond` method that control how a matched
* request is handled.
*/
createShortMethods('when');
/**
* @ngdoc method
- * @name ngMock.$httpBackend#expect
- * @methodOf ngMock.$httpBackend
+ * @name $httpBackend#expect
* @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 {string|RegExp|function(string)} url HTTP url or function that receives the url
+ * and returns true if the url match the current definition.
+ * @param {(string|RegExp|function(string)|Object)=} data HTTP request body or function that
+ * receives data string and returns true if the data is as expected, or Object if request body
+ * is in JSON format.
* @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)}`
+ * - 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) {
@@ -1157,121 +1335,126 @@
};
/**
* @ngdoc method
- * @name ngMock.$httpBackend#expectGET
- * @methodOf ngMock.$httpBackend
+ * @name $httpBackend#expectGET
* @description
* Creates a new request expectation for GET requests. For more info see `expect()`.
*
- * @param {string|RegExp} url HTTP url.
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
+ * and returns true if the url match the current definition.
* @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 ngMock.$httpBackend#expectHEAD
- * @methodOf ngMock.$httpBackend
+ * @name $httpBackend#expectHEAD
* @description
* Creates a new request expectation for HEAD requests. For more info see `expect()`.
*
- * @param {string|RegExp} url HTTP url.
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
+ * and returns true if the url match the current definition.
* @param {Object=} headers HTTP headers.
* @returns {requestHandler} Returns an object with `respond` method that control how a matched
* request is handled.
*/
/**
* @ngdoc method
- * @name ngMock.$httpBackend#expectDELETE
- * @methodOf ngMock.$httpBackend
+ * @name $httpBackend#expectDELETE
* @description
* Creates a new request expectation for DELETE requests. For more info see `expect()`.
*
- * @param {string|RegExp} url HTTP url.
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
+ * and returns true if the url match the current definition.
* @param {Object=} headers HTTP headers.
* @returns {requestHandler} Returns an object with `respond` method that control how a matched
* request is handled.
*/
/**
* @ngdoc method
- * @name ngMock.$httpBackend#expectPOST
- * @methodOf ngMock.$httpBackend
+ * @name $httpBackend#expectPOST
* @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 {string|RegExp|function(string)} url HTTP url or function that receives the url
+ * and returns true if the url match the current definition.
+ * @param {(string|RegExp|function(string)|Object)=} data HTTP request body or function that
+ * receives data string and returns true if the data is as expected, or Object if request body
+ * is in JSON format.
* @param {Object=} headers HTTP headers.
* @returns {requestHandler} Returns an object with `respond` method that control how a matched
* request is handled.
*/
/**
* @ngdoc method
- * @name ngMock.$httpBackend#expectPUT
- * @methodOf ngMock.$httpBackend
+ * @name $httpBackend#expectPUT
* @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 {string|RegExp|function(string)} url HTTP url or function that receives the url
+ * and returns true if the url match the current definition.
+ * @param {(string|RegExp|function(string)|Object)=} data HTTP request body or function that
+ * receives data string and returns true if the data is as expected, or Object if request body
+ * is in JSON format.
* @param {Object=} headers HTTP headers.
* @returns {requestHandler} Returns an object with `respond` method that control how a matched
* request is handled.
*/
/**
* @ngdoc method
- * @name ngMock.$httpBackend#expectPATCH
- * @methodOf ngMock.$httpBackend
+ * @name $httpBackend#expectPATCH
* @description
* Creates a new request expectation for PATCH requests. For more info see `expect()`.
*
- * @param {string|RegExp} url HTTP url.
- * @param {(string|RegExp)=} data HTTP request body.
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
+ * and returns true if the url match the current definition.
+ * @param {(string|RegExp|function(string)|Object)=} data HTTP request body or function that
+ * receives data string and returns true if the data is as expected, or Object if request body
+ * is in JSON format.
* @param {Object=} headers HTTP headers.
* @returns {requestHandler} Returns an object with `respond` method that control how a matched
* request is handled.
*/
/**
* @ngdoc method
- * @name ngMock.$httpBackend#expectJSONP
- * @methodOf ngMock.$httpBackend
+ * @name $httpBackend#expectJSONP
* @description
* Creates a new request expectation for JSONP requests. For more info see `expect()`.
*
- * @param {string|RegExp} url HTTP url.
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
+ * and returns true if the url match the current definition.
* @returns {requestHandler} Returns an object with `respond` method that control how a matched
* request is handled.
*/
createShortMethods('expect');
/**
* @ngdoc method
- * @name ngMock.$httpBackend#flush
- * @methodOf ngMock.$httpBackend
+ * @name $httpBackend#flush
* @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) {
$rootScope.$digest();
- if (!responses.length) throw Error('No pending request to flush !');
+ if (!responses.length) throw new Error('No pending request to flush !');
if (angular.isDefined(count)) {
while (count--) {
- if (!responses.length) throw Error('No more pending request to flush !');
+ if (!responses.length) throw new Error('No more pending request to flush !');
responses.shift()();
}
} else {
while (responses.length) {
responses.shift()();
@@ -1281,56 +1464,53 @@
};
/**
* @ngdoc method
- * @name ngMock.$httpBackend#verifyNoOutstandingExpectation
- * @methodOf ngMock.$httpBackend
+ * @name $httpBackend#verifyNoOutstandingExpectation
* @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.
*
- * <pre>
- * afterEach($httpBackend.verifyExpectations);
- * </pre>
+ * ```js
+ * afterEach($httpBackend.verifyNoOutstandingExpectation);
+ * ```
*/
$httpBackend.verifyNoOutstandingExpectation = function() {
$rootScope.$digest();
if (expectations.length) {
- throw Error('Unsatisfied requests: ' + expectations.join(', '));
+ throw new Error('Unsatisfied requests: ' + expectations.join(', '));
}
};
/**
* @ngdoc method
- * @name ngMock.$httpBackend#verifyNoOutstandingRequest
- * @methodOf ngMock.$httpBackend
+ * @name $httpBackend#verifyNoOutstandingRequest
* @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.
*
- * <pre>
+ * ```js
* afterEach($httpBackend.verifyNoOutstandingRequest);
- * </pre>
+ * ```
*/
$httpBackend.verifyNoOutstandingRequest = function() {
if (responses.length) {
- throw Error('Unflushed requests: ' + responses.length);
+ throw new Error('Unflushed requests: ' + responses.length);
}
};
/**
* @ngdoc method
- * @name ngMock.$httpBackend#resetExpectations
- * @methodOf ngMock.$httpBackend
+ * @name $httpBackend#resetExpectations
* @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.
*/
@@ -1343,18 +1523,18 @@
function createShortMethods(prefix) {
angular.forEach(['GET', 'DELETE', 'JSONP'], function(method) {
$httpBackend[prefix + method] = function(url, headers) {
- return $httpBackend[prefix](method, url, undefined, headers)
- }
+ return $httpBackend[prefix](method, url, undefined, headers);
+ };
});
angular.forEach(['PUT', 'POST', 'PATCH'], function(method) {
$httpBackend[prefix + method] = function(url, data, headers) {
- return $httpBackend[prefix](method, url, data, headers)
- }
+ return $httpBackend[prefix](method, url, data, headers);
+ };
});
}
}
function MockHttpExpectation(method, url, data, headers) {
@@ -1371,10 +1551,11 @@
};
this.matchUrl = function(u) {
if (!url) return true;
if (angular.isFunction(url.test)) return url.test(u);
+ if (angular.isFunction(url)) return url(u);
return url == u;
};
this.matchHeaders = function(h) {
if (angular.isUndefined(headers)) return true;
@@ -1383,19 +1564,24 @@
};
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;
+ if (data && angular.isFunction(data)) return data(d);
+ if (data && !angular.isString(data)) return angular.equals(data, angular.fromJson(d));
return data == d;
};
this.toString = function() {
return method + ' ' + url;
};
}
+function createMockXhr() {
+ return new MockXhr();
+}
+
function MockXhr() {
// hack for testing $http, $httpBackend
MockXhr.$$lastInstance = this;
@@ -1414,11 +1600,12 @@
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
+ // the lookup must be case insensitive,
+ // that's why we try two quick lookups first and full scan last
var header = this.$$respHeaders[name];
if (header) return header;
name = angular.lowercase(name);
header = this.$$respHeaders[name];
@@ -1443,43 +1630,43 @@
this.abort = angular.noop;
}
/**
- * @ngdoc function
- * @name ngMock.$timeout
+ * @ngdoc service
+ * @name $timeout
* @description
*
* This service is just a simple decorator for {@link ng.$timeout $timeout} service
* that adds a "flush" and "verifyNoPendingTasks" methods.
- */
+ */
angular.mock.$TimeoutDecorator = function($delegate, $browser) {
/**
* @ngdoc method
- * @name ngMock.$timeout#flush
- * @methodOf ngMock.$timeout
+ * @name $timeout#flush
* @description
*
* Flushes the queue of pending tasks.
+ *
+ * @param {number=} delay maximum timeout amount to flush up until
*/
- $delegate.flush = function() {
- $browser.defer.flush();
+ $delegate.flush = function(delay) {
+ $browser.defer.flush(delay);
};
/**
* @ngdoc method
- * @name ngMock.$timeout#verifyNoPendingTasks
- * @methodOf ngMock.$timeout
+ * @name $timeout#verifyNoPendingTasks
* @description
*
* Verifies that there are no pending tasks that need to be flushed.
*/
$delegate.verifyNoPendingTasks = function() {
if ($browser.deferredFns.length) {
- throw Error('Deferred tasks to flush (' + $browser.deferredFns.length + '): ' +
+ throw new Error('Deferred tasks to flush (' + $browser.deferredFns.length + '): ' +
formatPendingTasksAsString($browser.deferredFns));
}
};
function formatPendingTasksAsString(tasks) {
@@ -1492,53 +1679,107 @@
}
return $delegate;
};
+angular.mock.$RAFDecorator = function($delegate) {
+ var queue = [];
+ var rafFn = function(fn) {
+ var index = queue.length;
+ queue.push(fn);
+ return function() {
+ queue.splice(index, 1);
+ };
+ };
+
+ rafFn.supported = $delegate.supported;
+
+ rafFn.flush = function() {
+ if(queue.length === 0) {
+ throw new Error('No rAF callbacks present');
+ }
+
+ var length = queue.length;
+ for(var i=0;i<length;i++) {
+ queue[i]();
+ }
+
+ queue = [];
+ };
+
+ return rafFn;
+};
+
+angular.mock.$AsyncCallbackDecorator = function($delegate) {
+ var callbacks = [];
+ var addFn = function(fn) {
+ callbacks.push(fn);
+ };
+ addFn.flush = function() {
+ angular.forEach(callbacks, function(fn) {
+ fn();
+ });
+ callbacks = [];
+ };
+ return addFn;
+};
+
/**
*
*/
angular.mock.$RootElementProvider = function() {
this.$get = function() {
return angular.element('<div ng-app></div>');
- }
+ };
};
/**
- * @ngdoc overview
+ * @ngdoc module
* @name 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 AUTO.$injector $injector}.
+ * # ngMock
+ *
+ * The `ngMock` module providers support to inject and mock Angular services into unit tests.
+ * In addition, ngMock also extends various core ng services such that they can be
+ * inspected and controlled in a synchronous manner within test code.
+ *
+ *
+ * <div doc-module-components="ngMock"></div>
+ *
*/
angular.module('ngMock', ['ng']).provider({
$browser: angular.mock.$BrowserProvider,
$exceptionHandler: angular.mock.$ExceptionHandlerProvider,
$log: angular.mock.$LogProvider,
+ $interval: angular.mock.$IntervalProvider,
$httpBackend: angular.mock.$HttpBackendProvider,
$rootElement: angular.mock.$RootElementProvider
-}).config(function($provide) {
+}).config(['$provide', function($provide) {
$provide.decorator('$timeout', angular.mock.$TimeoutDecorator);
-});
+ $provide.decorator('$$rAF', angular.mock.$RAFDecorator);
+ $provide.decorator('$$asyncCallback', angular.mock.$AsyncCallbackDecorator);
+}]);
/**
- * @ngdoc overview
+ * @ngdoc module
* @name ngMockE2E
+ * @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 ngMockE2E.$httpBackend e2e $httpBackend} mock.
*/
-angular.module('ngMockE2E', ['ng']).config(function($provide) {
+angular.module('ngMockE2E', ['ng']).config(['$provide', function($provide) {
$provide.decorator('$httpBackend', angular.mock.e2e.$httpBackendDecorator);
-});
+}]);
/**
- * @ngdoc object
- * @name ngMockE2E.$httpBackend
+ * @ngdoc service
+ * @name $httpBackend
+ * @module ngMockE2E
* @description
* Fake HTTP backend implementation suitable for end-to-end testing or backend-less development of
* applications that use the {@link ng.$http $http service}.
*
* *Note*: For fake http backend implementation suitable for unit testing please see
@@ -1560,186 +1801,183 @@
* 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:
*
- * <pre>
+ * ```js
* 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));
+ * phones.push(angular.fromJson(data));
* });
* $httpBackend.whenGET(/^\/templates\//).passThrough();
* //...
* });
- * </pre>
+ * ```
*
* Afterwards, bootstrap your app with this new module.
*/
/**
* @ngdoc method
- * @name ngMockE2E.$httpBackend#when
- * @methodOf ngMockE2E.$httpBackend
+ * @name $httpBackend#when
+ * @module ngMockE2E
* @description
* Creates a new backend definition.
*
* @param {string} method HTTP method.
- * @param {string|RegExp} url HTTP url.
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
+ * and returns true if the url match the current definition.
* @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)}`
+ * - 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.
+ * handler will be passed through to the real backend (an XHR request will be made to the
+ * server.)
*/
/**
* @ngdoc method
- * @name ngMockE2E.$httpBackend#whenGET
- * @methodOf ngMockE2E.$httpBackend
+ * @name $httpBackend#whenGET
+ * @module ngMockE2E
* @description
* Creates a new backend definition for GET requests. For more info see `when()`.
*
- * @param {string|RegExp} url HTTP url.
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
+ * and returns true if the url match the current definition.
* @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 ngMockE2E.$httpBackend#whenHEAD
- * @methodOf ngMockE2E.$httpBackend
+ * @name $httpBackend#whenHEAD
+ * @module ngMockE2E
* @description
* Creates a new backend definition for HEAD requests. For more info see `when()`.
*
- * @param {string|RegExp} url HTTP url.
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
+ * and returns true if the url match the current definition.
* @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 ngMockE2E.$httpBackend#whenDELETE
- * @methodOf ngMockE2E.$httpBackend
+ * @name $httpBackend#whenDELETE
+ * @module ngMockE2E
* @description
* Creates a new backend definition for DELETE requests. For more info see `when()`.
*
- * @param {string|RegExp} url HTTP url.
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
+ * and returns true if the url match the current definition.
* @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 ngMockE2E.$httpBackend#whenPOST
- * @methodOf ngMockE2E.$httpBackend
+ * @name $httpBackend#whenPOST
+ * @module ngMockE2E
* @description
* Creates a new backend definition for POST requests. For more info see `when()`.
*
- * @param {string|RegExp} url HTTP url.
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
+ * and returns true if the url match the current definition.
* @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 ngMockE2E.$httpBackend#whenPUT
- * @methodOf ngMockE2E.$httpBackend
+ * @name $httpBackend#whenPUT
+ * @module ngMockE2E
* @description
* Creates a new backend definition for PUT requests. For more info see `when()`.
*
- * @param {string|RegExp} url HTTP url.
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
+ * and returns true if the url match the current definition.
* @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 ngMockE2E.$httpBackend#whenPATCH
- * @methodOf ngMockE2E.$httpBackend
+ * @name $httpBackend#whenPATCH
+ * @module ngMockE2E
* @description
* Creates a new backend definition for PATCH requests. For more info see `when()`.
*
- * @param {string|RegExp} url HTTP url.
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
+ * and returns true if the url match the current definition.
* @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 ngMockE2E.$httpBackend#whenJSONP
- * @methodOf ngMockE2E.$httpBackend
+ * @name $httpBackend#whenJSONP
+ * @module ngMockE2E
* @description
* Creates a new backend definition for JSONP requests. For more info see `when()`.
*
- * @param {string|RegExp} url HTTP url.
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
+ * and returns true if the url match the current definition.
* @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 = ['$rootScope', '$delegate', '$browser', createHttpBackendMock];
+angular.mock.e2e.$httpBackendDecorator =
+ ['$rootScope', '$delegate', '$browser', createHttpBackendMock];
angular.mock.clearDataCache = function() {
var key,
cache = angular.element.cache;
for(key in cache) {
- if (cache.hasOwnProperty(key)) {
+ if (Object.prototype.hasOwnProperty.call(cache,key)) {
var handle = cache[key].handle;
- handle && angular.element(handle.elem).unbind();
+ handle && angular.element(handle.elem).off();
delete cache[key];
}
}
};
-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);
+if(window.jasmine || window.mocha) {
+ var currentSpec = null,
+ isSpecRunning = function() {
+ return !!currentSpec;
+ };
-(window.jasmine || window.mocha) && (function(window) {
- var currentSpec = null;
-
beforeEach(function() {
currentSpec = this;
});
afterEach(function() {
@@ -1748,11 +1986,11 @@
currentSpec.$injector = null;
currentSpec.$modules = null;
currentSpec = null;
if (injector) {
- injector.get('$rootElement').unbind();
+ injector.get('$rootElement').off();
injector.get('$browser').pollFns.length = 0;
}
angular.mock.clearDataCache();
@@ -1767,14 +2005,10 @@
delete angular.callbacks[key];
});
angular.callbacks.counter = 0;
});
- function isSpecRunning() {
- return currentSpec && (window.mocha || currentSpec.queue.running);
- }
-
/**
* @ngdoc function
* @name angular.mock.module
* @description
*
@@ -1783,25 +2017,35 @@
* This function registers a module configuration code. It collects the configuration information
* which will be used when the injector is created by {@link angular.mock.inject inject}.
*
* See {@link angular.mock.inject inject} for usage example
*
- * @param {...(string|Function)} fns any number of modules which are represented as string
+ * @param {...(string|Function|Object)} fns any number of modules which are represented as string
* aliases or as anonymous module initialization functions. The modules are used to
- * configure the injector. The 'ng' and 'ngMock' modules are automatically loaded.
+ * configure the injector. The 'ng' and 'ngMock' modules are automatically loaded. If an
+ * object literal is passed they will be register as values in the module, the key being
+ * the module name and the value being what is returned.
*/
window.module = angular.mock.module = function() {
var moduleFns = Array.prototype.slice.call(arguments, 0);
return isSpecRunning() ? workFn() : workFn;
/////////////////////
function workFn() {
if (currentSpec.$injector) {
- throw Error('Injector already created, can not register a module!');
+ throw new Error('Injector already created, can not register a module!');
} else {
var modules = currentSpec.$modules || (currentSpec.$modules = []);
angular.forEach(moduleFns, function(module) {
- modules.push(module);
+ if (angular.isObject(module) && !angular.isArray(module)) {
+ modules.push(function($provide) {
+ angular.forEach(module, function(value, key) {
+ $provide.value(key, value);
+ });
+ });
+ } else {
+ modules.push(module);
+ }
});
}
}
};
@@ -1811,17 +2055,49 @@
* @description
*
* *NOTE*: This function is also published on window for easy access.<br>
*
* The inject function wraps a function into an injectable function. The inject() creates new
- * instance of {@link AUTO.$injector $injector} per test, which is then used for
+ * instance of {@link auto.$injector $injector} per test, which is then used for
* resolving references.
*
- * See also {@link angular.mock.module module}
*
+ * ## Resolving References (Underscore Wrapping)
+ * Often, we would like to inject a reference once, in a `beforeEach()` block and reuse this
+ * in multiple `it()` clauses. To be able to do this we must assign the reference to a variable
+ * that is declared in the scope of the `describe()` block. Since we would, most likely, want
+ * the variable to have the same name of the reference we have a problem, since the parameter
+ * to the `inject()` function would hide the outer variable.
+ *
+ * To help with this, the injected parameters can, optionally, be enclosed with underscores.
+ * These are ignored by the injector when the reference name is resolved.
+ *
+ * For example, the parameter `_myService_` would be resolved as the reference `myService`.
+ * Since it is available in the function body as _myService_, we can then assign it to a variable
+ * defined in an outer scope.
+ *
+ * ```
+ * // Defined out reference variable outside
+ * var myService;
+ *
+ * // Wrap the parameter in underscores
+ * beforeEach( inject( function(_myService_){
+ * myService = _myService_;
+ * }));
+ *
+ * // Use myService in a series of tests.
+ * it('makes use of myService', function() {
+ * myService.doStuff();
+ * });
+ *
+ * ```
+ *
+ * See also {@link angular.mock.module angular.mock.module}
+ *
+ * ## Example
* Example of what a typical jasmine tests looks like with the inject method.
- * <pre>
+ * ```js
*
* angular.module('myApplicationModule', [])
* .value('mode', 'app')
* .value('version', 'v1.0.1');
*
@@ -1848,21 +2124,35 @@
* });
*
* inject(function(version) {
* expect(version).toEqual('overridden');
* });
- * ));
+ * });
* });
*
- * </pre>
+ * ```
*
* @param {...Function} fns any number of functions which will be injected using the injector.
*/
+
+
+
+ var ErrorAddingDeclarationLocationStack = function(e, errorForStack) {
+ this.message = e.message;
+ this.name = e.name;
+ if (e.line) this.line = e.line;
+ if (e.sourceId) this.sourceId = e.sourceId;
+ if (e.stack && errorForStack)
+ this.stack = e.stack + '\n' + errorForStack.stack;
+ if (e.stackArray) this.stackArray = e.stackArray;
+ };
+ ErrorAddingDeclarationLocationStack.prototype.toString = Error.prototype.toString;
+
window.inject = angular.mock.inject = function() {
var blockFns = Array.prototype.slice.call(arguments, 0);
var errorForStack = new Error('Declaration Location');
- return isSpecRunning() ? workFn() : workFn;
+ return isSpecRunning() ? workFn.call(currentSpec) : workFn;
/////////////////////
function workFn() {
var modules = currentSpec.$modules || [];
modules.unshift('ngMock');
@@ -1871,16 +2161,23 @@
if (!injector) {
injector = currentSpec.$injector = angular.injector(modules);
}
for(var i = 0, ii = blockFns.length; i < ii; i++) {
try {
+ /* jshint -W040 *//* Jasmine explicitly provides a `this` object when calling functions */
injector.invoke(blockFns[i] || angular.noop, this);
+ /* jshint +W040 */
} catch (e) {
- if(e.stack && errorForStack) e.stack += '\n' + errorForStack.stack;
+ if (e.stack && errorForStack) {
+ throw new ErrorAddingDeclarationLocationStack(e, errorForStack);
+ }
throw e;
} finally {
errorForStack = null;
}
}
}
};
-})(window);
+}
+
+
+})(window, window.angular);