vendor/assets/javascripts/angular-mocks.js in angularjs-rails-1.4.8 vs vendor/assets/javascripts/angular-mocks.js in angularjs-rails-1.5.0
- old
+ new
@@ -1,8 +1,8 @@
/**
- * @license AngularJS v1.4.8
- * (c) 2010-2015 Google, Inc. http://angularjs.org
+ * @license AngularJS v1.5.0
+ * (c) 2010-2016 Google, Inc. http://angularjs.org
* License: MIT
*/
(function(window, angular, undefined) {
'use strict';
@@ -756,10 +756,19 @@
//make "tzDateInstance instanceof Date" return true
angular.mock.TzDate.prototype = Date.prototype;
/* jshint +W101 */
+
+/**
+ * @ngdoc service
+ * @name $animate
+ *
+ * @description
+ * Mock implementation of the {@link ng.$animate `$animate`} service. Exposes two additional methods
+ * for testing animations.
+ */
angular.mock.animate = angular.module('ngAnimateMock', ['ng'])
.config(['$provide', function($provide) {
$provide.factory('$$forceReflow', function() {
@@ -788,13 +797,54 @@
return true;
};
return queueFn;
});
- $provide.decorator('$animate', ['$delegate', '$timeout', '$browser', '$$rAF',
+ $provide.decorator('$$animateJs', ['$delegate', function($delegate) {
+ var runners = [];
+
+ var animateJsConstructor = function() {
+ var animator = $delegate.apply($delegate, arguments);
+ // If no javascript animation is found, animator is undefined
+ if (animator) {
+ runners.push(animator);
+ }
+ return animator;
+ };
+
+ animateJsConstructor.$closeAndFlush = function() {
+ runners.forEach(function(runner) {
+ runner.end();
+ });
+ runners = [];
+ };
+
+ return animateJsConstructor;
+ }]);
+
+ $provide.decorator('$animateCss', ['$delegate', function($delegate) {
+ var runners = [];
+
+ var animateCssConstructor = function(element, options) {
+ var animator = $delegate(element, options);
+ runners.push(animator);
+ return animator;
+ };
+
+ animateCssConstructor.$closeAndFlush = function() {
+ runners.forEach(function(runner) {
+ runner.end();
+ });
+ runners = [];
+ };
+
+ return animateCssConstructor;
+ }]);
+
+ $provide.decorator('$animate', ['$delegate', '$timeout', '$browser', '$$rAF', '$animateCss', '$$animateJs',
'$$forceReflow', '$$animateAsyncRun', '$rootScope',
- function($delegate, $timeout, $browser, $$rAF,
+ function($delegate, $timeout, $browser, $$rAF, $animateCss, $$animateJs,
$$forceReflow, $$animateAsyncRun, $rootScope) {
var animate = {
queue: [],
cancel: $delegate.cancel,
on: $delegate.on,
@@ -802,11 +852,39 @@
pin: $delegate.pin,
get reflows() {
return $$forceReflow.totalReflows;
},
enabled: $delegate.enabled,
- flush: function() {
+ /**
+ * @ngdoc method
+ * @name $animate#closeAndFlush
+ * @description
+ *
+ * This method will close all pending animations (both {@link ngAnimate#javascript-based-animations Javascript}
+ * and {@link ngAnimate.$animateCss CSS}) and it will also flush any remaining animation frames and/or callbacks.
+ */
+ closeAndFlush: function() {
+ // we allow the flush command to swallow the errors
+ // because depending on whether CSS or JS animations are
+ // used, there may not be a RAF flush. The primary flush
+ // at the end of this function must throw an exception
+ // because it will track if there were pending animations
+ this.flush(true);
+ $animateCss.$closeAndFlush();
+ $$animateJs.$closeAndFlush();
+ this.flush();
+ },
+ /**
+ * @ngdoc method
+ * @name $animate#flush
+ * @description
+ *
+ * This method is used to flush the pending callbacks and animation frames to either start
+ * an animation or conclude an animation. Note that this will not actually close an
+ * actively running animation (see {@link ngMock.$animate#closeAndFlush `closeAndFlush()`} for that).
+ */
+ flush: function(hideErrors) {
$rootScope.$digest();
var doNextRun, somethingFlushed = false;
do {
doNextRun = false;
@@ -819,11 +897,11 @@
if ($$animateAsyncRun.flush()) {
doNextRun = somethingFlushed = true;
}
} while (doNextRun);
- if (!somethingFlushed) {
+ if (!somethingFlushed && !hideErrors) {
throw new Error('No pending animations ready to be closed or flushed');
}
$rootScope.$digest();
}
@@ -948,11 +1026,11 @@
*
* - `$httpBackend.expect` - specifies a request expectation
* - `$httpBackend.when` - specifies a backend definition
*
*
- * # Request Expectations vs Backend Definitions
+ * ## 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.
*
@@ -1004,21 +1082,21 @@
* If a request didn't match any expectation or if the expectation doesn't have the response
* defined, the backend definitions are evaluated in sequential order to see if any of them match
* the request. The response from the first matched definition is returned.
*
*
- * # Flushing HTTP requests
+ * ## Flushing HTTP requests
*
* 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
+ * ## 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:
*
```js
// The module code
@@ -1028,22 +1106,22 @@
// The controller code
function MyController($scope, $http) {
var authToken;
- $http.get('/auth.py').success(function(data, status, headers) {
- authToken = headers('A-Token');
- $scope.user = data;
+ $http.get('/auth.py').then(function(response) {
+ authToken = response.headers('A-Token');
+ $scope.user = response.data;
});
$scope.saveMessage = function(message) {
var headers = { 'Authorization': authToken };
$scope.status = 'Saving...';
- $http.post('/add-msg.py', message, { headers: headers } ).success(function(response) {
+ $http.post('/add-msg.py', message, { headers: headers } ).then(function(response) {
$scope.status = '';
- }).error(function() {
+ }).catch(function() {
$scope.status = 'Failed...';
});
};
}
```
@@ -1130,11 +1208,91 @@
$rootScope.saveMessage('whatever');
$httpBackend.flush();
});
});
- ```
+ ```
+ *
+ * ## Dynamic responses
+ *
+ * You define a response to a request by chaining a call to `respond()` onto a definition or expectation.
+ * If you provide a **callback** as the first parameter to `respond(callback)` then you can dynamically generate
+ * a response based on the properties of the request.
+ *
+ * The `callback` function should be of the form `function(method, url, data, headers, params)`.
+ *
+ * ### Query parameters
+ *
+ * By default, query parameters on request URLs are parsed into the `params` object. So a request URL
+ * of `/list?q=searchstr&orderby=-name` would set `params` to be `{q: 'searchstr', orderby: '-name'}`.
+ *
+ * ### Regex parameter matching
+ *
+ * If an expectation or definition uses a **regex** to match the URL, you can provide an array of **keys** via a
+ * `params` argument. The index of each **key** in the array will match the index of a **group** in the
+ * **regex**.
+ *
+ * The `params` object in the **callback** will now have properties with these keys, which hold the value of the
+ * corresponding **group** in the **regex**.
+ *
+ * This also applies to the `when` and `expect` shortcut methods.
+ *
+ *
+ * ```js
+ * $httpBackend.expect('GET', /\/user\/(.+)/, undefined, undefined, ['id'])
+ * .respond(function(method, url, data, headers, params) {
+ * // for requested url of '/user/1234' params is {id: '1234'}
+ * });
+ *
+ * $httpBackend.whenPATCH(/\/user\/(.+)\/article\/(.+)/, undefined, undefined, ['user', 'article'])
+ * .respond(function(method, url, data, headers, params) {
+ * // for url of '/user/1234/article/567' params is {user: '1234', article: '567'}
+ * });
+ * ```
+ *
+ * ## Matching route requests
+ *
+ * For extra convenience, `whenRoute` and `expectRoute` shortcuts are available. These methods offer colon
+ * delimited matching of the url path, ignoring the query string. This allows declarations
+ * similar to how application routes are configured with `$routeProvider`. Because these methods convert
+ * the definition url to regex, declaration order is important. Combined with query parameter parsing,
+ * the following is possible:
+ *
+ ```js
+ $httpBackend.whenRoute('GET', '/users/:id')
+ .respond(function(method, url, data, headers, params) {
+ return [200, MockUserList[Number(params.id)]];
+ });
+
+ $httpBackend.whenRoute('GET', '/users')
+ .respond(function(method, url, data, headers, params) {
+ var userList = angular.copy(MockUserList),
+ defaultSort = 'lastName',
+ count, pages, isPrevious, isNext;
+
+ // paged api response '/v1/users?page=2'
+ params.page = Number(params.page) || 1;
+
+ // query for last names '/v1/users?q=Archer'
+ if (params.q) {
+ userList = $filter('filter')({lastName: params.q});
+ }
+
+ pages = Math.ceil(userList.length / pagingLength);
+ isPrevious = params.page > 1;
+ isNext = params.page < pages;
+
+ return [200, {
+ count: userList.length,
+ previous: isPrevious,
+ next: isNext,
+ // sort field -> '/v1/users?sortBy=firstName'
+ results: $filter('orderBy')(userList, params.sortBy || defaultSort)
+ .splice((params.page - 1) * pagingLength, pagingLength)
+ }];
+ });
+ ```
*/
angular.mock.$HttpBackendProvider = function() {
this.$get = ['$rootScope', '$timeout', createHttpBackendMock];
};
@@ -1187,11 +1345,11 @@
}
return handleResponse;
function handleResponse() {
- var response = wrapped.response(method, url, data, headers);
+ var response = wrapped.response(method, url, data, headers, wrapped.params(url));
xhr.$$respHeaders = response[2];
callback(copy(response[0]), copy(response[1]), xhr.getAllResponseHeaders(),
copy(response[3] || ''));
}
@@ -1256,24 +1414,25 @@
* and returns true if the url matches 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.
+ * @param {(Array)=} keys Array of keys to assign to regex matches in request url described above.
* @returns {requestHandler} Returns an object with `respond` method that controls how a matched
* request is handled. You can save this object for later use and invoke `respond` again in
* order to change how a matched request is handled.
*
* - respond –
* `{function([status,] data[, headers, statusText])
- * | function(function(method, url, data, headers)}`
+ * | function(function(method, url, data, headers, params)}`
* – 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), response
* headers (Object), and the text for the status (string). The respond method returns the
* `requestHandler` object for possible overrides.
*/
- $httpBackend.when = function(method, url, data, headers) {
- var definition = new MockHttpExpectation(method, url, data, headers),
+ $httpBackend.when = function(method, url, data, headers, keys) {
+ var definition = new MockHttpExpectation(method, url, data, headers, keys),
chain = {
respond: function(status, data, headers, statusText) {
definition.passThrough = undefined;
definition.response = createResponse(status, data, headers, statusText);
return chain;
@@ -1299,10 +1458,11 @@
* Creates a new backend definition for GET requests. For more info see `when()`.
*
* @param {string|RegExp|function(string)} url HTTP url or function that receives a url
* and returns true if the url matches the current definition.
* @param {(Object|function(Object))=} headers HTTP headers.
+ * @param {(Array)=} keys Array of keys to assign to regex matches in request url described above.
* @returns {requestHandler} Returns an object with `respond` method that controls how a matched
* request is handled. You can save this object for later use and invoke `respond` again in
* order to change how a matched request is handled.
*/
@@ -1313,10 +1473,11 @@
* Creates a new backend definition for HEAD requests. For more info see `when()`.
*
* @param {string|RegExp|function(string)} url HTTP url or function that receives a url
* and returns true if the url matches the current definition.
* @param {(Object|function(Object))=} headers HTTP headers.
+ * @param {(Array)=} keys Array of keys to assign to regex matches in request url described above.
* @returns {requestHandler} Returns an object with `respond` method that controls how a matched
* request is handled. You can save this object for later use and invoke `respond` again in
* order to change how a matched request is handled.
*/
@@ -1327,10 +1488,11 @@
* Creates a new backend definition for DELETE requests. For more info see `when()`.
*
* @param {string|RegExp|function(string)} url HTTP url or function that receives a url
* and returns true if the url matches the current definition.
* @param {(Object|function(Object))=} headers HTTP headers.
+ * @param {(Array)=} keys Array of keys to assign to regex matches in request url described above.
* @returns {requestHandler} Returns an object with `respond` method that controls how a matched
* request is handled. You can save this object for later use and invoke `respond` again in
* order to change how a matched request is handled.
*/
@@ -1343,10 +1505,11 @@
* @param {string|RegExp|function(string)} url HTTP url or function that receives a url
* and returns true if the url matches 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.
+ * @param {(Array)=} keys Array of keys to assign to regex matches in request url described above.
* @returns {requestHandler} Returns an object with `respond` method that controls how a matched
* request is handled. You can save this object for later use and invoke `respond` again in
* order to change how a matched request is handled.
*/
@@ -1359,10 +1522,11 @@
* @param {string|RegExp|function(string)} url HTTP url or function that receives a url
* and returns true if the url matches 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.
+ * @param {(Array)=} keys Array of keys to assign to regex matches in request url described above.
* @returns {requestHandler} Returns an object with `respond` method that controls how a matched
* request is handled. You can save this object for later use and invoke `respond` again in
* order to change how a matched request is handled.
*/
@@ -1372,17 +1536,64 @@
* @description
* Creates a new backend definition for JSONP requests. For more info see `when()`.
*
* @param {string|RegExp|function(string)} url HTTP url or function that receives a url
* and returns true if the url matches the current definition.
+ * @param {(Array)=} keys Array of keys to assign to regex matches in request url described above.
* @returns {requestHandler} Returns an object with `respond` method that controls how a matched
* request is handled. You can save this object for later use and invoke `respond` again in
* order to change how a matched request is handled.
*/
createShortMethods('when');
+ /**
+ * @ngdoc method
+ * @name $httpBackend#whenRoute
+ * @description
+ * Creates a new backend definition that compares only with the requested route.
+ *
+ * @param {string} method HTTP method.
+ * @param {string} url HTTP url string that supports colon param matching.
+ * @returns {requestHandler} Returns an object with `respond` method that controls how a matched
+ * request is handled. You can save this object for later use and invoke `respond` again in
+ * order to change how a matched request is handled. See #when for more info.
+ */
+ $httpBackend.whenRoute = function(method, url) {
+ var pathObj = parseRoute(url);
+ return $httpBackend.when(method, pathObj.regexp, undefined, undefined, pathObj.keys);
+ };
+ function parseRoute(url) {
+ var ret = {
+ regexp: url
+ },
+ keys = ret.keys = [];
+
+ if (!url || !angular.isString(url)) return ret;
+
+ url = url
+ .replace(/([().])/g, '\\$1')
+ .replace(/(\/)?:(\w+)([\?\*])?/g, function(_, slash, key, option) {
+ var optional = option === '?' ? option : null;
+ var star = option === '*' ? option : null;
+ keys.push({ name: key, optional: !!optional });
+ slash = slash || '';
+ return ''
+ + (optional ? '' : slash)
+ + '(?:'
+ + (optional ? slash : '')
+ + (star && '(.+?)' || '([^/]+)')
+ + (optional || '')
+ + ')'
+ + (optional || '');
+ })
+ .replace(/([\/$\*])/g, '\\$1');
+
+ ret.regexp = new RegExp('^' + url, 'i');
+ return ret;
+ }
+
/**
* @ngdoc method
* @name $httpBackend#expect
* @description
* Creates a new request expectation.
@@ -1393,24 +1604,25 @@
* @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.
+ * @param {(Array)=} keys Array of keys to assign to regex matches in request url described above.
* @returns {requestHandler} Returns an object with `respond` method that controls how a matched
* request is handled. You can save this object for later use and invoke `respond` again in
* order to change how a matched request is handled.
*
* - respond –
* `{function([status,] data[, headers, statusText])
- * | function(function(method, url, data, headers)}`
+ * | function(function(method, url, data, headers, params)}`
* – 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), response
* headers (Object), and the text for the status (string). The respond method returns the
* `requestHandler` object for possible overrides.
*/
- $httpBackend.expect = function(method, url, data, headers) {
- var expectation = new MockHttpExpectation(method, url, data, headers),
+ $httpBackend.expect = function(method, url, data, headers, keys) {
+ var expectation = new MockHttpExpectation(method, url, data, headers, keys),
chain = {
respond: function(status, data, headers, statusText) {
expectation.response = createResponse(status, data, headers, statusText);
return chain;
}
@@ -1418,20 +1630,20 @@
expectations.push(expectation);
return chain;
};
-
/**
* @ngdoc method
* @name $httpBackend#expectGET
* @description
* Creates a new request expectation for GET requests. For more info see `expect()`.
*
* @param {string|RegExp|function(string)} url HTTP url or function that receives a url
* and returns true if the url matches the current definition.
* @param {Object=} headers HTTP headers.
+ * @param {(Array)=} keys Array of keys to assign to regex matches in request url described above.
* @returns {requestHandler} Returns an object with `respond` method that controls how a matched
* request is handled. You can save this object for later use and invoke `respond` again in
* order to change how a matched request is handled. See #expect for more info.
*/
@@ -1442,10 +1654,11 @@
* Creates a new request expectation for HEAD requests. For more info see `expect()`.
*
* @param {string|RegExp|function(string)} url HTTP url or function that receives a url
* and returns true if the url matches the current definition.
* @param {Object=} headers HTTP headers.
+ * @param {(Array)=} keys Array of keys to assign to regex matches in request url described above.
* @returns {requestHandler} Returns an object with `respond` method that controls how a matched
* request is handled. You can save this object for later use and invoke `respond` again in
* order to change how a matched request is handled.
*/
@@ -1456,10 +1669,11 @@
* Creates a new request expectation for DELETE requests. For more info see `expect()`.
*
* @param {string|RegExp|function(string)} url HTTP url or function that receives a url
* and returns true if the url matches the current definition.
* @param {Object=} headers HTTP headers.
+ * @param {(Array)=} keys Array of keys to assign to regex matches in request url described above.
* @returns {requestHandler} Returns an object with `respond` method that controls how a matched
* request is handled. You can save this object for later use and invoke `respond` again in
* order to change how a matched request is handled.
*/
@@ -1473,10 +1687,11 @@
* and returns true if the url matches 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.
+ * @param {(Array)=} keys Array of keys to assign to regex matches in request url described above.
* @returns {requestHandler} Returns an object with `respond` method that controls how a matched
* request is handled. You can save this object for later use and invoke `respond` again in
* order to change how a matched request is handled.
*/
@@ -1490,10 +1705,11 @@
* and returns true if the url matches 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.
+ * @param {(Array)=} keys Array of keys to assign to regex matches in request url described above.
* @returns {requestHandler} Returns an object with `respond` method that controls how a matched
* request is handled. You can save this object for later use and invoke `respond` again in
* order to change how a matched request is handled.
*/
@@ -1507,10 +1723,11 @@
* and returns true if the url matches 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.
+ * @param {(Array)=} keys Array of keys to assign to regex matches in request url described above.
* @returns {requestHandler} Returns an object with `respond` method that controls how a matched
* request is handled. You can save this object for later use and invoke `respond` again in
* order to change how a matched request is handled.
*/
@@ -1520,17 +1737,35 @@
* @description
* Creates a new request expectation for JSONP requests. For more info see `expect()`.
*
* @param {string|RegExp|function(string)} url HTTP url or function that receives an url
* and returns true if the url matches the current definition.
+ * @param {(Array)=} keys Array of keys to assign to regex matches in request url described above.
* @returns {requestHandler} Returns an object with `respond` method that controls how a matched
* request is handled. You can save this object for later use and invoke `respond` again in
* order to change how a matched request is handled.
*/
createShortMethods('expect');
+ /**
+ * @ngdoc method
+ * @name $httpBackend#expectRoute
+ * @description
+ * Creates a new request expectation that compares only with the requested route.
+ *
+ * @param {string} method HTTP method.
+ * @param {string} url HTTP url string that supports colon param matching.
+ * @returns {requestHandler} Returns an object with `respond` method that controls how a matched
+ * request is handled. You can save this object for later use and invoke `respond` again in
+ * order to change how a matched request is handled. See #expect for more info.
+ */
+ $httpBackend.expectRoute = function(method, url) {
+ var pathObj = parseRoute(url);
+ return $httpBackend.expect(method, pathObj.regexp, undefined, undefined, pathObj.keys);
+ };
+
/**
* @ngdoc method
* @name $httpBackend#flush
* @description
* Flushes all pending requests using the trained responses.
@@ -1615,24 +1850,24 @@
return $httpBackend;
function createShortMethods(prefix) {
angular.forEach(['GET', 'DELETE', 'JSONP', 'HEAD'], function(method) {
- $httpBackend[prefix + method] = function(url, headers) {
- return $httpBackend[prefix](method, url, undefined, headers);
+ $httpBackend[prefix + method] = function(url, headers, keys) {
+ return $httpBackend[prefix](method, url, undefined, headers, keys);
};
});
angular.forEach(['PUT', 'POST', 'PATCH'], function(method) {
- $httpBackend[prefix + method] = function(url, data, headers) {
- return $httpBackend[prefix](method, url, data, headers);
+ $httpBackend[prefix + method] = function(url, data, headers, keys) {
+ return $httpBackend[prefix](method, url, data, headers, keys);
};
});
}
}
-function MockHttpExpectation(method, url, data, headers) {
+function MockHttpExpectation(method, url, data, headers, keys) {
this.data = data;
this.headers = headers;
this.match = function(m, u, d, h) {
@@ -1667,10 +1902,63 @@
};
this.toString = function() {
return method + ' ' + url;
};
+
+ this.params = function(u) {
+ return angular.extend(parseQuery(), pathParams());
+
+ function pathParams() {
+ var keyObj = {};
+ if (!url || !angular.isFunction(url.test) || !keys || keys.length === 0) return keyObj;
+
+ var m = url.exec(u);
+ if (!m) return keyObj;
+ for (var i = 1, len = m.length; i < len; ++i) {
+ var key = keys[i - 1];
+ var val = m[i];
+ if (key && val) {
+ keyObj[key.name || key] = val;
+ }
+ }
+
+ return keyObj;
+ }
+
+ function parseQuery() {
+ var obj = {}, key_value, key,
+ queryStr = u.indexOf('?') > -1
+ ? u.substring(u.indexOf('?') + 1)
+ : "";
+
+ angular.forEach(queryStr.split('&'), function(keyValue) {
+ if (keyValue) {
+ key_value = keyValue.replace(/\+/g,'%20').split('=');
+ key = tryDecodeURIComponent(key_value[0]);
+ if (angular.isDefined(key)) {
+ var val = angular.isDefined(key_value[1]) ? tryDecodeURIComponent(key_value[1]) : true;
+ if (!hasOwnProperty.call(obj, key)) {
+ obj[key] = val;
+ } else if (angular.isArray(obj[key])) {
+ obj[key].push(val);
+ } else {
+ obj[key] = [obj[key],val];
+ }
+ }
+ }
+ });
+ return obj;
+ }
+ function tryDecodeURIComponent(value) {
+ try {
+ return decodeURIComponent(value);
+ } catch (e) {
+ // Ignore any invalid uri component
+ }
+ }
+ };
}
function createMockXhr() {
return new MockXhr();
}
@@ -1835,11 +2123,11 @@
* });
*
*
* // Controller definition ...
*
- * myMod.controller('MyDirectiveController', ['log', function($log) {
+ * myMod.controller('MyDirectiveController', ['$log', function($log) {
* $log.info(this.name);
* })];
*
*
* // In a test ...
@@ -1881,11 +2169,54 @@
}
return $delegate(expression, locals, later, ident);
};
}];
+/**
+ * @ngdoc service
+ * @name $componentController
+ * @description
+ * A service that can be used to create instances of component controllers.
+ * <div class="alert alert-info">
+ * Be aware that the controller will be instantiated and attached to the scope as specified in
+ * the component definition object. That means that you must always provide a `$scope` object
+ * in the `locals` param.
+ * </div>
+ * @param {string} componentName the name of the component whose controller we want to instantiate
+ * @param {Object} locals Injection locals for Controller.
+ * @param {Object=} bindings Properties to add to the controller before invoking the constructor. This is used
+ * to simulate the `bindToController` feature and simplify certain kinds of tests.
+ * @param {string=} ident Override the property name to use when attaching the controller to the scope.
+ * @return {Object} Instance of requested controller.
+ */
+angular.mock.$ComponentControllerProvider = ['$compileProvider', function($compileProvider) {
+ return {
+ $get: ['$controller','$injector', function($controller,$injector) {
+ return function $componentController(componentName, locals, bindings, ident) {
+ // get all directives associated to the component name
+ var directives = $injector.get(componentName + 'Directive');
+ // look for those directives that are components
+ var candidateDirectives = directives.filter(function(directiveInfo) {
+ // components have controller, controllerAs and restrict:'E'
+ return directiveInfo.controller && directiveInfo.controllerAs && directiveInfo.restrict === 'E';
+ });
+ // check if valid directives found
+ if (candidateDirectives.length === 0) {
+ throw new Error('No component found');
+ }
+ if (candidateDirectives.length > 1) {
+ throw new Error('Too many components found');
+ }
+ // get the info of the component
+ var directiveInfo = candidateDirectives[0];
+ return $controller(directiveInfo.controller, locals, bindings, ident || directiveInfo.controllerAs);
+ };
+ }]
+ };
+}];
+
/**
* @ngdoc module
* @name ngMock
* @packageName angular-mocks
* @description
@@ -1904,11 +2235,12 @@
$browser: angular.mock.$BrowserProvider,
$exceptionHandler: angular.mock.$ExceptionHandlerProvider,
$log: angular.mock.$LogProvider,
$interval: angular.mock.$IntervalProvider,
$httpBackend: angular.mock.$HttpBackendProvider,
- $rootElement: angular.mock.$RootElementProvider
+ $rootElement: angular.mock.$RootElementProvider,
+ $componentController: angular.mock.$ComponentControllerProvider
}).config(['$provide', function($provide) {
$provide.decorator('$timeout', angular.mock.$TimeoutDecorator);
$provide.decorator('$$rAF', angular.mock.$RAFDecorator);
$provide.decorator('$rootScope', angular.mock.$RootScopeDecorator);
$provide.decorator('$controller', angular.mock.$ControllerDecorator);
@@ -1991,17 +2323,19 @@
* @param {string|RegExp|function(string)} url HTTP url or function that receives a url
* and returns true if the url matches 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.
+ * @param {(Array)=} keys Array of keys to assign to regex matches in request url described on
+ * {@link ngMock.$httpBackend $httpBackend mock}.
* @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
* control how a matched request is handled. You can save this object for later use and invoke
* `respond` or `passThrough` again in order to change how a matched request is handled.
*
* - respond –
* `{function([status,] data[, headers, statusText])
- * | function(function(method, url, data, headers)}`
+ * | function(function(method, url, data, headers, params)}`
* – 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), response headers
* (Object), and the text for the status (string).
* - passThrough – `{function()}` – Any request matching a backend definition with
* `passThrough` handler will be passed through to the real backend (an XHR request will be made
@@ -2017,10 +2351,12 @@
* Creates a new backend definition for GET requests. For more info see `when()`.
*
* @param {string|RegExp|function(string)} url HTTP url or function that receives a url
* and returns true if the url matches the current definition.
* @param {(Object|function(Object))=} headers HTTP headers.
+ * @param {(Array)=} keys Array of keys to assign to regex matches in request url described on
+ * {@link ngMock.$httpBackend $httpBackend mock}.
* @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
* control how a matched request is handled. You can save this object for later use and invoke
* `respond` or `passThrough` again in order to change how a matched request is handled.
*/
@@ -2032,10 +2368,12 @@
* Creates a new backend definition for HEAD requests. For more info see `when()`.
*
* @param {string|RegExp|function(string)} url HTTP url or function that receives a url
* and returns true if the url matches the current definition.
* @param {(Object|function(Object))=} headers HTTP headers.
+ * @param {(Array)=} keys Array of keys to assign to regex matches in request url described on
+ * {@link ngMock.$httpBackend $httpBackend mock}.
* @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
* control how a matched request is handled. You can save this object for later use and invoke
* `respond` or `passThrough` again in order to change how a matched request is handled.
*/
@@ -2047,10 +2385,12 @@
* Creates a new backend definition for DELETE requests. For more info see `when()`.
*
* @param {string|RegExp|function(string)} url HTTP url or function that receives a url
* and returns true if the url matches the current definition.
* @param {(Object|function(Object))=} headers HTTP headers.
+ * @param {(Array)=} keys Array of keys to assign to regex matches in request url described on
+ * {@link ngMock.$httpBackend $httpBackend mock}.
* @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
* control how a matched request is handled. You can save this object for later use and invoke
* `respond` or `passThrough` again in order to change how a matched request is handled.
*/
@@ -2063,10 +2403,12 @@
*
* @param {string|RegExp|function(string)} url HTTP url or function that receives a url
* and returns true if the url matches the current definition.
* @param {(string|RegExp)=} data HTTP request body.
* @param {(Object|function(Object))=} headers HTTP headers.
+ * @param {(Array)=} keys Array of keys to assign to regex matches in request url described on
+ * {@link ngMock.$httpBackend $httpBackend mock}.
* @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
* control how a matched request is handled. You can save this object for later use and invoke
* `respond` or `passThrough` again in order to change how a matched request is handled.
*/
@@ -2079,10 +2421,12 @@
*
* @param {string|RegExp|function(string)} url HTTP url or function that receives a url
* and returns true if the url matches the current definition.
* @param {(string|RegExp)=} data HTTP request body.
* @param {(Object|function(Object))=} headers HTTP headers.
+ * @param {(Array)=} keys Array of keys to assign to regex matches in request url described on
+ * {@link ngMock.$httpBackend $httpBackend mock}.
* @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
* control how a matched request is handled. You can save this object for later use and invoke
* `respond` or `passThrough` again in order to change how a matched request is handled.
*/
@@ -2095,10 +2439,12 @@
*
* @param {string|RegExp|function(string)} url HTTP url or function that receives a url
* and returns true if the url matches the current definition.
* @param {(string|RegExp)=} data HTTP request body.
* @param {(Object|function(Object))=} headers HTTP headers.
+ * @param {(Array)=} keys Array of keys to assign to regex matches in request url described on
+ * {@link ngMock.$httpBackend $httpBackend mock}.
* @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
* control how a matched request is handled. You can save this object for later use and invoke
* `respond` or `passThrough` again in order to change how a matched request is handled.
*/
@@ -2109,14 +2455,29 @@
* @description
* Creates a new backend definition for JSONP requests. For more info see `when()`.
*
* @param {string|RegExp|function(string)} url HTTP url or function that receives a url
* and returns true if the url matches the current definition.
+ * @param {(Array)=} keys Array of keys to assign to regex matches in request url described on
+ * {@link ngMock.$httpBackend $httpBackend mock}.
* @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
* control how a matched request is handled. You can save this object for later use and invoke
* `respond` or `passThrough` again in order to change how a matched request is handled.
*/
+/**
+ * @ngdoc method
+ * @name $httpBackend#whenRoute
+ * @module ngMockE2E
+ * @description
+ * Creates a new backend definition that compares only with the requested route.
+ *
+ * @param {string} method HTTP method.
+ * @param {string} url HTTP url string that supports colon param matching.
+ * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
+ * control how a matched request is handled. You can save this object for later use and invoke
+ * `respond` or `passThrough` again in order to change how a matched request is handled.
+ */
angular.mock.e2e = {};
angular.mock.e2e.$httpBackendDecorator =
['$rootScope', '$timeout', '$delegate', '$browser', createHttpBackendMock];
@@ -2241,14 +2602,16 @@
}
});
currentSpec.$injector = null;
currentSpec.$modules = null;
+ currentSpec.$providerInjector = null;
currentSpec = null;
if (injector) {
injector.get('$rootElement').off();
+ injector.get('$rootScope').$destroy();
}
// clean up jquery's fragment cache
angular.forEach(angular.element.fragments, function(val, key) {
delete angular.element.fragments[key];
@@ -2288,21 +2651,26 @@
/////////////////////
function workFn() {
if (currentSpec.$injector) {
throw new Error('Injector already created, can not register a module!');
} else {
- var modules = currentSpec.$modules || (currentSpec.$modules = []);
+ var fn, modules = currentSpec.$modules || (currentSpec.$modules = []);
angular.forEach(moduleFns, function(module) {
if (angular.isObject(module) && !angular.isArray(module)) {
- modules.push(function($provide) {
+ fn = function($provide) {
angular.forEach(module, function(value, key) {
$provide.value(key, value);
});
- });
+ };
} else {
- modules.push(module);
+ fn = module;
}
+ if (currentSpec.$providerInjector) {
+ currentSpec.$providerInjector.invoke(fn);
+ } else {
+ modules.push(fn);
+ }
});
}
}
};
@@ -2411,9 +2779,12 @@
return isSpecRunning() ? workFn.call(currentSpec) : workFn;
/////////////////////
function workFn() {
var modules = currentSpec.$modules || [];
var strictDi = !!currentSpec.$injectorStrict;
+ modules.unshift(function($injector) {
+ currentSpec.$providerInjector = $injector;
+ });
modules.unshift('ngMock');
modules.unshift('ng');
var injector = currentSpec.$injector;
if (!injector) {
if (strictDi) {