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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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);