angularjs-rails-resource 1.0.0.pre.4 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 20771e48c443e10d5168fbd655ef6612531ce5fd
4
- data.tar.gz: 0f47dfc805d46e310170964e062ca7b343bbbabc
3
+ metadata.gz: f3bf9757cba16ef593b4a0b823c29d61f47910d5
4
+ data.tar.gz: 62a2d930c231b2e6a54dbeb718dca18eb4c2ff9c
5
5
  SHA512:
6
- metadata.gz: 6fcbd686a622b259875e64033a564ed2291678a7ef439cd83c898fc494b62a81bf7c0a3402f60222d507b51108fe9dfc830b18a9bae7994df3a16eaac3e80c4b
7
- data.tar.gz: d1508be43ab85c0b47870a55413187d81a4bad5960156cd602c037847dd64b2bd47193f8e8a526b1062109b5146ec1d4a7978ee1dd9eab55178e0fd452900d5f
6
+ metadata.gz: 610c9c4762c53128e74996a87d27c83d59ce9a186d093f614092673d084c9cf441e5cb6107a08e8599b5ae384f900e577c8c9c3ee9d39b714f75f6d2524e055e
7
+ data.tar.gz: 59ca8304a0d22e07a7fc00bbf1552fdb28d6da859207dc74276762838441b1f43ef97cc3e3e53777dc2d842d7b22652c673d685e615325527241dcdbd05b1914
data/bower.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "angularjs-rails-resource",
3
- "version": "1.0.0-pre.4",
3
+ "version": "1.0.0",
4
4
  "main": "angularjs-rails-resource.js",
5
5
  "description": "A resource factory inspired by $resource from AngularJS",
6
6
  "repository": {
@@ -1,7 +1,7 @@
1
1
  module Angularjs
2
2
  module Rails
3
3
  module Resource
4
- VERSION = '1.0.0.pre.4'
4
+ VERSION = '1.0.0'
5
5
  end
6
6
  end
7
7
  end
data/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "angularjs-rails-resource",
3
3
  "description" : "A resource factory inspired by $resource from AngularJS",
4
- "version": "1.0.0-pre.4",
4
+ "version": "1.0.0",
5
5
  "main" : "dist/angularjs-rails-resource.min.js",
6
6
  "homepage" : "https://github.com/FineLinePrototyping/angularjs-rails-resource.git",
7
7
  "author" : "",
@@ -1,14 +1,25 @@
1
1
  /**
2
- * @license AngularJS v1.1.4
3
- * (c) 2010-2012 Google, Inc. http://angularjs.org
2
+ * @license AngularJS v1.2.6
3
+ * (c) 2010-2014 Google, Inc. http://angularjs.org
4
4
  * License: MIT
5
5
  */
6
- (function(window, angular, undefined) {
7
- 'use strict';
6
+ (function(window, angular, undefined) {'use strict';
8
7
 
9
8
  /**
10
9
  * @ngdoc overview
11
10
  * @name ngCookies
11
+ * @description
12
+ *
13
+ * # ngCookies
14
+ *
15
+ * The `ngCookies` module provides a convenient wrapper for reading and writing browser cookies.
16
+ *
17
+ * {@installModule cookies}
18
+ *
19
+ * <div doc-module-components="ngCookies"></div>
20
+ *
21
+ * See {@link ngCookies.$cookies `$cookies`} and
22
+ * {@link ngCookies.$cookieStore `$cookieStore`} for usage.
12
23
  */
13
24
 
14
25
 
@@ -24,6 +35,8 @@ angular.module('ngCookies', ['ng']).
24
35
  * Only a simple Object is exposed and by adding or removing properties to/from
25
36
  * this object, new cookies are created/deleted at the end of current $eval.
26
37
  *
38
+ * Requires the {@link ngCookies `ngCookies`} module to be installed.
39
+ *
27
40
  * @example
28
41
  <doc:example>
29
42
  <doc:source>
@@ -68,7 +81,8 @@ angular.module('ngCookies', ['ng']).
68
81
 
69
82
 
70
83
  /**
71
- * Pushes all the cookies from the service to the browser and verifies if all cookies were stored.
84
+ * Pushes all the cookies from the service to the browser and verifies if all cookies were
85
+ * stored.
72
86
  */
73
87
  function push() {
74
88
  var name,
@@ -128,6 +142,9 @@ angular.module('ngCookies', ['ng']).
128
142
  * Provides a key-value (string-object) storage, that is backed by session cookies.
129
143
  * Objects put or retrieved from this storage are automatically serialized or
130
144
  * deserialized by angular's toJson/fromJson.
145
+ *
146
+ * Requires the {@link ngCookies `ngCookies`} module to be installed.
147
+ *
131
148
  * @example
132
149
  */
133
150
  factory('$cookieStore', ['$cookies', function($cookies) {
@@ -145,7 +162,8 @@ angular.module('ngCookies', ['ng']).
145
162
  * @returns {Object} Deserialized cookie value.
146
163
  */
147
164
  get: function(key) {
148
- return angular.fromJson($cookies[key]);
165
+ var value = $cookies[key];
166
+ return value ? angular.fromJson(value) : value;
149
167
  },
150
168
 
151
169
  /**
@@ -1,10 +1,84 @@
1
1
  /**
2
- * @license AngularJS v1.1.4
3
- * (c) 2010-2012 Google, Inc. http://angularjs.org
2
+ * @license AngularJS v1.2.6
3
+ * (c) 2010-2014 Google, Inc. http://angularjs.org
4
4
  * License: MIT
5
5
  */
6
6
 
7
- (
7
+ (function() {'use strict';
8
+
9
+ /**
10
+ * @description
11
+ *
12
+ * This object provides a utility for producing rich Error messages within
13
+ * Angular. It can be called as follows:
14
+ *
15
+ * var exampleMinErr = minErr('example');
16
+ * throw exampleMinErr('one', 'This {0} is {1}', foo, bar);
17
+ *
18
+ * The above creates an instance of minErr in the example namespace. The
19
+ * resulting error will have a namespaced error code of example.one. The
20
+ * resulting error will replace {0} with the value of foo, and {1} with the
21
+ * value of bar. The object is not restricted in the number of arguments it can
22
+ * take.
23
+ *
24
+ * If fewer arguments are specified than necessary for interpolation, the extra
25
+ * interpolation markers will be preserved in the final string.
26
+ *
27
+ * Since data will be parsed statically during a build step, some restrictions
28
+ * are applied with respect to how minErr instances are created and called.
29
+ * Instances should have names of the form namespaceMinErr for a minErr created
30
+ * using minErr('namespace') . Error codes, namespaces and template strings
31
+ * should all be static strings, not variables or general expressions.
32
+ *
33
+ * @param {string} module The namespace to use for the new minErr instance.
34
+ * @returns {function(string, string, ...): Error} instance
35
+ */
36
+
37
+ function minErr(module) {
38
+ return function () {
39
+ var code = arguments[0],
40
+ prefix = '[' + (module ? module + ':' : '') + code + '] ',
41
+ template = arguments[1],
42
+ templateArgs = arguments,
43
+ stringify = function (obj) {
44
+ if (typeof obj === 'function') {
45
+ return obj.toString().replace(/ \{[\s\S]*$/, '');
46
+ } else if (typeof obj === 'undefined') {
47
+ return 'undefined';
48
+ } else if (typeof obj !== 'string') {
49
+ return JSON.stringify(obj);
50
+ }
51
+ return obj;
52
+ },
53
+ message, i;
54
+
55
+ message = prefix + template.replace(/\{\d+\}/g, function (match) {
56
+ var index = +match.slice(1, -1), arg;
57
+
58
+ if (index + 2 < templateArgs.length) {
59
+ arg = templateArgs[index + 2];
60
+ if (typeof arg === 'function') {
61
+ return arg.toString().replace(/ ?\{[\s\S]*$/, '');
62
+ } else if (typeof arg === 'undefined') {
63
+ return 'undefined';
64
+ } else if (typeof arg !== 'string') {
65
+ return toJson(arg);
66
+ }
67
+ return arg;
68
+ }
69
+ return match;
70
+ });
71
+
72
+ message = message + '\nhttp://errors.angularjs.org/1.2.6/' +
73
+ (module ? module + '/' : '') + code;
74
+ for (i = 2; i < arguments.length; i++) {
75
+ message = message + (i == 2 ? '?' : '&') + 'p' + (i-2) + '=' +
76
+ encodeURIComponent(stringify(arguments[i]));
77
+ }
78
+
79
+ return new Error(message);
80
+ };
81
+ }
8
82
 
9
83
  /**
10
84
  * @ngdoc interface
@@ -16,11 +90,19 @@
16
90
 
17
91
  function setupModuleLoader(window) {
18
92
 
93
+ var $injectorMinErr = minErr('$injector');
94
+ var ngMinErr = minErr('ng');
95
+
19
96
  function ensure(obj, name, factory) {
20
97
  return obj[name] || (obj[name] = factory());
21
98
  }
22
99
 
23
- return ensure(ensure(window, 'angular', Object), 'module', function() {
100
+ var angular = ensure(window, 'angular', Object);
101
+
102
+ // We need to expose `angular.$$minErr` to modules such as `ngResource` that reference it during bootstrap
103
+ angular.$$minErr = angular.$$minErr || minErr;
104
+
105
+ return ensure(angular, 'module', function() {
24
106
  /** @type {Object.<string, angular.Module>} */
25
107
  var modules = {};
26
108
 
@@ -29,15 +111,19 @@ function setupModuleLoader(window) {
29
111
  * @name angular.module
30
112
  * @description
31
113
  *
32
- * The `angular.module` is a global place for creating and registering Angular modules. All
33
- * modules (angular core or 3rd party) that should be available to an application must be
114
+ * The `angular.module` is a global place for creating, registering and retrieving Angular
115
+ * modules.
116
+ * All modules (angular core or 3rd party) that should be available to an application must be
34
117
  * registered using this mechanism.
35
118
  *
119
+ * When passed two or more arguments, a new module is created. If passed only one argument, an
120
+ * existing module (the name passed as the first argument to `module`) is retrieved.
121
+ *
36
122
  *
37
123
  * # Module
38
124
  *
39
- * A module is a collocation of services, directives, filters, and configuration information. Module
40
- * is used to configure the {@link AUTO.$injector $injector}.
125
+ * A module is a collection of services, directives, filters, and configuration information.
126
+ * `angular.module` is used to configure the {@link AUTO.$injector $injector}.
41
127
  *
42
128
  * <pre>
43
129
  * // Create a new module
@@ -48,7 +134,6 @@ function setupModuleLoader(window) {
48
134
  *
49
135
  * // configure existing services inside initialization blocks.
50
136
  * myModule.config(function($locationProvider) {
51
- 'use strict';
52
137
  * // Configure existing providers
53
138
  * $locationProvider.hashPrefix('!');
54
139
  * });
@@ -65,19 +150,28 @@ function setupModuleLoader(window) {
65
150
  * {@link angular.bootstrap} to simplify this process for you.
66
151
  *
67
152
  * @param {!string} name The name of the module to create or retrieve.
68
- * @param {Array.<string>=} requires If specified then new module is being created. If unspecified then the
69
- * the module is being retrieved for further configuration.
153
+ * @param {Array.<string>=} requires If specified then new module is being created. If
154
+ * unspecified then the the module is being retrieved for further configuration.
70
155
  * @param {Function} configFn Optional configuration function for the module. Same as
71
- * {@link angular.Module#config Module#config()}.
156
+ * {@link angular.Module#methods_config Module#config()}.
72
157
  * @returns {module} new module with the {@link angular.Module} api.
73
158
  */
74
159
  return function module(name, requires, configFn) {
160
+ var assertNotHasOwnProperty = function(name, context) {
161
+ if (name === 'hasOwnProperty') {
162
+ throw ngMinErr('badname', 'hasOwnProperty is not a valid {0} name', context);
163
+ }
164
+ };
165
+
166
+ assertNotHasOwnProperty(name, 'module');
75
167
  if (requires && modules.hasOwnProperty(name)) {
76
168
  modules[name] = null;
77
169
  }
78
170
  return ensure(modules, name, function() {
79
171
  if (!requires) {
80
- throw Error('No module: ' + name);
172
+ throw $injectorMinErr('nomod', "Module '{0}' is not available! You either misspelled " +
173
+ "the module name or forgot to load it. If registering a module ensure that you " +
174
+ "specify the dependencies as the second argument.", name);
81
175
  }
82
176
 
83
177
  /** @type {!Array.<Array.<*>>} */
@@ -100,7 +194,8 @@ function setupModuleLoader(window) {
100
194
  * @propertyOf angular.Module
101
195
  * @returns {Array.<string>} List of module names which must be loaded before this module.
102
196
  * @description
103
- * Holds the list of modules which the injector will load before the current module is loaded.
197
+ * Holds the list of modules which the injector will load before the current module is
198
+ * loaded.
104
199
  */
105
200
  requires: requires,
106
201
 
@@ -119,7 +214,8 @@ function setupModuleLoader(window) {
119
214
  * @name angular.Module#provider
120
215
  * @methodOf angular.Module
121
216
  * @param {string} name service name
122
- * @param {Function} providerType Construction function for creating new instance of the service.
217
+ * @param {Function} providerType Construction function for creating new instance of the
218
+ * service.
123
219
  * @description
124
220
  * See {@link AUTO.$provide#provider $provide.provider()}.
125
221
  */
@@ -175,27 +271,34 @@ function setupModuleLoader(window) {
175
271
  * @name angular.Module#animation
176
272
  * @methodOf angular.Module
177
273
  * @param {string} name animation name
178
- * @param {Function} animationFactory Factory function for creating new instance of an animation.
274
+ * @param {Function} animationFactory Factory function for creating new instance of an
275
+ * animation.
179
276
  * @description
180
277
  *
181
- * Defines an animation hook that can be later used with {@link ng.directive:ngAnimate ngAnimate}
182
- * alongside {@link ng.directive:ngAnimate#Description common ng directives} as well as custom directives.
278
+ * **NOTE**: animations take effect only if the **ngAnimate** module is loaded.
279
+ *
280
+ *
281
+ * Defines an animation hook that can be later used with
282
+ * {@link ngAnimate.$animate $animate} service and directives that use this service.
283
+ *
183
284
  * <pre>
184
- * module.animation('animation-name', function($inject1, $inject2) {
285
+ * module.animation('.animation-name', function($inject1, $inject2) {
185
286
  * return {
186
- * //this gets called in preparation to setup an animation
187
- * setup : function(element) { ... },
188
- *
189
- * //this gets called once the animation is run
190
- * start : function(element, done, memo) { ... }
287
+ * eventName : function(element, done) {
288
+ * //code to run the animation
289
+ * //once complete, then run done()
290
+ * return function cancellationFunction(element) {
291
+ * //code to cancel the animation
292
+ * }
293
+ * }
191
294
  * }
192
295
  * })
193
296
  * </pre>
194
297
  *
195
- * See {@link ng.$animationProvider#register $animationProvider.register()} and
196
- * {@link ng.directive:ngAnimate ngAnimate} for more information.
298
+ * See {@link ngAnimate.$animateProvider#register $animateProvider.register()} and
299
+ * {@link ngAnimate ngAnimate module} for more information.
197
300
  */
198
- animation: invokeLater('$animationProvider', 'register'),
301
+ animation: invokeLater('$animateProvider', 'register'),
199
302
 
200
303
  /**
201
304
  * @ngdoc method
@@ -212,7 +315,8 @@ function setupModuleLoader(window) {
212
315
  * @ngdoc method
213
316
  * @name angular.Module#controller
214
317
  * @methodOf angular.Module
215
- * @param {string} name Controller name.
318
+ * @param {string|Object} name Controller name, or an object map of controllers where the
319
+ * keys are the names and the values are the constructors.
216
320
  * @param {Function} constructor Controller constructor function.
217
321
  * @description
218
322
  * See {@link ng.$controllerProvider#register $controllerProvider.register()}.
@@ -223,11 +327,12 @@ function setupModuleLoader(window) {
223
327
  * @ngdoc method
224
328
  * @name angular.Module#directive
225
329
  * @methodOf angular.Module
226
- * @param {string} name directive name
330
+ * @param {string|Object} name Directive name, or an object map of directives where the
331
+ * keys are the names and the values are the factories.
227
332
  * @param {Function} directiveFactory Factory function for creating new instance of
228
333
  * directives.
229
334
  * @description
230
- * See {@link ng.$compileProvider#directive $compileProvider.directive()}.
335
+ * See {@link ng.$compileProvider#methods_directive $compileProvider.directive()}.
231
336
  */
232
337
  directive: invokeLater('$compileProvider', 'directive'),
233
338
 
@@ -274,7 +379,7 @@ function setupModuleLoader(window) {
274
379
  return function() {
275
380
  invokeQueue[insertMethod || 'push']([provider, method, arguments]);
276
381
  return moduleInstance;
277
- }
382
+ };
278
383
  }
279
384
  });
280
385
  };
@@ -282,7 +387,8 @@ function setupModuleLoader(window) {
282
387
 
283
388
  }
284
389
 
285
- )(window);
390
+ setupModuleLoader(window);
391
+ })(window);
286
392
 
287
393
  /**
288
394
  * Closure compiler type information
@@ -1,10 +1,11 @@
1
1
  /**
2
- * @license AngularJS v1.1.4
3
- * (c) 2010-2012 Google, Inc. http://angularjs.org
2
+ * @license AngularJS v1.2.6
3
+ * (c) 2010-2014 Google, Inc. http://angularjs.org
4
4
  * License: MIT
5
- *
6
- * TODO(vojta): wrap whole file into closure during build
7
5
  */
6
+ (function(window, angular, undefined) {
7
+
8
+ 'use strict';
8
9
 
9
10
  /**
10
11
  * @ngdoc overview
@@ -29,7 +30,7 @@ angular.mock = {};
29
30
  * that there are several helper methods available which can be used in tests.
30
31
  */
31
32
  angular.mock.$BrowserProvider = function() {
32
- this.$get = function(){
33
+ this.$get = function() {
33
34
  return new angular.mock.$Browser();
34
35
  };
35
36
  };
@@ -75,6 +76,13 @@ angular.mock.$Browser = function() {
75
76
  };
76
77
 
77
78
 
79
+ /**
80
+ * @name ngMock.$browser#defer.now
81
+ * @propertyOf ngMock.$browser
82
+ *
83
+ * @description
84
+ * Current milliseconds mock time.
85
+ */
78
86
  self.defer.now = 0;
79
87
 
80
88
 
@@ -110,7 +118,7 @@ angular.mock.$Browser = function() {
110
118
  if (self.deferredFns.length) {
111
119
  self.defer.now = self.deferredFns[self.deferredFns.length-1].time;
112
120
  } else {
113
- throw Error('No deferred tasks to be flushed');
121
+ throw new Error('No deferred tasks to be flushed');
114
122
  }
115
123
  }
116
124
 
@@ -118,13 +126,6 @@ angular.mock.$Browser = function() {
118
126
  self.deferredFns.shift().fn();
119
127
  }
120
128
  };
121
- /**
122
- * @name ngMock.$browser#defer.now
123
- * @propertyOf ngMock.$browser
124
- *
125
- * @description
126
- * Current milliseconds mock time.
127
- */
128
129
 
129
130
  self.$$baseHref = '';
130
131
  self.baseHref = function() {
@@ -162,7 +163,7 @@ angular.mock.$Browser.prototype = {
162
163
 
163
164
  cookies: function(name, value) {
164
165
  if (name) {
165
- if (value == undefined) {
166
+ if (angular.isUndefined(value)) {
166
167
  delete this.cookieHash[name];
167
168
  } else {
168
169
  if (angular.isString(value) && //strings only
@@ -190,8 +191,8 @@ angular.mock.$Browser.prototype = {
190
191
  * @name ngMock.$exceptionHandlerProvider
191
192
  *
192
193
  * @description
193
- * Configures the mock implementation of {@link ng.$exceptionHandler} to rethrow or to log errors passed
194
- * into the `$exceptionHandler`.
194
+ * Configures the mock implementation of {@link ng.$exceptionHandler} to rethrow or to log errors
195
+ * passed into the `$exceptionHandler`.
195
196
  */
196
197
 
197
198
  /**
@@ -241,13 +242,13 @@ angular.mock.$ExceptionHandlerProvider = function() {
241
242
  *
242
243
  * @param {string} mode Mode of operation, defaults to `rethrow`.
243
244
  *
244
- * - `rethrow`: If any errors are are passed into the handler in tests, it typically
245
+ * - `rethrow`: If any errors are passed into the handler in tests, it typically
245
246
  * means that there is a bug in the application or test, so this mock will
246
247
  * make these tests fail.
247
- * - `log`: Sometimes it is desirable to test that an error is thrown, for this case the `log` mode stores an
248
- * array of errors in `$exceptionHandler.errors`, to allow later assertion of them.
249
- * See {@link ngMock.$log#assertEmpty assertEmpty()} and
250
- * {@link ngMock.$log#reset reset()}
248
+ * - `log`: Sometimes it is desirable to test that an error is thrown, for this case the `log`
249
+ * mode stores an array of errors in `$exceptionHandler.errors`, to allow later
250
+ * assertion of them. See {@link ngMock.$log#assertEmpty assertEmpty()} and
251
+ * {@link ngMock.$log#reset reset()}
251
252
  */
252
253
  this.mode = function(mode) {
253
254
  switch(mode) {
@@ -270,7 +271,7 @@ angular.mock.$ExceptionHandlerProvider = function() {
270
271
  handler.errors = errors;
271
272
  break;
272
273
  default:
273
- throw Error("Unknown mode '" + mode + "', only 'log'/'rethrow' modes are allowed!");
274
+ throw new Error("Unknown mode '" + mode + "', only 'log'/'rethrow' modes are allowed!");
274
275
  }
275
276
  };
276
277
 
@@ -293,18 +294,32 @@ angular.mock.$ExceptionHandlerProvider = function() {
293
294
  *
294
295
  */
295
296
  angular.mock.$LogProvider = function() {
297
+ var debug = true;
296
298
 
297
299
  function concat(array1, array2, index) {
298
300
  return array1.concat(Array.prototype.slice.call(array2, index));
299
301
  }
300
302
 
303
+ this.debugEnabled = function(flag) {
304
+ if (angular.isDefined(flag)) {
305
+ debug = flag;
306
+ return this;
307
+ } else {
308
+ return debug;
309
+ }
310
+ };
301
311
 
302
312
  this.$get = function () {
303
313
  var $log = {
304
314
  log: function() { $log.log.logs.push(concat([], arguments, 0)); },
305
315
  warn: function() { $log.warn.logs.push(concat([], arguments, 0)); },
306
316
  info: function() { $log.info.logs.push(concat([], arguments, 0)); },
307
- error: function() { $log.error.logs.push(concat([], arguments, 0)); }
317
+ error: function() { $log.error.logs.push(concat([], arguments, 0)); },
318
+ debug: function() {
319
+ if (debug) {
320
+ $log.debug.logs.push(concat([], arguments, 0));
321
+ }
322
+ }
308
323
  };
309
324
 
310
325
  /**
@@ -322,36 +337,75 @@ angular.mock.$LogProvider = function() {
322
337
  * @propertyOf ngMock.$log
323
338
  *
324
339
  * @description
325
- * Array of logged messages.
340
+ * Array of messages logged using {@link ngMock.$log#log}.
341
+ *
342
+ * @example
343
+ * <pre>
344
+ * $log.log('Some Log');
345
+ * var first = $log.log.logs.unshift();
346
+ * </pre>
326
347
  */
327
348
  $log.log.logs = [];
328
349
  /**
329
350
  * @ngdoc property
330
- * @name ngMock.$log#warn.logs
351
+ * @name ngMock.$log#info.logs
331
352
  * @propertyOf ngMock.$log
332
353
  *
333
354
  * @description
334
- * Array of logged messages.
355
+ * Array of messages logged using {@link ngMock.$log#info}.
356
+ *
357
+ * @example
358
+ * <pre>
359
+ * $log.info('Some Info');
360
+ * var first = $log.info.logs.unshift();
361
+ * </pre>
335
362
  */
336
- $log.warn.logs = [];
363
+ $log.info.logs = [];
337
364
  /**
338
365
  * @ngdoc property
339
- * @name ngMock.$log#info.logs
366
+ * @name ngMock.$log#warn.logs
340
367
  * @propertyOf ngMock.$log
341
368
  *
342
369
  * @description
343
- * Array of logged messages.
370
+ * Array of messages logged using {@link ngMock.$log#warn}.
371
+ *
372
+ * @example
373
+ * <pre>
374
+ * $log.warn('Some Warning');
375
+ * var first = $log.warn.logs.unshift();
376
+ * </pre>
344
377
  */
345
- $log.info.logs = [];
378
+ $log.warn.logs = [];
346
379
  /**
347
380
  * @ngdoc property
348
381
  * @name ngMock.$log#error.logs
349
382
  * @propertyOf ngMock.$log
350
383
  *
351
384
  * @description
352
- * Array of logged messages.
385
+ * Array of messages logged using {@link ngMock.$log#error}.
386
+ *
387
+ * @example
388
+ * <pre>
389
+ * $log.log('Some Error');
390
+ * var first = $log.error.logs.unshift();
391
+ * </pre>
353
392
  */
354
393
  $log.error.logs = [];
394
+ /**
395
+ * @ngdoc property
396
+ * @name ngMock.$log#debug.logs
397
+ * @propertyOf ngMock.$log
398
+ *
399
+ * @description
400
+ * Array of messages logged using {@link ngMock.$log#debug}.
401
+ *
402
+ * @example
403
+ * <pre>
404
+ * $log.debug('Some Error');
405
+ * var first = $log.debug.logs.unshift();
406
+ * </pre>
407
+ */
408
+ $log.debug.logs = [];
355
409
  };
356
410
 
357
411
  /**
@@ -360,20 +414,22 @@ angular.mock.$LogProvider = function() {
360
414
  * @methodOf ngMock.$log
361
415
  *
362
416
  * @description
363
- * Assert that the all of the logging methods have no logged messages. If messages present, an exception is thrown.
417
+ * Assert that the all of the logging methods have no logged messages. If messages present, an
418
+ * exception is thrown.
364
419
  */
365
420
  $log.assertEmpty = function() {
366
421
  var errors = [];
367
- angular.forEach(['error', 'warn', 'info', 'log'], function(logLevel) {
422
+ angular.forEach(['error', 'warn', 'info', 'log', 'debug'], function(logLevel) {
368
423
  angular.forEach($log[logLevel].logs, function(log) {
369
424
  angular.forEach(log, function (logItem) {
370
- errors.push('MOCK $log (' + logLevel + '): ' + String(logItem) + '\n' + (logItem.stack || ''));
425
+ errors.push('MOCK $log (' + logLevel + '): ' + String(logItem) + '\n' +
426
+ (logItem.stack || ''));
371
427
  });
372
428
  });
373
429
  });
374
430
  if (errors.length) {
375
- errors.unshift("Expected $log to be empty! Either a message was logged unexpectedly, or an expected " +
376
- "log message was not checked and removed:");
431
+ errors.unshift("Expected $log to be empty! Either a message was logged unexpectedly, or "+
432
+ "an expected log message was not checked and removed:");
377
433
  errors.push('');
378
434
  throw new Error(errors.join('\n---------\n'));
379
435
  }
@@ -385,260 +441,371 @@ angular.mock.$LogProvider = function() {
385
441
  };
386
442
 
387
443
 
388
- (function() {
389
- var R_ISO8061_STR = /^(\d{4})-?(\d\d)-?(\d\d)(?:T(\d\d)(?:\:?(\d\d)(?:\:?(\d\d)(?:\.(\d{3}))?)?)?(Z|([+-])(\d\d):?(\d\d)))?$/;
390
-
391
- function jsonStringToDate(string){
392
- var match;
393
- if (match = string.match(R_ISO8061_STR)) {
394
- var date = new Date(0),
395
- tzHour = 0,
396
- tzMin = 0;
397
- if (match[9]) {
398
- tzHour = int(match[9] + match[10]);
399
- tzMin = int(match[9] + match[11]);
400
- }
401
- date.setUTCFullYear(int(match[1]), int(match[2]) - 1, int(match[3]));
402
- date.setUTCHours(int(match[4]||0) - tzHour, int(match[5]||0) - tzMin, int(match[6]||0), int(match[7]||0));
403
- return date;
404
- }
405
- return string;
406
- }
407
-
408
- function int(str) {
409
- return parseInt(str, 10);
410
- }
411
-
412
- function padNumber(num, digits, trim) {
413
- var neg = '';
414
- if (num < 0) {
415
- neg = '-';
416
- num = -num;
417
- }
418
- num = '' + num;
419
- while(num.length < digits) num = '0' + num;
420
- if (trim)
421
- num = num.substr(num.length - digits);
422
- return neg + num;
423
- }
424
-
425
-
426
- /**
427
- * @ngdoc object
428
- * @name angular.mock.TzDate
429
- * @description
430
- *
431
- * *NOTE*: this is not an injectable instance, just a globally available mock class of `Date`.
432
- *
433
- * Mock of the Date type which has its timezone specified via constructor arg.
434
- *
435
- * The main purpose is to create Date-like instances with timezone fixed to the specified timezone
436
- * offset, so that we can test code that depends on local timezone settings without dependency on
437
- * the time zone settings of the machine where the code is running.
438
- *
439
- * @param {number} offset Offset of the *desired* timezone in hours (fractions will be honored)
440
- * @param {(number|string)} timestamp Timestamp representing the desired time in *UTC*
441
- *
442
- * @example
443
- * !!!! WARNING !!!!!
444
- * This is not a complete Date object so only methods that were implemented can be called safely.
445
- * To make matters worse, TzDate instances inherit stuff from Date via a prototype.
446
- *
447
- * We do our best to intercept calls to "unimplemented" methods, but since the list of methods is
448
- * incomplete we might be missing some non-standard methods. This can result in errors like:
449
- * "Date.prototype.foo called on incompatible Object".
450
- *
451
- * <pre>
452
- * var newYearInBratislava = new TzDate(-1, '2009-12-31T23:00:00Z');
453
- * newYearInBratislava.getTimezoneOffset() => -60;
454
- * newYearInBratislava.getFullYear() => 2010;
455
- * newYearInBratislava.getMonth() => 0;
456
- * newYearInBratislava.getDate() => 1;
457
- * newYearInBratislava.getHours() => 0;
458
- * newYearInBratislava.getMinutes() => 0;
459
- * newYearInBratislava.getSeconds() => 0;
460
- * </pre>
461
- *
462
- */
463
- angular.mock.TzDate = function (offset, timestamp) {
464
- var self = new Date(0);
465
- if (angular.isString(timestamp)) {
466
- var tsStr = timestamp;
467
-
468
- self.origDate = jsonStringToDate(timestamp);
469
-
470
- timestamp = self.origDate.getTime();
471
- if (isNaN(timestamp))
472
- throw {
473
- name: "Illegal Argument",
474
- message: "Arg '" + tsStr + "' passed into TzDate constructor is not a valid date string"
475
- };
476
- } else {
477
- self.origDate = new Date(timestamp);
478
- }
479
-
480
- var localOffset = new Date(timestamp).getTimezoneOffset();
481
- self.offsetDiff = localOffset*60*1000 - offset*1000*60*60;
482
- self.date = new Date(timestamp + self.offsetDiff);
444
+ /**
445
+ * @ngdoc service
446
+ * @name ngMock.$interval
447
+ *
448
+ * @description
449
+ * Mock implementation of the $interval service.
450
+ *
451
+ * Use {@link ngMock.$interval#methods_flush `$interval.flush(millis)`} to
452
+ * move forward by `millis` milliseconds and trigger any functions scheduled to run in that
453
+ * time.
454
+ *
455
+ * @param {function()} fn A function that should be called repeatedly.
456
+ * @param {number} delay Number of milliseconds between each function call.
457
+ * @param {number=} [count=0] Number of times to repeat. If not set, or 0, will repeat
458
+ * indefinitely.
459
+ * @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise
460
+ * will invoke `fn` within the {@link ng.$rootScope.Scope#methods_$apply $apply} block.
461
+ * @returns {promise} A promise which will be notified on each iteration.
462
+ */
463
+ angular.mock.$IntervalProvider = function() {
464
+ this.$get = ['$rootScope', '$q',
465
+ function($rootScope, $q) {
466
+ var repeatFns = [],
467
+ nextRepeatId = 0,
468
+ now = 0;
483
469
 
484
- self.getTime = function() {
485
- return self.date.getTime() - self.offsetDiff;
486
- };
470
+ var $interval = function(fn, delay, count, invokeApply) {
471
+ var deferred = $q.defer(),
472
+ promise = deferred.promise,
473
+ iteration = 0,
474
+ skipApply = (angular.isDefined(invokeApply) && !invokeApply);
487
475
 
488
- self.toLocaleDateString = function() {
489
- return self.date.toLocaleDateString();
490
- };
476
+ count = (angular.isDefined(count)) ? count : 0,
477
+ promise.then(null, null, fn);
491
478
 
492
- self.getFullYear = function() {
493
- return self.date.getFullYear();
494
- };
479
+ promise.$$intervalId = nextRepeatId;
495
480
 
496
- self.getMonth = function() {
497
- return self.date.getMonth();
498
- };
481
+ function tick() {
482
+ deferred.notify(iteration++);
499
483
 
500
- self.getDate = function() {
501
- return self.date.getDate();
502
- };
484
+ if (count > 0 && iteration >= count) {
485
+ var fnIndex;
486
+ deferred.resolve(iteration);
503
487
 
504
- self.getHours = function() {
505
- return self.date.getHours();
506
- };
507
-
508
- self.getMinutes = function() {
509
- return self.date.getMinutes();
510
- };
488
+ angular.forEach(repeatFns, function(fn, index) {
489
+ if (fn.id === promise.$$intervalId) fnIndex = index;
490
+ });
511
491
 
512
- self.getSeconds = function() {
513
- return self.date.getSeconds();
514
- };
492
+ if (fnIndex !== undefined) {
493
+ repeatFns.splice(fnIndex, 1);
494
+ }
495
+ }
515
496
 
516
- self.getMilliseconds = function() {
517
- return self.date.getMilliseconds();
518
- };
497
+ if (!skipApply) $rootScope.$apply();
498
+ }
519
499
 
520
- self.getTimezoneOffset = function() {
521
- return offset * 60;
522
- };
500
+ repeatFns.push({
501
+ nextTime:(now + delay),
502
+ delay: delay,
503
+ fn: tick,
504
+ id: nextRepeatId,
505
+ deferred: deferred
506
+ });
507
+ repeatFns.sort(function(a,b){ return a.nextTime - b.nextTime;});
523
508
 
524
- self.getUTCFullYear = function() {
525
- return self.origDate.getUTCFullYear();
509
+ nextRepeatId++;
510
+ return promise;
526
511
  };
527
512
 
528
- self.getUTCMonth = function() {
529
- return self.origDate.getUTCMonth();
530
- };
513
+ $interval.cancel = function(promise) {
514
+ var fnIndex;
531
515
 
532
- self.getUTCDate = function() {
533
- return self.origDate.getUTCDate();
534
- };
516
+ angular.forEach(repeatFns, function(fn, index) {
517
+ if (fn.id === promise.$$intervalId) fnIndex = index;
518
+ });
535
519
 
536
- self.getUTCHours = function() {
537
- return self.origDate.getUTCHours();
538
- };
520
+ if (fnIndex !== undefined) {
521
+ repeatFns[fnIndex].deferred.reject('canceled');
522
+ repeatFns.splice(fnIndex, 1);
523
+ return true;
524
+ }
539
525
 
540
- self.getUTCMinutes = function() {
541
- return self.origDate.getUTCMinutes();
526
+ return false;
542
527
  };
543
528
 
544
- self.getUTCSeconds = function() {
545
- return self.origDate.getUTCSeconds();
529
+ /**
530
+ * @ngdoc method
531
+ * @name ngMock.$interval#flush
532
+ * @methodOf ngMock.$interval
533
+ * @description
534
+ *
535
+ * Runs interval tasks scheduled to be run in the next `millis` milliseconds.
536
+ *
537
+ * @param {number=} millis maximum timeout amount to flush up until.
538
+ *
539
+ * @return {number} The amount of time moved forward.
540
+ */
541
+ $interval.flush = function(millis) {
542
+ now += millis;
543
+ while (repeatFns.length && repeatFns[0].nextTime <= now) {
544
+ var task = repeatFns[0];
545
+ task.fn();
546
+ task.nextTime += task.delay;
547
+ repeatFns.sort(function(a,b){ return a.nextTime - b.nextTime;});
548
+ }
549
+ return millis;
546
550
  };
547
551
 
548
- self.getUTCMilliseconds = function() {
549
- return self.origDate.getUTCMilliseconds();
550
- };
552
+ return $interval;
553
+ }];
554
+ };
551
555
 
552
- self.getDay = function() {
553
- return self.date.getDay();
554
- };
555
556
 
556
- // provide this method only on browsers that already have it
557
- if (self.toISOString) {
558
- self.toISOString = function() {
559
- return padNumber(self.origDate.getUTCFullYear(), 4) + '-' +
560
- padNumber(self.origDate.getUTCMonth() + 1, 2) + '-' +
561
- padNumber(self.origDate.getUTCDate(), 2) + 'T' +
562
- padNumber(self.origDate.getUTCHours(), 2) + ':' +
563
- padNumber(self.origDate.getUTCMinutes(), 2) + ':' +
564
- padNumber(self.origDate.getUTCSeconds(), 2) + '.' +
565
- padNumber(self.origDate.getUTCMilliseconds(), 3) + 'Z'
566
- }
557
+ /* jshint -W101 */
558
+ /* The R_ISO8061_STR regex is never going to fit into the 100 char limit!
559
+ * This directive should go inside the anonymous function but a bug in JSHint means that it would
560
+ * not be enacted early enough to prevent the warning.
561
+ */
562
+ var R_ISO8061_STR = /^(\d{4})-?(\d\d)-?(\d\d)(?:T(\d\d)(?:\:?(\d\d)(?:\:?(\d\d)(?:\.(\d{3}))?)?)?(Z|([+-])(\d\d):?(\d\d)))?$/;
563
+
564
+ function jsonStringToDate(string) {
565
+ var match;
566
+ if (match = string.match(R_ISO8061_STR)) {
567
+ var date = new Date(0),
568
+ tzHour = 0,
569
+ tzMin = 0;
570
+ if (match[9]) {
571
+ tzHour = int(match[9] + match[10]);
572
+ tzMin = int(match[9] + match[11]);
567
573
  }
574
+ date.setUTCFullYear(int(match[1]), int(match[2]) - 1, int(match[3]));
575
+ date.setUTCHours(int(match[4]||0) - tzHour,
576
+ int(match[5]||0) - tzMin,
577
+ int(match[6]||0),
578
+ int(match[7]||0));
579
+ return date;
580
+ }
581
+ return string;
582
+ }
568
583
 
569
- //hide all methods not implemented in this mock that the Date prototype exposes
570
- var unimplementedMethods = ['getUTCDay',
571
- 'getYear', 'setDate', 'setFullYear', 'setHours', 'setMilliseconds',
572
- 'setMinutes', 'setMonth', 'setSeconds', 'setTime', 'setUTCDate', 'setUTCFullYear',
573
- 'setUTCHours', 'setUTCMilliseconds', 'setUTCMinutes', 'setUTCMonth', 'setUTCSeconds',
574
- 'setYear', 'toDateString', 'toGMTString', 'toJSON', 'toLocaleFormat', 'toLocaleString',
575
- 'toLocaleTimeString', 'toSource', 'toString', 'toTimeString', 'toUTCString', 'valueOf'];
576
-
577
- angular.forEach(unimplementedMethods, function(methodName) {
578
- self[methodName] = function() {
579
- throw Error("Method '" + methodName + "' is not implemented in the TzDate mock");
580
- };
581
- });
584
+ function int(str) {
585
+ return parseInt(str, 10);
586
+ }
582
587
 
583
- return self;
584
- };
588
+ function padNumber(num, digits, trim) {
589
+ var neg = '';
590
+ if (num < 0) {
591
+ neg = '-';
592
+ num = -num;
593
+ }
594
+ num = '' + num;
595
+ while(num.length < digits) num = '0' + num;
596
+ if (trim)
597
+ num = num.substr(num.length - digits);
598
+ return neg + num;
599
+ }
585
600
 
586
- //make "tzDateInstance instanceof Date" return true
587
- angular.mock.TzDate.prototype = Date.prototype;
588
- })();
589
601
 
590
602
  /**
591
- * @ngdoc function
592
- * @name angular.mock.createMockWindow
603
+ * @ngdoc object
604
+ * @name angular.mock.TzDate
593
605
  * @description
594
606
  *
595
- * This function creates a mock window object useful for controlling access ot setTimeout, but mocking out
596
- * sufficient window's properties to allow Angular to execute.
607
+ * *NOTE*: this is not an injectable instance, just a globally available mock class of `Date`.
608
+ *
609
+ * Mock of the Date type which has its timezone specified via constructor arg.
610
+ *
611
+ * The main purpose is to create Date-like instances with timezone fixed to the specified timezone
612
+ * offset, so that we can test code that depends on local timezone settings without dependency on
613
+ * the time zone settings of the machine where the code is running.
614
+ *
615
+ * @param {number} offset Offset of the *desired* timezone in hours (fractions will be honored)
616
+ * @param {(number|string)} timestamp Timestamp representing the desired time in *UTC*
597
617
  *
598
618
  * @example
619
+ * !!!! WARNING !!!!!
620
+ * This is not a complete Date object so only methods that were implemented can be called safely.
621
+ * To make matters worse, TzDate instances inherit stuff from Date via a prototype.
622
+ *
623
+ * We do our best to intercept calls to "unimplemented" methods, but since the list of methods is
624
+ * incomplete we might be missing some non-standard methods. This can result in errors like:
625
+ * "Date.prototype.foo called on incompatible Object".
599
626
  *
600
627
  * <pre>
601
- beforeEach(module(function($provide) {
602
- $provide.value('$window', window = angular.mock.createMockWindow());
603
- }));
604
-
605
- it('should do something', inject(function($window) {
606
- var val = null;
607
- $window.setTimeout(function() { val = 123; }, 10);
608
- expect(val).toEqual(null);
609
- window.setTimeout.expect(10).process();
610
- expect(val).toEqual(123);
611
- });
628
+ * var newYearInBratislava = new TzDate(-1, '2009-12-31T23:00:00Z');
629
+ * newYearInBratislava.getTimezoneOffset() => -60;
630
+ * newYearInBratislava.getFullYear() => 2010;
631
+ * newYearInBratislava.getMonth() => 0;
632
+ * newYearInBratislava.getDate() => 1;
633
+ * newYearInBratislava.getHours() => 0;
634
+ * newYearInBratislava.getMinutes() => 0;
635
+ * newYearInBratislava.getSeconds() => 0;
612
636
  * </pre>
613
637
  *
614
638
  */
615
- angular.mock.createMockWindow = function() {
616
- var mockWindow = {};
617
- var setTimeoutQueue = [];
618
-
619
- mockWindow.document = window.document;
620
- mockWindow.getComputedStyle = angular.bind(window, window.getComputedStyle);
621
- mockWindow.scrollTo = angular.bind(window, window.scrollTo);
622
- mockWindow.navigator = window.navigator;
623
- mockWindow.setTimeout = function(fn, delay) {
624
- setTimeoutQueue.push({fn: fn, delay: delay});
625
- };
626
- mockWindow.setTimeout.queue = setTimeoutQueue;
627
- mockWindow.setTimeout.expect = function(delay) {
628
- if (setTimeoutQueue.length > 0) {
629
- return {
630
- process: function() {
631
- setTimeoutQueue.shift().fn();
632
- }
639
+ angular.mock.TzDate = function (offset, timestamp) {
640
+ var self = new Date(0);
641
+ if (angular.isString(timestamp)) {
642
+ var tsStr = timestamp;
643
+
644
+ self.origDate = jsonStringToDate(timestamp);
645
+
646
+ timestamp = self.origDate.getTime();
647
+ if (isNaN(timestamp))
648
+ throw {
649
+ name: "Illegal Argument",
650
+ message: "Arg '" + tsStr + "' passed into TzDate constructor is not a valid date string"
633
651
  };
634
- } else {
635
- expect('SetTimoutQueue empty. Expecting delay of ').toEqual(delay);
636
- }
652
+ } else {
653
+ self.origDate = new Date(timestamp);
654
+ }
655
+
656
+ var localOffset = new Date(timestamp).getTimezoneOffset();
657
+ self.offsetDiff = localOffset*60*1000 - offset*1000*60*60;
658
+ self.date = new Date(timestamp + self.offsetDiff);
659
+
660
+ self.getTime = function() {
661
+ return self.date.getTime() - self.offsetDiff;
662
+ };
663
+
664
+ self.toLocaleDateString = function() {
665
+ return self.date.toLocaleDateString();
666
+ };
667
+
668
+ self.getFullYear = function() {
669
+ return self.date.getFullYear();
670
+ };
671
+
672
+ self.getMonth = function() {
673
+ return self.date.getMonth();
674
+ };
675
+
676
+ self.getDate = function() {
677
+ return self.date.getDate();
678
+ };
679
+
680
+ self.getHours = function() {
681
+ return self.date.getHours();
682
+ };
683
+
684
+ self.getMinutes = function() {
685
+ return self.date.getMinutes();
686
+ };
687
+
688
+ self.getSeconds = function() {
689
+ return self.date.getSeconds();
690
+ };
691
+
692
+ self.getMilliseconds = function() {
693
+ return self.date.getMilliseconds();
694
+ };
695
+
696
+ self.getTimezoneOffset = function() {
697
+ return offset * 60;
698
+ };
699
+
700
+ self.getUTCFullYear = function() {
701
+ return self.origDate.getUTCFullYear();
702
+ };
703
+
704
+ self.getUTCMonth = function() {
705
+ return self.origDate.getUTCMonth();
706
+ };
707
+
708
+ self.getUTCDate = function() {
709
+ return self.origDate.getUTCDate();
710
+ };
711
+
712
+ self.getUTCHours = function() {
713
+ return self.origDate.getUTCHours();
637
714
  };
638
715
 
639
- return mockWindow;
716
+ self.getUTCMinutes = function() {
717
+ return self.origDate.getUTCMinutes();
718
+ };
719
+
720
+ self.getUTCSeconds = function() {
721
+ return self.origDate.getUTCSeconds();
722
+ };
723
+
724
+ self.getUTCMilliseconds = function() {
725
+ return self.origDate.getUTCMilliseconds();
726
+ };
727
+
728
+ self.getDay = function() {
729
+ return self.date.getDay();
730
+ };
731
+
732
+ // provide this method only on browsers that already have it
733
+ if (self.toISOString) {
734
+ self.toISOString = function() {
735
+ return padNumber(self.origDate.getUTCFullYear(), 4) + '-' +
736
+ padNumber(self.origDate.getUTCMonth() + 1, 2) + '-' +
737
+ padNumber(self.origDate.getUTCDate(), 2) + 'T' +
738
+ padNumber(self.origDate.getUTCHours(), 2) + ':' +
739
+ padNumber(self.origDate.getUTCMinutes(), 2) + ':' +
740
+ padNumber(self.origDate.getUTCSeconds(), 2) + '.' +
741
+ padNumber(self.origDate.getUTCMilliseconds(), 3) + 'Z';
742
+ };
743
+ }
744
+
745
+ //hide all methods not implemented in this mock that the Date prototype exposes
746
+ var unimplementedMethods = ['getUTCDay',
747
+ 'getYear', 'setDate', 'setFullYear', 'setHours', 'setMilliseconds',
748
+ 'setMinutes', 'setMonth', 'setSeconds', 'setTime', 'setUTCDate', 'setUTCFullYear',
749
+ 'setUTCHours', 'setUTCMilliseconds', 'setUTCMinutes', 'setUTCMonth', 'setUTCSeconds',
750
+ 'setYear', 'toDateString', 'toGMTString', 'toJSON', 'toLocaleFormat', 'toLocaleString',
751
+ 'toLocaleTimeString', 'toSource', 'toString', 'toTimeString', 'toUTCString', 'valueOf'];
752
+
753
+ angular.forEach(unimplementedMethods, function(methodName) {
754
+ self[methodName] = function() {
755
+ throw new Error("Method '" + methodName + "' is not implemented in the TzDate mock");
756
+ };
757
+ });
758
+
759
+ return self;
640
760
  };
641
761
 
762
+ //make "tzDateInstance instanceof Date" return true
763
+ angular.mock.TzDate.prototype = Date.prototype;
764
+ /* jshint +W101 */
765
+
766
+ angular.mock.animate = angular.module('mock.animate', ['ng'])
767
+
768
+ .config(['$provide', function($provide) {
769
+
770
+ $provide.decorator('$animate', function($delegate) {
771
+ var animate = {
772
+ queue : [],
773
+ enabled : $delegate.enabled,
774
+ flushNext : function(name) {
775
+ var tick = animate.queue.shift();
776
+
777
+ if (!tick) throw new Error('No animation to be flushed');
778
+ if(tick.method !== name) {
779
+ throw new Error('The next animation is not "' + name +
780
+ '", but is "' + tick.method + '"');
781
+ }
782
+ tick.fn();
783
+ return tick;
784
+ }
785
+ };
786
+
787
+ angular.forEach(['enter','leave','move','addClass','removeClass'], function(method) {
788
+ animate[method] = function() {
789
+ var params = arguments;
790
+ animate.queue.push({
791
+ method : method,
792
+ params : params,
793
+ element : angular.isElement(params[0]) && params[0],
794
+ parent : angular.isElement(params[1]) && params[1],
795
+ after : angular.isElement(params[2]) && params[2],
796
+ fn : function() {
797
+ $delegate[method].apply($delegate, params);
798
+ }
799
+ });
800
+ };
801
+ });
802
+
803
+ return animate;
804
+ });
805
+
806
+ }]);
807
+
808
+
642
809
  /**
643
810
  * @ngdoc function
644
811
  * @name angular.mock.dump
@@ -646,9 +813,11 @@ angular.mock.createMockWindow = function() {
646
813
  *
647
814
  * *NOTE*: this is not an injectable instance, just a globally available function.
648
815
  *
649
- * Method for serializing common angular objects (scope, elements, etc..) into strings, useful for debugging.
816
+ * Method for serializing common angular objects (scope, elements, etc..) into strings, useful for
817
+ * debugging.
650
818
  *
651
- * This method is also available on window, where it can be used to display objects on debug console.
819
+ * This method is also available on window, where it can be used to display objects on debug
820
+ * console.
652
821
  *
653
822
  * @param {*} object - any object to turn into string.
654
823
  * @return {string} a serialized string of the argument
@@ -678,6 +847,8 @@ angular.mock.dump = function(object) {
678
847
  } else if (object instanceof Error) {
679
848
  out = object.stack || ('' + object.name + ': ' + object.message);
680
849
  } else {
850
+ // TODO(i): this prevents methods being logged,
851
+ // we should have a better way to serialize objects
681
852
  out = angular.toJson(object, true);
682
853
  }
683
854
  } else {
@@ -691,7 +862,7 @@ angular.mock.dump = function(object) {
691
862
  offset = offset || ' ';
692
863
  var log = [offset + 'Scope(' + scope.$id + '): {'];
693
864
  for ( var key in scope ) {
694
- if (scope.hasOwnProperty(key) && !key.match(/^(\$|this)/)) {
865
+ if (Object.prototype.hasOwnProperty.call(scope, key) && !key.match(/^(\$|this)/)) {
695
866
  log.push(' ' + key + ': ' + angular.toJson(scope[key]));
696
867
  }
697
868
  }
@@ -709,10 +880,10 @@ angular.mock.dump = function(object) {
709
880
  * @ngdoc object
710
881
  * @name ngMock.$httpBackend
711
882
  * @description
712
- * Fake HTTP backend implementation suitable for unit testing application that use the
883
+ * Fake HTTP backend implementation suitable for unit testing applications that use the
713
884
  * {@link ng.$http $http service}.
714
885
  *
715
- * *Note*: For fake http backend implementation suitable for end-to-end testing or backend-less
886
+ * *Note*: For fake HTTP backend implementation suitable for end-to-end testing or backend-less
716
887
  * development please see {@link ngMockE2E.$httpBackend e2e $httpBackend mock}.
717
888
  *
718
889
  * During unit testing, we want our unit tests to run quickly and have no external dependencies so
@@ -805,75 +976,100 @@ angular.mock.dump = function(object) {
805
976
  *
806
977
  *
807
978
  * # Unit testing with mock $httpBackend
979
+ * The following code shows how to setup and use the mock backend in unit testing a controller.
980
+ * First we create the controller under test
808
981
  *
809
- * <pre>
810
- // controller
811
- function MyController($scope, $http) {
812
- $http.get('/auth.py').success(function(data) {
813
- $scope.user = data;
814
- });
815
-
816
- this.saveMessage = function(message) {
817
- $scope.status = 'Saving...';
818
- $http.post('/add-msg.py', message).success(function(response) {
819
- $scope.status = '';
820
- }).error(function() {
821
- $scope.status = 'ERROR!';
822
- });
823
- };
824
- }
982
+ <pre>
983
+ // The controller code
984
+ function MyController($scope, $http) {
985
+ var authToken;
986
+
987
+ $http.get('/auth.py').success(function(data, status, headers) {
988
+ authToken = headers('A-Token');
989
+ $scope.user = data;
990
+ });
991
+
992
+ $scope.saveMessage = function(message) {
993
+ var headers = { 'Authorization': authToken };
994
+ $scope.status = 'Saving...';
995
+
996
+ $http.post('/add-msg.py', message, { headers: headers } ).success(function(response) {
997
+ $scope.status = '';
998
+ }).error(function() {
999
+ $scope.status = 'ERROR!';
1000
+ });
1001
+ };
1002
+ }
1003
+ </pre>
1004
+ *
1005
+ * Now we setup the mock backend and create the test specs.
1006
+ *
1007
+ <pre>
1008
+ // testing controller
1009
+ describe('MyController', function() {
1010
+ var $httpBackend, $rootScope, createController;
1011
+
1012
+ beforeEach(inject(function($injector) {
1013
+ // Set up the mock http service responses
1014
+ $httpBackend = $injector.get('$httpBackend');
1015
+ // backend definition common for all tests
1016
+ $httpBackend.when('GET', '/auth.py').respond({userId: 'userX'}, {'A-Token': 'xxx'});
825
1017
 
826
- // testing controller
827
- var $httpBackend;
1018
+ // Get hold of a scope (i.e. the root scope)
1019
+ $rootScope = $injector.get('$rootScope');
1020
+ // The $controller service is used to create instances of controllers
1021
+ var $controller = $injector.get('$controller');
828
1022
 
829
- beforeEach(inject(function($injector) {
830
- $httpBackend = $injector.get('$httpBackend');
1023
+ createController = function() {
1024
+ return $controller('MyController', {'$scope' : $rootScope });
1025
+ };
1026
+ }));
831
1027
 
832
- // backend definition common for all tests
833
- $httpBackend.when('GET', '/auth.py').respond({userId: 'userX'}, {'A-Token': 'xxx'});
834
- }));
1028
+
1029
+ afterEach(function() {
1030
+ $httpBackend.verifyNoOutstandingExpectation();
1031
+ $httpBackend.verifyNoOutstandingRequest();
1032
+ });
835
1033
 
836
1034
 
837
- afterEach(function() {
838
- $httpBackend.verifyNoOutstandingExpectation();
839
- $httpBackend.verifyNoOutstandingRequest();
840
- });
1035
+ it('should fetch authentication token', function() {
1036
+ $httpBackend.expectGET('/auth.py');
1037
+ var controller = createController();
1038
+ $httpBackend.flush();
1039
+ });
841
1040
 
842
1041
 
843
- it('should fetch authentication token', function() {
844
- $httpBackend.expectGET('/auth.py');
845
- var controller = scope.$new(MyController);
846
- $httpBackend.flush();
847
- });
1042
+ it('should send msg to server', function() {
1043
+ var controller = createController();
1044
+ $httpBackend.flush();
848
1045
 
1046
+ // now you don’t care about the authentication, but
1047
+ // the controller will still send the request and
1048
+ // $httpBackend will respond without you having to
1049
+ // specify the expectation and response for this request
849
1050
 
850
- it('should send msg to server', function() {
851
- // now you don’t care about the authentication, but
852
- // the controller will still send the request and
853
- // $httpBackend will respond without you having to
854
- // specify the expectation and response for this request
855
- $httpBackend.expectPOST('/add-msg.py', 'message content').respond(201, '');
1051
+ $httpBackend.expectPOST('/add-msg.py', 'message content').respond(201, '');
1052
+ $rootScope.saveMessage('message content');
1053
+ expect($rootScope.status).toBe('Saving...');
1054
+ $httpBackend.flush();
1055
+ expect($rootScope.status).toBe('');
1056
+ });
856
1057
 
857
- var controller = scope.$new(MyController);
858
- $httpBackend.flush();
859
- controller.saveMessage('message content');
860
- expect(controller.status).toBe('Saving...');
861
- $httpBackend.flush();
862
- expect(controller.status).toBe('');
863
- });
864
1058
 
1059
+ it('should send auth header', function() {
1060
+ var controller = createController();
1061
+ $httpBackend.flush();
865
1062
 
866
- it('should send auth header', function() {
867
- $httpBackend.expectPOST('/add-msg.py', undefined, function(headers) {
868
- // check if the header was send, if it wasn't the expectation won't
869
- // match the request and the test will fail
870
- return headers['Authorization'] == 'xxx';
871
- }).respond(201, '');
1063
+ $httpBackend.expectPOST('/add-msg.py', undefined, function(headers) {
1064
+ // check if the header was send, if it wasn't the expectation won't
1065
+ // match the request and the test will fail
1066
+ return headers['Authorization'] == 'xxx';
1067
+ }).respond(201, '');
872
1068
 
873
- var controller = scope.$new(MyController);
874
- controller.saveMessage('whatever');
875
- $httpBackend.flush();
876
- });
1069
+ $rootScope.saveMessage('whatever');
1070
+ $httpBackend.flush();
1071
+ });
1072
+ });
877
1073
  </pre>
878
1074
  */
879
1075
  angular.mock.$HttpBackendProvider = function() {
@@ -898,7 +1094,8 @@ function createHttpBackendMock($rootScope, $delegate, $browser) {
898
1094
  var definitions = [],
899
1095
  expectations = [],
900
1096
  responses = [],
901
- responsesPush = angular.bind(responses, responses.push);
1097
+ responsesPush = angular.bind(responses, responses.push),
1098
+ copy = angular.copy;
902
1099
 
903
1100
  function createResponse(status, data, headers) {
904
1101
  if (angular.isFunction(status)) return status;
@@ -911,7 +1108,7 @@ function createHttpBackendMock($rootScope, $delegate, $browser) {
911
1108
  }
912
1109
 
913
1110
  // TODO(vojta): change params to: method, url, data, headers, callback
914
- function $httpBackend(method, url, data, callback, headers) {
1111
+ function $httpBackend(method, url, data, callback, headers, timeout, withCredentials) {
915
1112
  var xhr = new MockXhr(),
916
1113
  expectation = expectations[0],
917
1114
  wasExpected = false;
@@ -922,24 +1119,42 @@ function createHttpBackendMock($rootScope, $delegate, $browser) {
922
1119
  : angular.toJson(data);
923
1120
  }
924
1121
 
1122
+ function wrapResponse(wrapped) {
1123
+ if (!$browser && timeout && timeout.then) timeout.then(handleTimeout);
1124
+
1125
+ return handleResponse;
1126
+
1127
+ function handleResponse() {
1128
+ var response = wrapped.response(method, url, data, headers);
1129
+ xhr.$$respHeaders = response[2];
1130
+ callback(copy(response[0]), copy(response[1]), xhr.getAllResponseHeaders());
1131
+ }
1132
+
1133
+ function handleTimeout() {
1134
+ for (var i = 0, ii = responses.length; i < ii; i++) {
1135
+ if (responses[i] === handleResponse) {
1136
+ responses.splice(i, 1);
1137
+ callback(-1, undefined, '');
1138
+ break;
1139
+ }
1140
+ }
1141
+ }
1142
+ }
1143
+
925
1144
  if (expectation && expectation.match(method, url)) {
926
1145
  if (!expectation.matchData(data))
927
- throw Error('Expected ' + expectation + ' with different data\n' +
1146
+ throw new Error('Expected ' + expectation + ' with different data\n' +
928
1147
  'EXPECTED: ' + prettyPrint(expectation.data) + '\nGOT: ' + data);
929
1148
 
930
1149
  if (!expectation.matchHeaders(headers))
931
- throw Error('Expected ' + expectation + ' with different headers\n' +
932
- 'EXPECTED: ' + prettyPrint(expectation.headers) + '\nGOT: ' +
933
- prettyPrint(headers));
1150
+ throw new Error('Expected ' + expectation + ' with different headers\n' +
1151
+ 'EXPECTED: ' + prettyPrint(expectation.headers) + '\nGOT: ' +
1152
+ prettyPrint(headers));
934
1153
 
935
1154
  expectations.shift();
936
1155
 
937
1156
  if (expectation.response) {
938
- responses.push(function() {
939
- var response = expectation.response(method, url, data, headers);
940
- xhr.$$respHeaders = response[2];
941
- callback(response[0], response[1], xhr.getAllResponseHeaders());
942
- });
1157
+ responses.push(wrapResponse(expectation));
943
1158
  return;
944
1159
  }
945
1160
  wasExpected = true;
@@ -950,21 +1165,17 @@ function createHttpBackendMock($rootScope, $delegate, $browser) {
950
1165
  if (definition.match(method, url, data, headers || {})) {
951
1166
  if (definition.response) {
952
1167
  // if $browser specified, we do auto flush all requests
953
- ($browser ? $browser.defer : responsesPush)(function() {
954
- var response = definition.response(method, url, data, headers);
955
- xhr.$$respHeaders = response[2];
956
- callback(response[0], response[1], xhr.getAllResponseHeaders());
957
- });
1168
+ ($browser ? $browser.defer : responsesPush)(wrapResponse(definition));
958
1169
  } else if (definition.passThrough) {
959
- $delegate(method, url, data, callback, headers);
960
- } else throw Error('No response defined !');
1170
+ $delegate(method, url, data, callback, headers, timeout, withCredentials);
1171
+ } else throw new Error('No response defined !');
961
1172
  return;
962
1173
  }
963
1174
  }
964
1175
  throw wasExpected ?
965
- Error('No response defined !') :
966
- Error('Unexpected request: ' + method + ' ' + url + '\n' +
967
- (expectation ? 'Expected ' + expectation : 'No more request expected'));
1176
+ new Error('No response defined !') :
1177
+ new Error('Unexpected request: ' + method + ' ' + url + '\n' +
1178
+ (expectation ? 'Expected ' + expectation : 'No more request expected'));
968
1179
  }
969
1180
 
970
1181
  /**
@@ -976,13 +1187,15 @@ function createHttpBackendMock($rootScope, $delegate, $browser) {
976
1187
  *
977
1188
  * @param {string} method HTTP method.
978
1189
  * @param {string|RegExp} url HTTP url.
979
- * @param {(string|RegExp)=} data HTTP request body.
1190
+ * @param {(string|RegExp|function(string))=} data HTTP request body or function that receives
1191
+ * data string and returns true if the data is as expected.
980
1192
  * @param {(Object|function(Object))=} headers HTTP headers or function that receives http header
981
1193
  * object and returns true if the headers match the current definition.
982
- * @returns {requestHandler} Returns an object with `respond` method that control how a matched
1194
+ * @returns {requestHandler} Returns an object with `respond` method that controls how a matched
983
1195
  * request is handled.
984
1196
  *
985
- * - respond – `{function([status,] data[, headers])|function(function(method, url, data, headers)}`
1197
+ * - respond –
1198
+ * `{function([status,] data[, headers])|function(function(method, url, data, headers)}`
986
1199
  * – The respond method takes a set of static data to be returned or a function that can return
987
1200
  * an array containing response status (number), response data (string) and response headers
988
1201
  * (Object).
@@ -1052,7 +1265,8 @@ function createHttpBackendMock($rootScope, $delegate, $browser) {
1052
1265
  * Creates a new backend definition for POST requests. For more info see `when()`.
1053
1266
  *
1054
1267
  * @param {string|RegExp} url HTTP url.
1055
- * @param {(string|RegExp)=} data HTTP request body.
1268
+ * @param {(string|RegExp|function(string))=} data HTTP request body or function that receives
1269
+ * data string and returns true if the data is as expected.
1056
1270
  * @param {(Object|function(Object))=} headers HTTP headers.
1057
1271
  * @returns {requestHandler} Returns an object with `respond` method that control how a matched
1058
1272
  * request is handled.
@@ -1066,7 +1280,8 @@ function createHttpBackendMock($rootScope, $delegate, $browser) {
1066
1280
  * Creates a new backend definition for PUT requests. For more info see `when()`.
1067
1281
  *
1068
1282
  * @param {string|RegExp} url HTTP url.
1069
- * @param {(string|RegExp)=} data HTTP request body.
1283
+ * @param {(string|RegExp|function(string))=} data HTTP request body or function that receives
1284
+ * data string and returns true if the data is as expected.
1070
1285
  * @param {(Object|function(Object))=} headers HTTP headers.
1071
1286
  * @returns {requestHandler} Returns an object with `respond` method that control how a matched
1072
1287
  * request is handled.
@@ -1095,13 +1310,16 @@ function createHttpBackendMock($rootScope, $delegate, $browser) {
1095
1310
  *
1096
1311
  * @param {string} method HTTP method.
1097
1312
  * @param {string|RegExp} url HTTP url.
1098
- * @param {(string|RegExp)=} data HTTP request body.
1313
+ * @param {(string|RegExp|function(string)|Object)=} data HTTP request body or function that
1314
+ * receives data string and returns true if the data is as expected, or Object if request body
1315
+ * is in JSON format.
1099
1316
  * @param {(Object|function(Object))=} headers HTTP headers or function that receives http header
1100
1317
  * object and returns true if the headers match the current expectation.
1101
1318
  * @returns {requestHandler} Returns an object with `respond` method that control how a matched
1102
1319
  * request is handled.
1103
1320
  *
1104
- * - respond – `{function([status,] data[, headers])|function(function(method, url, data, headers)}`
1321
+ * - respond –
1322
+ * `{function([status,] data[, headers])|function(function(method, url, data, headers)}`
1105
1323
  * – The respond method takes a set of static data to be returned or a function that can return
1106
1324
  * an array containing response status (number), response data (string) and response headers
1107
1325
  * (Object).
@@ -1164,7 +1382,9 @@ function createHttpBackendMock($rootScope, $delegate, $browser) {
1164
1382
  * Creates a new request expectation for POST requests. For more info see `expect()`.
1165
1383
  *
1166
1384
  * @param {string|RegExp} url HTTP url.
1167
- * @param {(string|RegExp)=} data HTTP request body.
1385
+ * @param {(string|RegExp|function(string)|Object)=} data HTTP request body or function that
1386
+ * receives data string and returns true if the data is as expected, or Object if request body
1387
+ * is in JSON format.
1168
1388
  * @param {Object=} headers HTTP headers.
1169
1389
  * @returns {requestHandler} Returns an object with `respond` method that control how a matched
1170
1390
  * request is handled.
@@ -1178,7 +1398,9 @@ function createHttpBackendMock($rootScope, $delegate, $browser) {
1178
1398
  * Creates a new request expectation for PUT requests. For more info see `expect()`.
1179
1399
  *
1180
1400
  * @param {string|RegExp} url HTTP url.
1181
- * @param {(string|RegExp)=} data HTTP request body.
1401
+ * @param {(string|RegExp|function(string)|Object)=} data HTTP request body or function that
1402
+ * receives data string and returns true if the data is as expected, or Object if request body
1403
+ * is in JSON format.
1182
1404
  * @param {Object=} headers HTTP headers.
1183
1405
  * @returns {requestHandler} Returns an object with `respond` method that control how a matched
1184
1406
  * request is handled.
@@ -1192,7 +1414,9 @@ function createHttpBackendMock($rootScope, $delegate, $browser) {
1192
1414
  * Creates a new request expectation for PATCH requests. For more info see `expect()`.
1193
1415
  *
1194
1416
  * @param {string|RegExp} url HTTP url.
1195
- * @param {(string|RegExp)=} data HTTP request body.
1417
+ * @param {(string|RegExp|function(string)|Object)=} data HTTP request body or function that
1418
+ * receives data string and returns true if the data is as expected, or Object if request body
1419
+ * is in JSON format.
1196
1420
  * @param {Object=} headers HTTP headers.
1197
1421
  * @returns {requestHandler} Returns an object with `respond` method that control how a matched
1198
1422
  * request is handled.
@@ -1225,11 +1449,11 @@ function createHttpBackendMock($rootScope, $delegate, $browser) {
1225
1449
  */
1226
1450
  $httpBackend.flush = function(count) {
1227
1451
  $rootScope.$digest();
1228
- if (!responses.length) throw Error('No pending request to flush !');
1452
+ if (!responses.length) throw new Error('No pending request to flush !');
1229
1453
 
1230
1454
  if (angular.isDefined(count)) {
1231
1455
  while (count--) {
1232
- if (!responses.length) throw Error('No more pending request to flush !');
1456
+ if (!responses.length) throw new Error('No more pending request to flush !');
1233
1457
  responses.shift()();
1234
1458
  }
1235
1459
  } else {
@@ -1253,13 +1477,13 @@ function createHttpBackendMock($rootScope, $delegate, $browser) {
1253
1477
  * "afterEach" clause.
1254
1478
  *
1255
1479
  * <pre>
1256
- * afterEach($httpBackend.verifyExpectations);
1480
+ * afterEach($httpBackend.verifyNoOutstandingExpectation);
1257
1481
  * </pre>
1258
1482
  */
1259
1483
  $httpBackend.verifyNoOutstandingExpectation = function() {
1260
1484
  $rootScope.$digest();
1261
1485
  if (expectations.length) {
1262
- throw Error('Unsatisfied requests: ' + expectations.join(', '));
1486
+ throw new Error('Unsatisfied requests: ' + expectations.join(', '));
1263
1487
  }
1264
1488
  };
1265
1489
 
@@ -1280,7 +1504,7 @@ function createHttpBackendMock($rootScope, $delegate, $browser) {
1280
1504
  */
1281
1505
  $httpBackend.verifyNoOutstandingRequest = function() {
1282
1506
  if (responses.length) {
1283
- throw Error('Unflushed requests: ' + responses.length);
1507
+ throw new Error('Unflushed requests: ' + responses.length);
1284
1508
  }
1285
1509
  };
1286
1510
 
@@ -1305,14 +1529,14 @@ function createHttpBackendMock($rootScope, $delegate, $browser) {
1305
1529
  function createShortMethods(prefix) {
1306
1530
  angular.forEach(['GET', 'DELETE', 'JSONP'], function(method) {
1307
1531
  $httpBackend[prefix + method] = function(url, headers) {
1308
- return $httpBackend[prefix](method, url, undefined, headers)
1309
- }
1532
+ return $httpBackend[prefix](method, url, undefined, headers);
1533
+ };
1310
1534
  });
1311
1535
 
1312
1536
  angular.forEach(['PUT', 'POST', 'PATCH'], function(method) {
1313
1537
  $httpBackend[prefix + method] = function(url, data, headers) {
1314
- return $httpBackend[prefix](method, url, data, headers)
1315
- }
1538
+ return $httpBackend[prefix](method, url, data, headers);
1539
+ };
1316
1540
  });
1317
1541
  }
1318
1542
  }
@@ -1345,7 +1569,8 @@ function MockHttpExpectation(method, url, data, headers) {
1345
1569
  this.matchData = function(d) {
1346
1570
  if (angular.isUndefined(data)) return true;
1347
1571
  if (data && angular.isFunction(data.test)) return data.test(d);
1348
- if (data && !angular.isString(data)) return angular.toJson(data) == d;
1572
+ if (data && angular.isFunction(data)) return data(d);
1573
+ if (data && !angular.isString(data)) return angular.equals(data, angular.fromJson(d));
1349
1574
  return data == d;
1350
1575
  };
1351
1576
 
@@ -1376,7 +1601,8 @@ function MockXhr() {
1376
1601
  };
1377
1602
 
1378
1603
  this.getResponseHeader = function(name) {
1379
- // the lookup must be case insensitive, that's why we try two quick lookups and full scan at last
1604
+ // the lookup must be case insensitive,
1605
+ // that's why we try two quick lookups first and full scan last
1380
1606
  var header = this.$$respHeaders[name];
1381
1607
  if (header) return header;
1382
1608
 
@@ -1411,7 +1637,7 @@ function MockXhr() {
1411
1637
  *
1412
1638
  * This service is just a simple decorator for {@link ng.$timeout $timeout} service
1413
1639
  * that adds a "flush" and "verifyNoPendingTasks" methods.
1414
- */
1640
+ */
1415
1641
 
1416
1642
  angular.mock.$TimeoutDecorator = function($delegate, $browser) {
1417
1643
 
@@ -1422,9 +1648,11 @@ angular.mock.$TimeoutDecorator = function($delegate, $browser) {
1422
1648
  * @description
1423
1649
  *
1424
1650
  * Flushes the queue of pending tasks.
1651
+ *
1652
+ * @param {number=} delay maximum timeout amount to flush up until
1425
1653
  */
1426
- $delegate.flush = function() {
1427
- $browser.defer.flush();
1654
+ $delegate.flush = function(delay) {
1655
+ $browser.defer.flush(delay);
1428
1656
  };
1429
1657
 
1430
1658
  /**
@@ -1437,7 +1665,7 @@ angular.mock.$TimeoutDecorator = function($delegate, $browser) {
1437
1665
  */
1438
1666
  $delegate.verifyNoPendingTasks = function() {
1439
1667
  if ($browser.deferredFns.length) {
1440
- throw Error('Deferred tasks to flush (' + $browser.deferredFns.length + '): ' +
1668
+ throw new Error('Deferred tasks to flush (' + $browser.deferredFns.length + '): ' +
1441
1669
  formatPendingTasksAsString($browser.deferredFns));
1442
1670
  }
1443
1671
  };
@@ -1460,7 +1688,7 @@ angular.mock.$TimeoutDecorator = function($delegate, $browser) {
1460
1688
  angular.mock.$RootElementProvider = function() {
1461
1689
  this.$get = function() {
1462
1690
  return angular.element('<div ng-app></div>');
1463
- }
1691
+ };
1464
1692
  };
1465
1693
 
1466
1694
  /**
@@ -1468,18 +1696,27 @@ angular.mock.$RootElementProvider = function() {
1468
1696
  * @name ngMock
1469
1697
  * @description
1470
1698
  *
1471
- * The `ngMock` is an angular module which is used with `ng` module and adds unit-test configuration as well as useful
1472
- * mocks to the {@link AUTO.$injector $injector}.
1699
+ * # ngMock
1700
+ *
1701
+ * The `ngMock` module providers support to inject and mock Angular services into unit tests.
1702
+ * In addition, ngMock also extends various core ng services such that they can be
1703
+ * inspected and controlled in a synchronous manner within test code.
1704
+ *
1705
+ * {@installModule mocks}
1706
+ *
1707
+ * <div doc-module-components="ngMock"></div>
1708
+ *
1473
1709
  */
1474
1710
  angular.module('ngMock', ['ng']).provider({
1475
1711
  $browser: angular.mock.$BrowserProvider,
1476
1712
  $exceptionHandler: angular.mock.$ExceptionHandlerProvider,
1477
1713
  $log: angular.mock.$LogProvider,
1714
+ $interval: angular.mock.$IntervalProvider,
1478
1715
  $httpBackend: angular.mock.$HttpBackendProvider,
1479
1716
  $rootElement: angular.mock.$RootElementProvider
1480
- }).config(function($provide) {
1717
+ }).config(['$provide', function($provide) {
1481
1718
  $provide.decorator('$timeout', angular.mock.$TimeoutDecorator);
1482
- });
1719
+ }]);
1483
1720
 
1484
1721
  /**
1485
1722
  * @ngdoc overview
@@ -1490,9 +1727,9 @@ angular.module('ngMock', ['ng']).provider({
1490
1727
  * Currently there is only one mock present in this module -
1491
1728
  * the {@link ngMockE2E.$httpBackend e2e $httpBackend} mock.
1492
1729
  */
1493
- angular.module('ngMockE2E', ['ng']).config(function($provide) {
1730
+ angular.module('ngMockE2E', ['ng']).config(['$provide', function($provide) {
1494
1731
  $provide.decorator('$httpBackend', angular.mock.e2e.$httpBackendDecorator);
1495
- });
1732
+ }]);
1496
1733
 
1497
1734
  /**
1498
1735
  * @ngdoc object
@@ -1532,7 +1769,7 @@ angular.module('ngMockE2E', ['ng']).config(function($provide) {
1532
1769
  *
1533
1770
  * // adds a new phone to the phones array
1534
1771
  * $httpBackend.whenPOST('/phones').respond(function(method, url, data) {
1535
- * phones.push(angular.fromJSON(data));
1772
+ * phones.push(angular.fromJson(data));
1536
1773
  * });
1537
1774
  * $httpBackend.whenGET(/^\/templates\//).passThrough();
1538
1775
  * //...
@@ -1557,7 +1794,8 @@ angular.module('ngMockE2E', ['ng']).config(function($provide) {
1557
1794
  * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
1558
1795
  * control how a matched request is handled.
1559
1796
  *
1560
- * - respond – `{function([status,] data[, headers])|function(function(method, url, data, headers)}`
1797
+ * - respond –
1798
+ * `{function([status,] data[, headers])|function(function(method, url, data, headers)}`
1561
1799
  * – The respond method takes a set of static data to be returned or a function that can return
1562
1800
  * an array containing response status (number), response data (string) and response headers
1563
1801
  * (Object).
@@ -1659,7 +1897,8 @@ angular.module('ngMockE2E', ['ng']).config(function($provide) {
1659
1897
  * control how a matched request is handled.
1660
1898
  */
1661
1899
  angular.mock.e2e = {};
1662
- angular.mock.e2e.$httpBackendDecorator = ['$rootScope', '$delegate', '$browser', createHttpBackendMock];
1900
+ angular.mock.e2e.$httpBackendDecorator =
1901
+ ['$rootScope', '$delegate', '$browser', createHttpBackendMock];
1663
1902
 
1664
1903
 
1665
1904
  angular.mock.clearDataCache = function() {
@@ -1667,36 +1906,24 @@ angular.mock.clearDataCache = function() {
1667
1906
  cache = angular.element.cache;
1668
1907
 
1669
1908
  for(key in cache) {
1670
- if (cache.hasOwnProperty(key)) {
1909
+ if (Object.prototype.hasOwnProperty.call(cache,key)) {
1671
1910
  var handle = cache[key].handle;
1672
1911
 
1673
- handle && angular.element(handle.elem).unbind();
1912
+ handle && angular.element(handle.elem).off();
1674
1913
  delete cache[key];
1675
1914
  }
1676
1915
  }
1677
1916
  };
1678
1917
 
1679
1918
 
1680
- window.jstestdriver && (function(window) {
1681
- /**
1682
- * Global method to output any number of objects into JSTD console. Useful for debugging.
1683
- */
1684
- window.dump = function() {
1685
- var args = [];
1686
- angular.forEach(arguments, function(arg) {
1687
- args.push(angular.mock.dump(arg));
1688
- });
1689
- jstestdriver.console.log.apply(jstestdriver.console, args);
1690
- if (window.console) {
1691
- window.console.log.apply(window.console, args);
1692
- }
1693
- };
1694
- })(window);
1695
1919
 
1920
+ if(window.jasmine || window.mocha) {
1696
1921
 
1697
- (window.jasmine || window.mocha) && (function(window) {
1922
+ var currentSpec = null,
1923
+ isSpecRunning = function() {
1924
+ return currentSpec && (window.mocha || currentSpec.queue.running);
1925
+ };
1698
1926
 
1699
- var currentSpec = null;
1700
1927
 
1701
1928
  beforeEach(function() {
1702
1929
  currentSpec = this;
@@ -1710,7 +1937,7 @@ window.jstestdriver && (function(window) {
1710
1937
  currentSpec = null;
1711
1938
 
1712
1939
  if (injector) {
1713
- injector.get('$rootElement').unbind();
1940
+ injector.get('$rootElement').off();
1714
1941
  injector.get('$browser').pollFns.length = 0;
1715
1942
  }
1716
1943
 
@@ -1729,10 +1956,6 @@ window.jstestdriver && (function(window) {
1729
1956
  angular.callbacks.counter = 0;
1730
1957
  });
1731
1958
 
1732
- function isSpecRunning() {
1733
- return currentSpec && (window.mocha || currentSpec.queue.running);
1734
- }
1735
-
1736
1959
  /**
1737
1960
  * @ngdoc function
1738
1961
  * @name angular.mock.module
@@ -1745,9 +1968,11 @@ window.jstestdriver && (function(window) {
1745
1968
  *
1746
1969
  * See {@link angular.mock.inject inject} for usage example
1747
1970
  *
1748
- * @param {...(string|Function)} fns any number of modules which are represented as string
1971
+ * @param {...(string|Function|Object)} fns any number of modules which are represented as string
1749
1972
  * aliases or as anonymous module initialization functions. The modules are used to
1750
- * configure the injector. The 'ng' and 'ngMock' modules are automatically loaded.
1973
+ * configure the injector. The 'ng' and 'ngMock' modules are automatically loaded. If an
1974
+ * object literal is passed they will be register as values in the module, the key being
1975
+ * the module name and the value being what is returned.
1751
1976
  */
1752
1977
  window.module = angular.mock.module = function() {
1753
1978
  var moduleFns = Array.prototype.slice.call(arguments, 0);
@@ -1755,11 +1980,19 @@ window.jstestdriver && (function(window) {
1755
1980
  /////////////////////
1756
1981
  function workFn() {
1757
1982
  if (currentSpec.$injector) {
1758
- throw Error('Injector already created, can not register a module!');
1983
+ throw new Error('Injector already created, can not register a module!');
1759
1984
  } else {
1760
1985
  var modules = currentSpec.$modules || (currentSpec.$modules = []);
1761
1986
  angular.forEach(moduleFns, function(module) {
1762
- modules.push(module);
1987
+ if (angular.isObject(module) && !angular.isArray(module)) {
1988
+ modules.push(function($provide) {
1989
+ angular.forEach(module, function(value, key) {
1990
+ $provide.value(key, value);
1991
+ });
1992
+ });
1993
+ } else {
1994
+ modules.push(module);
1995
+ }
1763
1996
  });
1764
1997
  }
1765
1998
  }
@@ -1776,8 +2009,40 @@ window.jstestdriver && (function(window) {
1776
2009
  * instance of {@link AUTO.$injector $injector} per test, which is then used for
1777
2010
  * resolving references.
1778
2011
  *
1779
- * See also {@link angular.mock.module module}
1780
2012
  *
2013
+ * ## Resolving References (Underscore Wrapping)
2014
+ * Often, we would like to inject a reference once, in a `beforeEach()` block and reuse this
2015
+ * in multiple `it()` clauses. To be able to do this we must assign the reference to a variable
2016
+ * that is declared in the scope of the `describe()` block. Since we would, most likely, want
2017
+ * the variable to have the same name of the reference we have a problem, since the parameter
2018
+ * to the `inject()` function would hide the outer variable.
2019
+ *
2020
+ * To help with this, the injected parameters can, optionally, be enclosed with underscores.
2021
+ * These are ignored by the injector when the reference name is resolved.
2022
+ *
2023
+ * For example, the parameter `_myService_` would be resolved as the reference `myService`.
2024
+ * Since it is available in the function body as _myService_, we can then assign it to a variable
2025
+ * defined in an outer scope.
2026
+ *
2027
+ * ```
2028
+ * // Defined out reference variable outside
2029
+ * var myService;
2030
+ *
2031
+ * // Wrap the parameter in underscores
2032
+ * beforeEach( inject( function(_myService_){
2033
+ * myService = _myService_;
2034
+ * }));
2035
+ *
2036
+ * // Use myService in a series of tests.
2037
+ * it('makes use of myService', function() {
2038
+ * myService.doStuff();
2039
+ * });
2040
+ *
2041
+ * ```
2042
+ *
2043
+ * See also {@link angular.mock.module angular.mock.module}
2044
+ *
2045
+ * ## Example
1781
2046
  * Example of what a typical jasmine tests looks like with the inject method.
1782
2047
  * <pre>
1783
2048
  *
@@ -1810,7 +2075,7 @@ window.jstestdriver && (function(window) {
1810
2075
  * inject(function(version) {
1811
2076
  * expect(version).toEqual('overridden');
1812
2077
  * });
1813
- * ));
2078
+ * });
1814
2079
  * });
1815
2080
  *
1816
2081
  * </pre>
@@ -1833,7 +2098,9 @@ window.jstestdriver && (function(window) {
1833
2098
  }
1834
2099
  for(var i = 0, ii = blockFns.length; i < ii; i++) {
1835
2100
  try {
2101
+ /* jshint -W040 *//* Jasmine explicitly provides a `this` object when calling functions */
1836
2102
  injector.invoke(blockFns[i] || angular.noop, this);
2103
+ /* jshint +W040 */
1837
2104
  } catch (e) {
1838
2105
  if(e.stack && errorForStack) e.stack += '\n' + errorForStack.stack;
1839
2106
  throw e;
@@ -1843,4 +2110,7 @@ window.jstestdriver && (function(window) {
1843
2110
  }
1844
2111
  }
1845
2112
  };
1846
- })(window);
2113
+ }
2114
+
2115
+
2116
+ })(window, window.angular);