mongo_browser 0.1.3 → 0.2.0.rc2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (118) hide show
  1. data/.gitignore +3 -0
  2. data/.travis.yml +3 -3
  3. data/README.md +1 -25
  4. data/Rakefile +0 -1
  5. data/app/assets/images/background.png +0 -0
  6. data/app/assets/javascripts/app/controllers/alerts.js.coffee +12 -0
  7. data/app/assets/javascripts/app/controllers/breadcrumbs.js.coffee +25 -0
  8. data/app/assets/javascripts/app/controllers/collections.js.coffee +40 -0
  9. data/app/assets/javascripts/app/controllers/databases.js.coffee +39 -0
  10. data/app/assets/javascripts/app/controllers/documents.js.coffee +49 -0
  11. data/app/assets/javascripts/app/controllers/main.js.coffee +10 -0
  12. data/app/assets/javascripts/app/controllers/server_info.js.coffee +14 -0
  13. data/app/assets/javascripts/app/controllers.js.coffee +2 -0
  14. data/app/assets/javascripts/app/directives.js.coffee +20 -0
  15. data/app/assets/javascripts/app/filters.js.coffee +48 -0
  16. data/app/assets/javascripts/app/modules/dialogs.js.coffee +29 -0
  17. data/app/assets/javascripts/app/modules/pager.js.coffee +87 -0
  18. data/app/assets/javascripts/app/modules/table_filter.js.coffee +27 -0
  19. data/app/assets/javascripts/app/resources.js.coffee +22 -0
  20. data/app/assets/javascripts/app/services.js.coffee +36 -0
  21. data/app/assets/javascripts/app.js.coffee +8 -0
  22. data/app/assets/javascripts/application.js.coffee +35 -6
  23. data/app/assets/javascripts/templates/.gitkeep +0 -0
  24. data/app/assets/javascripts/templates.js.coffee +1 -0
  25. data/app/assets/javascripts/vendor.js.coffee +5 -0
  26. data/app/assets/stylesheets/application.css.scss +46 -3
  27. data/app/assets/templates/collections.html +53 -0
  28. data/app/assets/templates/databases.html +32 -0
  29. data/app/assets/templates/documents.html +45 -0
  30. data/app/assets/templates/pager.html +13 -0
  31. data/app/{views/server_info.erb → assets/templates/server_info.html} +5 -7
  32. data/app/assets/templates/table_filter.html +10 -0
  33. data/bin/mongo_browser +8 -45
  34. data/config-e2e.ru +20 -0
  35. data/grunt.js +36 -0
  36. data/lib/mongo_browser/application.rb +143 -64
  37. data/lib/mongo_browser/middleware/sprockets_base.rb +11 -0
  38. data/lib/mongo_browser/middleware/sprockets_sinatra.rb +3 -7
  39. data/lib/mongo_browser/middleware/sprockets_specs.rb +18 -0
  40. data/lib/mongo_browser/models/collection.rb +67 -0
  41. data/lib/mongo_browser/models/database.rb +52 -0
  42. data/lib/mongo_browser/models/document.rb +17 -0
  43. data/lib/mongo_browser/models/pager.rb +30 -0
  44. data/lib/mongo_browser/models/server.rb +51 -0
  45. data/lib/mongo_browser/version.rb +1 -1
  46. data/lib/mongo_browser.rb +10 -5
  47. data/mongo_browser.gemspec +4 -11
  48. data/public/index.html +47 -0
  49. data/script/ci_all +21 -0
  50. data/script/ci_e2e +11 -0
  51. data/script/ci_javascripts +4 -0
  52. data/script/ci_rspec +3 -0
  53. data/spec/features/collections_list_spec.rb +6 -49
  54. data/spec/features/documents_list_spec.rb +15 -14
  55. data/spec/features/server_info_spec.rb +3 -3
  56. data/spec/javascripts/app/controllers/alerts_spec.js.coffee +36 -0
  57. data/spec/javascripts/app/controllers/breadcrumbs_spec.js.coffee +28 -0
  58. data/spec/javascripts/app/controllers/collections_spec.js.coffee +78 -0
  59. data/spec/javascripts/app/controllers/databases_spec.js.coffee +55 -0
  60. data/spec/javascripts/app/controllers/documents_spec.js.coffee +62 -0
  61. data/spec/javascripts/app/controllers/main_spec.js.coffee +20 -0
  62. data/spec/javascripts/app/controllers/server_info_spec.js.coffee +21 -0
  63. data/spec/javascripts/app/directives_spec.js.coffee +58 -0
  64. data/spec/javascripts/app/filters_spec.js.coffee +99 -0
  65. data/spec/javascripts/app/modules/dialogs_spec.js.coffee +51 -0
  66. data/spec/javascripts/app/modules/pager_spec.js.coffee +104 -0
  67. data/spec/javascripts/app/modules/table_filter_spec.js.coffee +76 -0
  68. data/spec/javascripts/app/services_spec.js.coffee +83 -0
  69. data/spec/javascripts/config/testacular-e2e.conf.js +19 -0
  70. data/spec/javascripts/config/testacular.conf.js +43 -0
  71. data/spec/javascripts/e2e/collections_scenario.js.coffee +49 -0
  72. data/spec/javascripts/e2e/databases_scenario.js.coffee +74 -0
  73. data/spec/javascripts/e2e/documents_scenario.js.coffee +18 -0
  74. data/spec/javascripts/e2e/server_info_scenario.js.coffee +12 -0
  75. data/spec/javascripts/helpers/matchers.js.coffee +5 -0
  76. data/spec/javascripts/helpers/mocks.js.coffee +7 -0
  77. data/spec/javascripts/helpers_e2e/app_element.js.coffee +6 -0
  78. data/spec/javascripts/lib/angular-mocks.js +1740 -0
  79. data/spec/javascripts/lib/angular-scenario.js +26147 -0
  80. data/spec/javascripts/lib/jasmine-html.js +681 -0
  81. data/spec/javascripts/lib/jasmine.css +82 -0
  82. data/spec/javascripts/lib/jasmine.js +2600 -0
  83. data/spec/javascripts/runner.html +54 -0
  84. data/spec/javascripts/runner_e2e.html +10 -0
  85. data/spec/javascripts/spec.js.coffee +2 -0
  86. data/spec/javascripts/spec_e2e.js.coffee +2 -0
  87. data/spec/lib/models/collection_spec.rb +80 -0
  88. data/spec/lib/models/database_spec.rb +75 -0
  89. data/spec/lib/models/document_spec.rb +17 -0
  90. data/spec/lib/models/pager_spec.rb +64 -0
  91. data/spec/lib/models/server_spec.rb +76 -0
  92. data/spec/lib/mongo_browser_spec.rb +1 -1
  93. data/spec/spec_helper.rb +2 -19
  94. data/spec/support/feature_example_group.rb +8 -3
  95. data/spec/support/fixtures/databases.json +8 -0
  96. data/spec/support/fixtures.rb +20 -3
  97. data/spec/support/matchers/have_flash_message.rb +1 -1
  98. data/spec/support/mongod.rb +37 -21
  99. data/spec/support/mongodb.conf +47 -0
  100. data/vendor/assets/javascripts/angular/angular-bootstrap.js +166 -0
  101. data/vendor/assets/javascripts/angular/angular-resource.js +435 -0
  102. data/vendor/assets/javascripts/angular/angular-sanitize.js +535 -0
  103. data/vendor/assets/javascripts/angular/angular.js +14531 -0
  104. data/vendor/assets/javascripts/underscore.js +1200 -0
  105. metadata +136 -148
  106. data/app/assets/javascripts/app/table_filter.js.coffee +0 -50
  107. data/app/assets/javascripts/ujs.js.coffee +0 -23
  108. data/app/views/collections/index.erb +0 -59
  109. data/app/views/databases/index.erb +0 -29
  110. data/app/views/documents/index.erb +0 -61
  111. data/app/views/layout/_flash_messages.erb +0 -10
  112. data/app/views/layout/_navbar.erb +0 -22
  113. data/app/views/layout.erb +0 -20
  114. data/app/views/shared/_filter.erb +0 -14
  115. data/features/mongo_browser.feature +0 -18
  116. data/features/step_definitions/mongo_browser_steps.rb +0 -1
  117. data/features/support/env.rb +0 -18
  118. data/spec/features/databases_list_spec.rb +0 -65
@@ -0,0 +1,1740 @@
1
+ /**
2
+ * @license AngularJS v1.0.3
3
+ * (c) 2010-2012 Google, Inc. http://angularjs.org
4
+ * License: MIT
5
+ *
6
+ * TODO(vojta): wrap whole file into closure during build
7
+ */
8
+
9
+ /**
10
+ * @ngdoc overview
11
+ * @name angular.mock
12
+ * @description
13
+ *
14
+ * Namespace from 'angular-mocks.js' which contains testing related code.
15
+ */
16
+ angular.mock = {};
17
+
18
+ /**
19
+ * ! This is a private undocumented service !
20
+ *
21
+ * @name ngMock.$browser
22
+ *
23
+ * @description
24
+ * This service is a mock implementation of {@link ng.$browser}. It provides fake
25
+ * implementation for commonly used browser apis that are hard to test, e.g. setTimeout, xhr,
26
+ * cookies, etc...
27
+ *
28
+ * The api of this service is the same as that of the real {@link ng.$browser $browser}, except
29
+ * that there are several helper methods available which can be used in tests.
30
+ */
31
+ angular.mock.$BrowserProvider = function() {
32
+ this.$get = function(){
33
+ return new angular.mock.$Browser();
34
+ };
35
+ };
36
+
37
+ angular.mock.$Browser = function() {
38
+ var self = this;
39
+
40
+ this.isMock = true;
41
+ self.$$url = "http://server/";
42
+ self.$$lastUrl = self.$$url; // used by url polling fn
43
+ self.pollFns = [];
44
+
45
+ // TODO(vojta): remove this temporary api
46
+ self.$$completeOutstandingRequest = angular.noop;
47
+ self.$$incOutstandingRequestCount = angular.noop;
48
+
49
+
50
+ // register url polling fn
51
+
52
+ self.onUrlChange = function(listener) {
53
+ self.pollFns.push(
54
+ function() {
55
+ if (self.$$lastUrl != self.$$url) {
56
+ self.$$lastUrl = self.$$url;
57
+ listener(self.$$url);
58
+ }
59
+ }
60
+ );
61
+
62
+ return listener;
63
+ };
64
+
65
+ self.cookieHash = {};
66
+ self.lastCookieHash = {};
67
+ self.deferredFns = [];
68
+ self.deferredNextId = 0;
69
+
70
+ self.defer = function(fn, delay) {
71
+ delay = delay || 0;
72
+ self.deferredFns.push({time:(self.defer.now + delay), fn:fn, id: self.deferredNextId});
73
+ self.deferredFns.sort(function(a,b){ return a.time - b.time;});
74
+ return self.deferredNextId++;
75
+ };
76
+
77
+
78
+ self.defer.now = 0;
79
+
80
+
81
+ self.defer.cancel = function(deferId) {
82
+ var fnIndex;
83
+
84
+ angular.forEach(self.deferredFns, function(fn, index) {
85
+ if (fn.id === deferId) fnIndex = index;
86
+ });
87
+
88
+ if (fnIndex !== undefined) {
89
+ self.deferredFns.splice(fnIndex, 1);
90
+ return true;
91
+ }
92
+
93
+ return false;
94
+ };
95
+
96
+
97
+ /**
98
+ * @name ngMock.$browser#defer.flush
99
+ * @methodOf ngMock.$browser
100
+ *
101
+ * @description
102
+ * Flushes all pending requests and executes the defer callbacks.
103
+ *
104
+ * @param {number=} number of milliseconds to flush. See {@link #defer.now}
105
+ */
106
+ self.defer.flush = function(delay) {
107
+ if (angular.isDefined(delay)) {
108
+ self.defer.now += delay;
109
+ } else {
110
+ if (self.deferredFns.length) {
111
+ self.defer.now = self.deferredFns[self.deferredFns.length-1].time;
112
+ } else {
113
+ throw Error('No deferred tasks to be flushed');
114
+ }
115
+ }
116
+
117
+ while (self.deferredFns.length && self.deferredFns[0].time <= self.defer.now) {
118
+ self.deferredFns.shift().fn();
119
+ }
120
+ };
121
+ /**
122
+ * @name ngMock.$browser#defer.now
123
+ * @propertyOf ngMock.$browser
124
+ *
125
+ * @description
126
+ * Current milliseconds mock time.
127
+ */
128
+
129
+ self.$$baseHref = '';
130
+ self.baseHref = function() {
131
+ return this.$$baseHref;
132
+ };
133
+ };
134
+ angular.mock.$Browser.prototype = {
135
+
136
+ /**
137
+ * @name ngMock.$browser#poll
138
+ * @methodOf ngMock.$browser
139
+ *
140
+ * @description
141
+ * run all fns in pollFns
142
+ */
143
+ poll: function poll() {
144
+ angular.forEach(this.pollFns, function(pollFn){
145
+ pollFn();
146
+ });
147
+ },
148
+
149
+ addPollFn: function(pollFn) {
150
+ this.pollFns.push(pollFn);
151
+ return pollFn;
152
+ },
153
+
154
+ url: function(url, replace) {
155
+ if (url) {
156
+ this.$$url = url;
157
+ return this;
158
+ }
159
+
160
+ return this.$$url;
161
+ },
162
+
163
+ cookies: function(name, value) {
164
+ if (name) {
165
+ if (value == undefined) {
166
+ delete this.cookieHash[name];
167
+ } else {
168
+ if (angular.isString(value) && //strings only
169
+ value.length <= 4096) { //strict cookie storage limits
170
+ this.cookieHash[name] = value;
171
+ }
172
+ }
173
+ } else {
174
+ if (!angular.equals(this.cookieHash, this.lastCookieHash)) {
175
+ this.lastCookieHash = angular.copy(this.cookieHash);
176
+ this.cookieHash = angular.copy(this.cookieHash);
177
+ }
178
+ return this.cookieHash;
179
+ }
180
+ },
181
+
182
+ notifyWhenNoOutstandingRequests: function(fn) {
183
+ fn();
184
+ }
185
+ };
186
+
187
+
188
+ /**
189
+ * @ngdoc object
190
+ * @name ngMock.$exceptionHandlerProvider
191
+ *
192
+ * @description
193
+ * Configures the mock implementation of {@link ng.$exceptionHandler} to rethrow or to log errors passed
194
+ * into the `$exceptionHandler`.
195
+ */
196
+
197
+ /**
198
+ * @ngdoc object
199
+ * @name ngMock.$exceptionHandler
200
+ *
201
+ * @description
202
+ * Mock implementation of {@link ng.$exceptionHandler} that rethrows or logs errors passed
203
+ * into it. See {@link ngMock.$exceptionHandlerProvider $exceptionHandlerProvider} for configuration
204
+ * information.
205
+ */
206
+
207
+ angular.mock.$ExceptionHandlerProvider = function() {
208
+ var handler;
209
+
210
+ /**
211
+ * @ngdoc method
212
+ * @name ngMock.$exceptionHandlerProvider#mode
213
+ * @methodOf ngMock.$exceptionHandlerProvider
214
+ *
215
+ * @description
216
+ * Sets the logging mode.
217
+ *
218
+ * @param {string} mode Mode of operation, defaults to `rethrow`.
219
+ *
220
+ * - `rethrow`: If any errors are are passed into the handler in tests, it typically
221
+ * means that there is a bug in the application or test, so this mock will
222
+ * make these tests fail.
223
+ * - `log`: Sometimes it is desirable to test that an error is throw, for this case the `log` mode stores the
224
+ * error and allows later assertion of it.
225
+ * See {@link ngMock.$log#assertEmpty assertEmpty()} and
226
+ * {@link ngMock.$log#reset reset()}
227
+ */
228
+ this.mode = function(mode) {
229
+ switch(mode) {
230
+ case 'rethrow':
231
+ handler = function(e) {
232
+ throw e;
233
+ };
234
+ break;
235
+ case 'log':
236
+ var errors = [];
237
+
238
+ handler = function(e) {
239
+ if (arguments.length == 1) {
240
+ errors.push(e);
241
+ } else {
242
+ errors.push([].slice.call(arguments, 0));
243
+ }
244
+ };
245
+
246
+ handler.errors = errors;
247
+ break;
248
+ default:
249
+ throw Error("Unknown mode '" + mode + "', only 'log'/'rethrow' modes are allowed!");
250
+ }
251
+ };
252
+
253
+ this.$get = function() {
254
+ return handler;
255
+ };
256
+
257
+ this.mode('rethrow');
258
+ };
259
+
260
+
261
+ /**
262
+ * @ngdoc service
263
+ * @name ngMock.$log
264
+ *
265
+ * @description
266
+ * Mock implementation of {@link ng.$log} that gathers all logged messages in arrays
267
+ * (one array per logging level). These arrays are exposed as `logs` property of each of the
268
+ * level-specific log function, e.g. for level `error` the array is exposed as `$log.error.logs`.
269
+ *
270
+ */
271
+ angular.mock.$LogProvider = function() {
272
+
273
+ function concat(array1, array2, index) {
274
+ return array1.concat(Array.prototype.slice.call(array2, index));
275
+ }
276
+
277
+
278
+ this.$get = function () {
279
+ var $log = {
280
+ log: function() { $log.log.logs.push(concat([], arguments, 0)); },
281
+ warn: function() { $log.warn.logs.push(concat([], arguments, 0)); },
282
+ info: function() { $log.info.logs.push(concat([], arguments, 0)); },
283
+ error: function() { $log.error.logs.push(concat([], arguments, 0)); }
284
+ };
285
+
286
+ /**
287
+ * @ngdoc method
288
+ * @name ngMock.$log#reset
289
+ * @methodOf ngMock.$log
290
+ *
291
+ * @description
292
+ * Reset all of the logging arrays to empty.
293
+ */
294
+ $log.reset = function () {
295
+ /**
296
+ * @ngdoc property
297
+ * @name ngMock.$log#log.logs
298
+ * @propertyOf ngMock.$log
299
+ *
300
+ * @description
301
+ * Array of logged messages.
302
+ */
303
+ $log.log.logs = [];
304
+ /**
305
+ * @ngdoc property
306
+ * @name ngMock.$log#warn.logs
307
+ * @propertyOf ngMock.$log
308
+ *
309
+ * @description
310
+ * Array of logged messages.
311
+ */
312
+ $log.warn.logs = [];
313
+ /**
314
+ * @ngdoc property
315
+ * @name ngMock.$log#info.logs
316
+ * @propertyOf ngMock.$log
317
+ *
318
+ * @description
319
+ * Array of logged messages.
320
+ */
321
+ $log.info.logs = [];
322
+ /**
323
+ * @ngdoc property
324
+ * @name ngMock.$log#error.logs
325
+ * @propertyOf ngMock.$log
326
+ *
327
+ * @description
328
+ * Array of logged messages.
329
+ */
330
+ $log.error.logs = [];
331
+ };
332
+
333
+ /**
334
+ * @ngdoc method
335
+ * @name ngMock.$log#assertEmpty
336
+ * @methodOf ngMock.$log
337
+ *
338
+ * @description
339
+ * Assert that the all of the logging methods have no logged messages. If messages present, an exception is thrown.
340
+ */
341
+ $log.assertEmpty = function() {
342
+ var errors = [];
343
+ angular.forEach(['error', 'warn', 'info', 'log'], function(logLevel) {
344
+ angular.forEach($log[logLevel].logs, function(log) {
345
+ angular.forEach(log, function (logItem) {
346
+ errors.push('MOCK $log (' + logLevel + '): ' + String(logItem) + '\n' + (logItem.stack || ''));
347
+ });
348
+ });
349
+ });
350
+ if (errors.length) {
351
+ errors.unshift("Expected $log to be empty! Either a message was logged unexpectedly, or an expected " +
352
+ "log message was not checked and removed:");
353
+ errors.push('');
354
+ throw new Error(errors.join('\n---------\n'));
355
+ }
356
+ };
357
+
358
+ $log.reset();
359
+ return $log;
360
+ };
361
+ };
362
+
363
+
364
+ (function() {
365
+ var R_ISO8061_STR = /^(\d{4})-?(\d\d)-?(\d\d)(?:T(\d\d)(?:\:?(\d\d)(?:\:?(\d\d)(?:\.(\d{3}))?)?)?(Z|([+-])(\d\d):?(\d\d)))?$/;
366
+
367
+ function jsonStringToDate(string){
368
+ var match;
369
+ if (match = string.match(R_ISO8061_STR)) {
370
+ var date = new Date(0),
371
+ tzHour = 0,
372
+ tzMin = 0;
373
+ if (match[9]) {
374
+ tzHour = int(match[9] + match[10]);
375
+ tzMin = int(match[9] + match[11]);
376
+ }
377
+ date.setUTCFullYear(int(match[1]), int(match[2]) - 1, int(match[3]));
378
+ date.setUTCHours(int(match[4]||0) - tzHour, int(match[5]||0) - tzMin, int(match[6]||0), int(match[7]||0));
379
+ return date;
380
+ }
381
+ return string;
382
+ }
383
+
384
+ function int(str) {
385
+ return parseInt(str, 10);
386
+ }
387
+
388
+ function padNumber(num, digits, trim) {
389
+ var neg = '';
390
+ if (num < 0) {
391
+ neg = '-';
392
+ num = -num;
393
+ }
394
+ num = '' + num;
395
+ while(num.length < digits) num = '0' + num;
396
+ if (trim)
397
+ num = num.substr(num.length - digits);
398
+ return neg + num;
399
+ }
400
+
401
+
402
+ /**
403
+ * @ngdoc object
404
+ * @name angular.mock.TzDate
405
+ * @description
406
+ *
407
+ * *NOTE*: this is not an injectable instance, just a globally available mock class of `Date`.
408
+ *
409
+ * Mock of the Date type which has its timezone specified via constroctor arg.
410
+ *
411
+ * The main purpose is to create Date-like instances with timezone fixed to the specified timezone
412
+ * offset, so that we can test code that depends on local timezone settings without dependency on
413
+ * the time zone settings of the machine where the code is running.
414
+ *
415
+ * @param {number} offset Offset of the *desired* timezone in hours (fractions will be honored)
416
+ * @param {(number|string)} timestamp Timestamp representing the desired time in *UTC*
417
+ *
418
+ * @example
419
+ * !!!! WARNING !!!!!
420
+ * This is not a complete Date object so only methods that were implemented can be called safely.
421
+ * To make matters worse, TzDate instances inherit stuff from Date via a prototype.
422
+ *
423
+ * We do our best to intercept calls to "unimplemented" methods, but since the list of methods is
424
+ * incomplete we might be missing some non-standard methods. This can result in errors like:
425
+ * "Date.prototype.foo called on incompatible Object".
426
+ *
427
+ * <pre>
428
+ * var newYearInBratislava = new TzDate(-1, '2009-12-31T23:00:00Z');
429
+ * newYearInBratislava.getTimezoneOffset() => -60;
430
+ * newYearInBratislava.getFullYear() => 2010;
431
+ * newYearInBratislava.getMonth() => 0;
432
+ * newYearInBratislava.getDate() => 1;
433
+ * newYearInBratislava.getHours() => 0;
434
+ * newYearInBratislava.getMinutes() => 0;
435
+ * </pre>
436
+ *
437
+ */
438
+ angular.mock.TzDate = function (offset, timestamp) {
439
+ var self = new Date(0);
440
+ if (angular.isString(timestamp)) {
441
+ var tsStr = timestamp;
442
+
443
+ self.origDate = jsonStringToDate(timestamp);
444
+
445
+ timestamp = self.origDate.getTime();
446
+ if (isNaN(timestamp))
447
+ throw {
448
+ name: "Illegal Argument",
449
+ message: "Arg '" + tsStr + "' passed into TzDate constructor is not a valid date string"
450
+ };
451
+ } else {
452
+ self.origDate = new Date(timestamp);
453
+ }
454
+
455
+ var localOffset = new Date(timestamp).getTimezoneOffset();
456
+ self.offsetDiff = localOffset*60*1000 - offset*1000*60*60;
457
+ self.date = new Date(timestamp + self.offsetDiff);
458
+
459
+ self.getTime = function() {
460
+ return self.date.getTime() - self.offsetDiff;
461
+ };
462
+
463
+ self.toLocaleDateString = function() {
464
+ return self.date.toLocaleDateString();
465
+ };
466
+
467
+ self.getFullYear = function() {
468
+ return self.date.getFullYear();
469
+ };
470
+
471
+ self.getMonth = function() {
472
+ return self.date.getMonth();
473
+ };
474
+
475
+ self.getDate = function() {
476
+ return self.date.getDate();
477
+ };
478
+
479
+ self.getHours = function() {
480
+ return self.date.getHours();
481
+ };
482
+
483
+ self.getMinutes = function() {
484
+ return self.date.getMinutes();
485
+ };
486
+
487
+ self.getSeconds = function() {
488
+ return self.date.getSeconds();
489
+ };
490
+
491
+ self.getTimezoneOffset = function() {
492
+ return offset * 60;
493
+ };
494
+
495
+ self.getUTCFullYear = function() {
496
+ return self.origDate.getUTCFullYear();
497
+ };
498
+
499
+ self.getUTCMonth = function() {
500
+ return self.origDate.getUTCMonth();
501
+ };
502
+
503
+ self.getUTCDate = function() {
504
+ return self.origDate.getUTCDate();
505
+ };
506
+
507
+ self.getUTCHours = function() {
508
+ return self.origDate.getUTCHours();
509
+ };
510
+
511
+ self.getUTCMinutes = function() {
512
+ return self.origDate.getUTCMinutes();
513
+ };
514
+
515
+ self.getUTCSeconds = function() {
516
+ return self.origDate.getUTCSeconds();
517
+ };
518
+
519
+ self.getUTCMilliseconds = function() {
520
+ return self.origDate.getUTCMilliseconds();
521
+ };
522
+
523
+ self.getDay = function() {
524
+ return self.date.getDay();
525
+ };
526
+
527
+ // provide this method only on browsers that already have it
528
+ if (self.toISOString) {
529
+ self.toISOString = function() {
530
+ return padNumber(self.origDate.getUTCFullYear(), 4) + '-' +
531
+ padNumber(self.origDate.getUTCMonth() + 1, 2) + '-' +
532
+ padNumber(self.origDate.getUTCDate(), 2) + 'T' +
533
+ padNumber(self.origDate.getUTCHours(), 2) + ':' +
534
+ padNumber(self.origDate.getUTCMinutes(), 2) + ':' +
535
+ padNumber(self.origDate.getUTCSeconds(), 2) + '.' +
536
+ padNumber(self.origDate.getUTCMilliseconds(), 3) + 'Z'
537
+ }
538
+ }
539
+
540
+ //hide all methods not implemented in this mock that the Date prototype exposes
541
+ var unimplementedMethods = ['getMilliseconds', 'getUTCDay',
542
+ 'getYear', 'setDate', 'setFullYear', 'setHours', 'setMilliseconds',
543
+ 'setMinutes', 'setMonth', 'setSeconds', 'setTime', 'setUTCDate', 'setUTCFullYear',
544
+ 'setUTCHours', 'setUTCMilliseconds', 'setUTCMinutes', 'setUTCMonth', 'setUTCSeconds',
545
+ 'setYear', 'toDateString', 'toGMTString', 'toJSON', 'toLocaleFormat', 'toLocaleString',
546
+ 'toLocaleTimeString', 'toSource', 'toString', 'toTimeString', 'toUTCString', 'valueOf'];
547
+
548
+ angular.forEach(unimplementedMethods, function(methodName) {
549
+ self[methodName] = function() {
550
+ throw Error("Method '" + methodName + "' is not implemented in the TzDate mock");
551
+ };
552
+ });
553
+
554
+ return self;
555
+ };
556
+
557
+ //make "tzDateInstance instanceof Date" return true
558
+ angular.mock.TzDate.prototype = Date.prototype;
559
+ })();
560
+
561
+
562
+ /**
563
+ * @ngdoc function
564
+ * @name angular.mock.debug
565
+ * @description
566
+ *
567
+ * *NOTE*: this is not an injectable instance, just a globally available function.
568
+ *
569
+ * Method for serializing common angular objects (scope, elements, etc..) into strings, useful for debugging.
570
+ *
571
+ * This method is also available on window, where it can be used to display objects on debug console.
572
+ *
573
+ * @param {*} object - any object to turn into string.
574
+ * @return {string} a serialized string of the argument
575
+ */
576
+ angular.mock.dump = function(object) {
577
+ return serialize(object);
578
+
579
+ function serialize(object) {
580
+ var out;
581
+
582
+ if (angular.isElement(object)) {
583
+ object = angular.element(object);
584
+ out = angular.element('<div></div>');
585
+ angular.forEach(object, function(element) {
586
+ out.append(angular.element(element).clone());
587
+ });
588
+ out = out.html();
589
+ } else if (angular.isArray(object)) {
590
+ out = [];
591
+ angular.forEach(object, function(o) {
592
+ out.push(serialize(o));
593
+ });
594
+ out = '[ ' + out.join(', ') + ' ]';
595
+ } else if (angular.isObject(object)) {
596
+ if (angular.isFunction(object.$eval) && angular.isFunction(object.$apply)) {
597
+ out = serializeScope(object);
598
+ } else if (object instanceof Error) {
599
+ out = object.stack || ('' + object.name + ': ' + object.message);
600
+ } else {
601
+ out = angular.toJson(object, true);
602
+ }
603
+ } else {
604
+ out = String(object);
605
+ }
606
+
607
+ return out;
608
+ }
609
+
610
+ function serializeScope(scope, offset) {
611
+ offset = offset || ' ';
612
+ var log = [offset + 'Scope(' + scope.$id + '): {'];
613
+ for ( var key in scope ) {
614
+ if (scope.hasOwnProperty(key) && !key.match(/^(\$|this)/)) {
615
+ log.push(' ' + key + ': ' + angular.toJson(scope[key]));
616
+ }
617
+ }
618
+ var child = scope.$$childHead;
619
+ while(child) {
620
+ log.push(serializeScope(child, offset + ' '));
621
+ child = child.$$nextSibling;
622
+ }
623
+ log.push('}');
624
+ return log.join('\n' + offset);
625
+ }
626
+ };
627
+
628
+ /**
629
+ * @ngdoc object
630
+ * @name ngMock.$httpBackend
631
+ * @description
632
+ * Fake HTTP backend implementation suitable for unit testing application that use the
633
+ * {@link ng.$http $http service}.
634
+ *
635
+ * *Note*: For fake http backend implementation suitable for end-to-end testing or backend-less
636
+ * development please see {@link ngMockE2E.$httpBackend e2e $httpBackend mock}.
637
+ *
638
+ * During unit testing, we want our unit tests to run quickly and have no external dependencies so
639
+ * we don’t want to send {@link https://developer.mozilla.org/en/xmlhttprequest XHR} or
640
+ * {@link http://en.wikipedia.org/wiki/JSONP JSONP} requests to a real server. All we really need is
641
+ * to verify whether a certain request has been sent or not, or alternatively just let the
642
+ * application make requests, respond with pre-trained responses and assert that the end result is
643
+ * what we expect it to be.
644
+ *
645
+ * This mock implementation can be used to respond with static or dynamic responses via the
646
+ * `expect` and `when` apis and their shortcuts (`expectGET`, `whenPOST`, etc).
647
+ *
648
+ * When an Angular application needs some data from a server, it calls the $http service, which
649
+ * sends the request to a real server using $httpBackend service. With dependency injection, it is
650
+ * easy to inject $httpBackend mock (which has the same API as $httpBackend) and use it to verify
651
+ * the requests and respond with some testing data without sending a request to real server.
652
+ *
653
+ * There are two ways to specify what test data should be returned as http responses by the mock
654
+ * backend when the code under test makes http requests:
655
+ *
656
+ * - `$httpBackend.expect` - specifies a request expectation
657
+ * - `$httpBackend.when` - specifies a backend definition
658
+ *
659
+ *
660
+ * # Request Expectations vs Backend Definitions
661
+ *
662
+ * Request expectations provide a way to make assertions about requests made by the application and
663
+ * to define responses for those requests. The test will fail if the expected requests are not made
664
+ * or they are made in the wrong order.
665
+ *
666
+ * Backend definitions allow you to define a fake backend for your application which doesn't assert
667
+ * if a particular request was made or not, it just returns a trained response if a request is made.
668
+ * The test will pass whether or not the request gets made during testing.
669
+ *
670
+ *
671
+ * <table class="table">
672
+ * <tr><th width="220px"></th><th>Request expectations</th><th>Backend definitions</th></tr>
673
+ * <tr>
674
+ * <th>Syntax</th>
675
+ * <td>.expect(...).respond(...)</td>
676
+ * <td>.when(...).respond(...)</td>
677
+ * </tr>
678
+ * <tr>
679
+ * <th>Typical usage</th>
680
+ * <td>strict unit tests</td>
681
+ * <td>loose (black-box) unit testing</td>
682
+ * </tr>
683
+ * <tr>
684
+ * <th>Fulfills multiple requests</th>
685
+ * <td>NO</td>
686
+ * <td>YES</td>
687
+ * </tr>
688
+ * <tr>
689
+ * <th>Order of requests matters</th>
690
+ * <td>YES</td>
691
+ * <td>NO</td>
692
+ * </tr>
693
+ * <tr>
694
+ * <th>Request required</th>
695
+ * <td>YES</td>
696
+ * <td>NO</td>
697
+ * </tr>
698
+ * <tr>
699
+ * <th>Response required</th>
700
+ * <td>optional (see below)</td>
701
+ * <td>YES</td>
702
+ * </tr>
703
+ * </table>
704
+ *
705
+ * In cases where both backend definitions and request expectations are specified during unit
706
+ * testing, the request expectations are evaluated first.
707
+ *
708
+ * If a request expectation has no response specified, the algorithm will search your backend
709
+ * definitions for an appropriate response.
710
+ *
711
+ * If a request didn't match any expectation or if the expectation doesn't have the response
712
+ * defined, the backend definitions are evaluated in sequential order to see if any of them match
713
+ * the request. The response from the first matched definition is returned.
714
+ *
715
+ *
716
+ * # Flushing HTTP requests
717
+ *
718
+ * The $httpBackend used in production, always responds to requests with responses asynchronously.
719
+ * If we preserved this behavior in unit testing, we'd have to create async unit tests, which are
720
+ * hard to write, follow and maintain. At the same time the testing mock, can't respond
721
+ * synchronously because that would change the execution of the code under test. For this reason the
722
+ * mock $httpBackend has a `flush()` method, which allows the test to explicitly flush pending
723
+ * requests and thus preserving the async api of the backend, while allowing the test to execute
724
+ * synchronously.
725
+ *
726
+ *
727
+ * # Unit testing with mock $httpBackend
728
+ *
729
+ * <pre>
730
+ // controller
731
+ function MyController($scope, $http) {
732
+ $http.get('/auth.py').success(function(data) {
733
+ $scope.user = data;
734
+ });
735
+
736
+ this.saveMessage = function(message) {
737
+ $scope.status = 'Saving...';
738
+ $http.post('/add-msg.py', message).success(function(response) {
739
+ $scope.status = '';
740
+ }).error(function() {
741
+ $scope.status = 'ERROR!';
742
+ });
743
+ };
744
+ }
745
+
746
+ // testing controller
747
+ var $http;
748
+
749
+ beforeEach(inject(function($injector) {
750
+ $httpBackend = $injector.get('$httpBackend');
751
+
752
+ // backend definition common for all tests
753
+ $httpBackend.when('GET', '/auth.py').respond({userId: 'userX'}, {'A-Token': 'xxx'});
754
+ }));
755
+
756
+
757
+ afterEach(function() {
758
+ $httpBackend.verifyNoOutstandingExpectation();
759
+ $httpBackend.verifyNoOutstandingRequest();
760
+ });
761
+
762
+
763
+ it('should fetch authentication token', function() {
764
+ $httpBackend.expectGET('/auth.py');
765
+ var controller = scope.$new(MyController);
766
+ $httpBackend.flush();
767
+ });
768
+
769
+
770
+ it('should send msg to server', function() {
771
+ // now you don’t care about the authentication, but
772
+ // the controller will still send the request and
773
+ // $httpBackend will respond without you having to
774
+ // specify the expectation and response for this request
775
+ $httpBackend.expectPOST('/add-msg.py', 'message content').respond(201, '');
776
+
777
+ var controller = scope.$new(MyController);
778
+ $httpBackend.flush();
779
+ controller.saveMessage('message content');
780
+ expect(controller.status).toBe('Saving...');
781
+ $httpBackend.flush();
782
+ expect(controller.status).toBe('');
783
+ });
784
+
785
+
786
+ it('should send auth header', function() {
787
+ $httpBackend.expectPOST('/add-msg.py', undefined, function(headers) {
788
+ // check if the header was send, if it wasn't the expectation won't
789
+ // match the request and the test will fail
790
+ return headers['Authorization'] == 'xxx';
791
+ }).respond(201, '');
792
+
793
+ var controller = scope.$new(MyController);
794
+ controller.saveMessage('whatever');
795
+ $httpBackend.flush();
796
+ });
797
+ </pre>
798
+ */
799
+ angular.mock.$HttpBackendProvider = function() {
800
+ this.$get = [createHttpBackendMock];
801
+ };
802
+
803
+ /**
804
+ * General factory function for $httpBackend mock.
805
+ * Returns instance for unit testing (when no arguments specified):
806
+ * - passing through is disabled
807
+ * - auto flushing is disabled
808
+ *
809
+ * Returns instance for e2e testing (when `$delegate` and `$browser` specified):
810
+ * - passing through (delegating request to real backend) is enabled
811
+ * - auto flushing is enabled
812
+ *
813
+ * @param {Object=} $delegate Real $httpBackend instance (allow passing through if specified)
814
+ * @param {Object=} $browser Auto-flushing enabled if specified
815
+ * @return {Object} Instance of $httpBackend mock
816
+ */
817
+ function createHttpBackendMock($delegate, $browser) {
818
+ var definitions = [],
819
+ expectations = [],
820
+ responses = [],
821
+ responsesPush = angular.bind(responses, responses.push);
822
+
823
+ function createResponse(status, data, headers) {
824
+ if (angular.isFunction(status)) return status;
825
+
826
+ return function() {
827
+ return angular.isNumber(status)
828
+ ? [status, data, headers]
829
+ : [200, status, data];
830
+ };
831
+ }
832
+
833
+ // TODO(vojta): change params to: method, url, data, headers, callback
834
+ function $httpBackend(method, url, data, callback, headers) {
835
+ var xhr = new MockXhr(),
836
+ expectation = expectations[0],
837
+ wasExpected = false;
838
+
839
+ function prettyPrint(data) {
840
+ return (angular.isString(data) || angular.isFunction(data) || data instanceof RegExp)
841
+ ? data
842
+ : angular.toJson(data);
843
+ }
844
+
845
+ if (expectation && expectation.match(method, url)) {
846
+ if (!expectation.matchData(data))
847
+ throw Error('Expected ' + expectation + ' with different data\n' +
848
+ 'EXPECTED: ' + prettyPrint(expectation.data) + '\nGOT: ' + data);
849
+
850
+ if (!expectation.matchHeaders(headers))
851
+ throw Error('Expected ' + expectation + ' with different headers\n' +
852
+ 'EXPECTED: ' + prettyPrint(expectation.headers) + '\nGOT: ' +
853
+ prettyPrint(headers));
854
+
855
+ expectations.shift();
856
+
857
+ if (expectation.response) {
858
+ responses.push(function() {
859
+ var response = expectation.response(method, url, data, headers);
860
+ xhr.$$respHeaders = response[2];
861
+ callback(response[0], response[1], xhr.getAllResponseHeaders());
862
+ });
863
+ return;
864
+ }
865
+ wasExpected = true;
866
+ }
867
+
868
+ var i = -1, definition;
869
+ while ((definition = definitions[++i])) {
870
+ if (definition.match(method, url, data, headers || {})) {
871
+ if (definition.response) {
872
+ // if $browser specified, we do auto flush all requests
873
+ ($browser ? $browser.defer : responsesPush)(function() {
874
+ var response = definition.response(method, url, data, headers);
875
+ xhr.$$respHeaders = response[2];
876
+ callback(response[0], response[1], xhr.getAllResponseHeaders());
877
+ });
878
+ } else if (definition.passThrough) {
879
+ $delegate(method, url, data, callback, headers);
880
+ } else throw Error('No response defined !');
881
+ return;
882
+ }
883
+ }
884
+ throw wasExpected ?
885
+ Error('No response defined !') :
886
+ Error('Unexpected request: ' + method + ' ' + url + '\n' +
887
+ (expectation ? 'Expected ' + expectation : 'No more request expected'));
888
+ }
889
+
890
+ /**
891
+ * @ngdoc method
892
+ * @name ngMock.$httpBackend#when
893
+ * @methodOf ngMock.$httpBackend
894
+ * @description
895
+ * Creates a new backend definition.
896
+ *
897
+ * @param {string} method HTTP method.
898
+ * @param {string|RegExp} url HTTP url.
899
+ * @param {(string|RegExp)=} data HTTP request body.
900
+ * @param {(Object|function(Object))=} headers HTTP headers or function that receives http header
901
+ * object and returns true if the headers match the current definition.
902
+ * @returns {requestHandler} Returns an object with `respond` method that control how a matched
903
+ * request is handled.
904
+ *
905
+ * - respond – `{function([status,] data[, headers])|function(function(method, url, data, headers)}`
906
+ * – The respond method takes a set of static data to be returned or a function that can return
907
+ * an array containing response status (number), response data (string) and response headers
908
+ * (Object).
909
+ */
910
+ $httpBackend.when = function(method, url, data, headers) {
911
+ var definition = new MockHttpExpectation(method, url, data, headers),
912
+ chain = {
913
+ respond: function(status, data, headers) {
914
+ definition.response = createResponse(status, data, headers);
915
+ }
916
+ };
917
+
918
+ if ($browser) {
919
+ chain.passThrough = function() {
920
+ definition.passThrough = true;
921
+ };
922
+ }
923
+
924
+ definitions.push(definition);
925
+ return chain;
926
+ };
927
+
928
+ /**
929
+ * @ngdoc method
930
+ * @name ngMock.$httpBackend#whenGET
931
+ * @methodOf ngMock.$httpBackend
932
+ * @description
933
+ * Creates a new backend definition for GET requests. For more info see `when()`.
934
+ *
935
+ * @param {string|RegExp} url HTTP url.
936
+ * @param {(Object|function(Object))=} headers HTTP headers.
937
+ * @returns {requestHandler} Returns an object with `respond` method that control how a matched
938
+ * request is handled.
939
+ */
940
+
941
+ /**
942
+ * @ngdoc method
943
+ * @name ngMock.$httpBackend#whenHEAD
944
+ * @methodOf ngMock.$httpBackend
945
+ * @description
946
+ * Creates a new backend definition for HEAD requests. For more info see `when()`.
947
+ *
948
+ * @param {string|RegExp} url HTTP url.
949
+ * @param {(Object|function(Object))=} headers HTTP headers.
950
+ * @returns {requestHandler} Returns an object with `respond` method that control how a matched
951
+ * request is handled.
952
+ */
953
+
954
+ /**
955
+ * @ngdoc method
956
+ * @name ngMock.$httpBackend#whenDELETE
957
+ * @methodOf ngMock.$httpBackend
958
+ * @description
959
+ * Creates a new backend definition for DELETE requests. For more info see `when()`.
960
+ *
961
+ * @param {string|RegExp} url HTTP url.
962
+ * @param {(Object|function(Object))=} headers HTTP headers.
963
+ * @returns {requestHandler} Returns an object with `respond` method that control how a matched
964
+ * request is handled.
965
+ */
966
+
967
+ /**
968
+ * @ngdoc method
969
+ * @name ngMock.$httpBackend#whenPOST
970
+ * @methodOf ngMock.$httpBackend
971
+ * @description
972
+ * Creates a new backend definition for POST requests. For more info see `when()`.
973
+ *
974
+ * @param {string|RegExp} url HTTP url.
975
+ * @param {(string|RegExp)=} data HTTP request body.
976
+ * @param {(Object|function(Object))=} headers HTTP headers.
977
+ * @returns {requestHandler} Returns an object with `respond` method that control how a matched
978
+ * request is handled.
979
+ */
980
+
981
+ /**
982
+ * @ngdoc method
983
+ * @name ngMock.$httpBackend#whenPUT
984
+ * @methodOf ngMock.$httpBackend
985
+ * @description
986
+ * Creates a new backend definition for PUT requests. For more info see `when()`.
987
+ *
988
+ * @param {string|RegExp} url HTTP url.
989
+ * @param {(string|RegExp)=} data HTTP request body.
990
+ * @param {(Object|function(Object))=} headers HTTP headers.
991
+ * @returns {requestHandler} Returns an object with `respond` method that control how a matched
992
+ * request is handled.
993
+ */
994
+
995
+ /**
996
+ * @ngdoc method
997
+ * @name ngMock.$httpBackend#whenJSONP
998
+ * @methodOf ngMock.$httpBackend
999
+ * @description
1000
+ * Creates a new backend definition for JSONP requests. For more info see `when()`.
1001
+ *
1002
+ * @param {string|RegExp} url HTTP url.
1003
+ * @returns {requestHandler} Returns an object with `respond` method that control how a matched
1004
+ * request is handled.
1005
+ */
1006
+ createShortMethods('when');
1007
+
1008
+
1009
+ /**
1010
+ * @ngdoc method
1011
+ * @name ngMock.$httpBackend#expect
1012
+ * @methodOf ngMock.$httpBackend
1013
+ * @description
1014
+ * Creates a new request expectation.
1015
+ *
1016
+ * @param {string} method HTTP method.
1017
+ * @param {string|RegExp} url HTTP url.
1018
+ * @param {(string|RegExp)=} data HTTP request body.
1019
+ * @param {(Object|function(Object))=} headers HTTP headers or function that receives http header
1020
+ * object and returns true if the headers match the current expectation.
1021
+ * @returns {requestHandler} Returns an object with `respond` method that control how a matched
1022
+ * request is handled.
1023
+ *
1024
+ * - respond – `{function([status,] data[, headers])|function(function(method, url, data, headers)}`
1025
+ * – The respond method takes a set of static data to be returned or a function that can return
1026
+ * an array containing response status (number), response data (string) and response headers
1027
+ * (Object).
1028
+ */
1029
+ $httpBackend.expect = function(method, url, data, headers) {
1030
+ var expectation = new MockHttpExpectation(method, url, data, headers);
1031
+ expectations.push(expectation);
1032
+ return {
1033
+ respond: function(status, data, headers) {
1034
+ expectation.response = createResponse(status, data, headers);
1035
+ }
1036
+ };
1037
+ };
1038
+
1039
+
1040
+ /**
1041
+ * @ngdoc method
1042
+ * @name ngMock.$httpBackend#expectGET
1043
+ * @methodOf ngMock.$httpBackend
1044
+ * @description
1045
+ * Creates a new request expectation for GET requests. For more info see `expect()`.
1046
+ *
1047
+ * @param {string|RegExp} url HTTP url.
1048
+ * @param {Object=} headers HTTP headers.
1049
+ * @returns {requestHandler} Returns an object with `respond` method that control how a matched
1050
+ * request is handled. See #expect for more info.
1051
+ */
1052
+
1053
+ /**
1054
+ * @ngdoc method
1055
+ * @name ngMock.$httpBackend#expectHEAD
1056
+ * @methodOf ngMock.$httpBackend
1057
+ * @description
1058
+ * Creates a new request expectation for HEAD requests. For more info see `expect()`.
1059
+ *
1060
+ * @param {string|RegExp} url HTTP url.
1061
+ * @param {Object=} headers HTTP headers.
1062
+ * @returns {requestHandler} Returns an object with `respond` method that control how a matched
1063
+ * request is handled.
1064
+ */
1065
+
1066
+ /**
1067
+ * @ngdoc method
1068
+ * @name ngMock.$httpBackend#expectDELETE
1069
+ * @methodOf ngMock.$httpBackend
1070
+ * @description
1071
+ * Creates a new request expectation for DELETE requests. For more info see `expect()`.
1072
+ *
1073
+ * @param {string|RegExp} url HTTP url.
1074
+ * @param {Object=} headers HTTP headers.
1075
+ * @returns {requestHandler} Returns an object with `respond` method that control how a matched
1076
+ * request is handled.
1077
+ */
1078
+
1079
+ /**
1080
+ * @ngdoc method
1081
+ * @name ngMock.$httpBackend#expectPOST
1082
+ * @methodOf ngMock.$httpBackend
1083
+ * @description
1084
+ * Creates a new request expectation for POST requests. For more info see `expect()`.
1085
+ *
1086
+ * @param {string|RegExp} url HTTP url.
1087
+ * @param {(string|RegExp)=} data HTTP request body.
1088
+ * @param {Object=} headers HTTP headers.
1089
+ * @returns {requestHandler} Returns an object with `respond` method that control how a matched
1090
+ * request is handled.
1091
+ */
1092
+
1093
+ /**
1094
+ * @ngdoc method
1095
+ * @name ngMock.$httpBackend#expectPUT
1096
+ * @methodOf ngMock.$httpBackend
1097
+ * @description
1098
+ * Creates a new request expectation for PUT requests. For more info see `expect()`.
1099
+ *
1100
+ * @param {string|RegExp} url HTTP url.
1101
+ * @param {(string|RegExp)=} data HTTP request body.
1102
+ * @param {Object=} headers HTTP headers.
1103
+ * @returns {requestHandler} Returns an object with `respond` method that control how a matched
1104
+ * request is handled.
1105
+ */
1106
+
1107
+ /**
1108
+ * @ngdoc method
1109
+ * @name ngMock.$httpBackend#expectPATCH
1110
+ * @methodOf ngMock.$httpBackend
1111
+ * @description
1112
+ * Creates a new request expectation for PATCH requests. For more info see `expect()`.
1113
+ *
1114
+ * @param {string|RegExp} url HTTP url.
1115
+ * @param {(string|RegExp)=} data HTTP request body.
1116
+ * @param {Object=} headers HTTP headers.
1117
+ * @returns {requestHandler} Returns an object with `respond` method that control how a matched
1118
+ * request is handled.
1119
+ */
1120
+
1121
+ /**
1122
+ * @ngdoc method
1123
+ * @name ngMock.$httpBackend#expectJSONP
1124
+ * @methodOf ngMock.$httpBackend
1125
+ * @description
1126
+ * Creates a new request expectation for JSONP requests. For more info see `expect()`.
1127
+ *
1128
+ * @param {string|RegExp} url HTTP url.
1129
+ * @returns {requestHandler} Returns an object with `respond` method that control how a matched
1130
+ * request is handled.
1131
+ */
1132
+ createShortMethods('expect');
1133
+
1134
+
1135
+ /**
1136
+ * @ngdoc method
1137
+ * @name ngMock.$httpBackend#flush
1138
+ * @methodOf ngMock.$httpBackend
1139
+ * @description
1140
+ * Flushes all pending requests using the trained responses.
1141
+ *
1142
+ * @param {number=} count Number of responses to flush (in the order they arrived). If undefined,
1143
+ * all pending requests will be flushed. If there are no pending requests when the flush method
1144
+ * is called an exception is thrown (as this typically a sign of programming error).
1145
+ */
1146
+ $httpBackend.flush = function(count) {
1147
+ if (!responses.length) throw Error('No pending request to flush !');
1148
+
1149
+ if (angular.isDefined(count)) {
1150
+ while (count--) {
1151
+ if (!responses.length) throw Error('No more pending request to flush !');
1152
+ responses.shift()();
1153
+ }
1154
+ } else {
1155
+ while (responses.length) {
1156
+ responses.shift()();
1157
+ }
1158
+ }
1159
+ $httpBackend.verifyNoOutstandingExpectation();
1160
+ };
1161
+
1162
+
1163
+ /**
1164
+ * @ngdoc method
1165
+ * @name ngMock.$httpBackend#verifyNoOutstandingExpectation
1166
+ * @methodOf ngMock.$httpBackend
1167
+ * @description
1168
+ * Verifies that all of the requests defined via the `expect` api were made. If any of the
1169
+ * requests were not made, verifyNoOutstandingExpectation throws an exception.
1170
+ *
1171
+ * Typically, you would call this method following each test case that asserts requests using an
1172
+ * "afterEach" clause.
1173
+ *
1174
+ * <pre>
1175
+ * afterEach($httpBackend.verifyExpectations);
1176
+ * </pre>
1177
+ */
1178
+ $httpBackend.verifyNoOutstandingExpectation = function() {
1179
+ if (expectations.length) {
1180
+ throw Error('Unsatisfied requests: ' + expectations.join(', '));
1181
+ }
1182
+ };
1183
+
1184
+
1185
+ /**
1186
+ * @ngdoc method
1187
+ * @name ngMock.$httpBackend#verifyNoOutstandingRequest
1188
+ * @methodOf ngMock.$httpBackend
1189
+ * @description
1190
+ * Verifies that there are no outstanding requests that need to be flushed.
1191
+ *
1192
+ * Typically, you would call this method following each test case that asserts requests using an
1193
+ * "afterEach" clause.
1194
+ *
1195
+ * <pre>
1196
+ * afterEach($httpBackend.verifyNoOutstandingRequest);
1197
+ * </pre>
1198
+ */
1199
+ $httpBackend.verifyNoOutstandingRequest = function() {
1200
+ if (responses.length) {
1201
+ throw Error('Unflushed requests: ' + responses.length);
1202
+ }
1203
+ };
1204
+
1205
+
1206
+ /**
1207
+ * @ngdoc method
1208
+ * @name ngMock.$httpBackend#resetExpectations
1209
+ * @methodOf ngMock.$httpBackend
1210
+ * @description
1211
+ * Resets all request expectations, but preserves all backend definitions. Typically, you would
1212
+ * call resetExpectations during a multiple-phase test when you want to reuse the same instance of
1213
+ * $httpBackend mock.
1214
+ */
1215
+ $httpBackend.resetExpectations = function() {
1216
+ expectations.length = 0;
1217
+ responses.length = 0;
1218
+ };
1219
+
1220
+ return $httpBackend;
1221
+
1222
+
1223
+ function createShortMethods(prefix) {
1224
+ angular.forEach(['GET', 'DELETE', 'JSONP'], function(method) {
1225
+ $httpBackend[prefix + method] = function(url, headers) {
1226
+ return $httpBackend[prefix](method, url, undefined, headers)
1227
+ }
1228
+ });
1229
+
1230
+ angular.forEach(['PUT', 'POST', 'PATCH'], function(method) {
1231
+ $httpBackend[prefix + method] = function(url, data, headers) {
1232
+ return $httpBackend[prefix](method, url, data, headers)
1233
+ }
1234
+ });
1235
+ }
1236
+ }
1237
+
1238
+ function MockHttpExpectation(method, url, data, headers) {
1239
+
1240
+ this.data = data;
1241
+ this.headers = headers;
1242
+
1243
+ this.match = function(m, u, d, h) {
1244
+ if (method != m) return false;
1245
+ if (!this.matchUrl(u)) return false;
1246
+ if (angular.isDefined(d) && !this.matchData(d)) return false;
1247
+ if (angular.isDefined(h) && !this.matchHeaders(h)) return false;
1248
+ return true;
1249
+ };
1250
+
1251
+ this.matchUrl = function(u) {
1252
+ if (!url) return true;
1253
+ if (angular.isFunction(url.test)) return url.test(u);
1254
+ return url == u;
1255
+ };
1256
+
1257
+ this.matchHeaders = function(h) {
1258
+ if (angular.isUndefined(headers)) return true;
1259
+ if (angular.isFunction(headers)) return headers(h);
1260
+ return angular.equals(headers, h);
1261
+ };
1262
+
1263
+ this.matchData = function(d) {
1264
+ if (angular.isUndefined(data)) return true;
1265
+ if (data && angular.isFunction(data.test)) return data.test(d);
1266
+ if (data && !angular.isString(data)) return angular.toJson(data) == d;
1267
+ return data == d;
1268
+ };
1269
+
1270
+ this.toString = function() {
1271
+ return method + ' ' + url;
1272
+ };
1273
+ }
1274
+
1275
+ function MockXhr() {
1276
+
1277
+ // hack for testing $http, $httpBackend
1278
+ MockXhr.$$lastInstance = this;
1279
+
1280
+ this.open = function(method, url, async) {
1281
+ this.$$method = method;
1282
+ this.$$url = url;
1283
+ this.$$async = async;
1284
+ this.$$reqHeaders = {};
1285
+ this.$$respHeaders = {};
1286
+ };
1287
+
1288
+ this.send = function(data) {
1289
+ this.$$data = data;
1290
+ };
1291
+
1292
+ this.setRequestHeader = function(key, value) {
1293
+ this.$$reqHeaders[key] = value;
1294
+ };
1295
+
1296
+ this.getResponseHeader = function(name) {
1297
+ // the lookup must be case insensitive, that's why we try two quick lookups and full scan at last
1298
+ var header = this.$$respHeaders[name];
1299
+ if (header) return header;
1300
+
1301
+ name = angular.lowercase(name);
1302
+ header = this.$$respHeaders[name];
1303
+ if (header) return header;
1304
+
1305
+ header = undefined;
1306
+ angular.forEach(this.$$respHeaders, function(headerVal, headerName) {
1307
+ if (!header && angular.lowercase(headerName) == name) header = headerVal;
1308
+ });
1309
+ return header;
1310
+ };
1311
+
1312
+ this.getAllResponseHeaders = function() {
1313
+ var lines = [];
1314
+
1315
+ angular.forEach(this.$$respHeaders, function(value, key) {
1316
+ lines.push(key + ': ' + value);
1317
+ });
1318
+ return lines.join('\n');
1319
+ };
1320
+
1321
+ this.abort = angular.noop;
1322
+ }
1323
+
1324
+
1325
+ /**
1326
+ * @ngdoc function
1327
+ * @name ngMock.$timeout
1328
+ * @description
1329
+ *
1330
+ * This service is just a simple decorator for {@link ng.$timeout $timeout} service
1331
+ * that adds a "flush" method.
1332
+ */
1333
+
1334
+ /**
1335
+ * @ngdoc method
1336
+ * @name ngMock.$timeout#flush
1337
+ * @methodOf ngMock.$timeout
1338
+ * @description
1339
+ *
1340
+ * Flushes the queue of pending tasks.
1341
+ */
1342
+
1343
+ /**
1344
+ *
1345
+ */
1346
+ angular.mock.$RootElementProvider = function() {
1347
+ this.$get = function() {
1348
+ return angular.element('<div ng-app></div>');
1349
+ }
1350
+ };
1351
+
1352
+ /**
1353
+ * @ngdoc overview
1354
+ * @name ngMock
1355
+ * @description
1356
+ *
1357
+ * The `ngMock` is an angular module which is used with `ng` module and adds unit-test configuration as well as useful
1358
+ * mocks to the {@link AUTO.$injector $injector}.
1359
+ */
1360
+ angular.module('ngMock', ['ng']).provider({
1361
+ $browser: angular.mock.$BrowserProvider,
1362
+ $exceptionHandler: angular.mock.$ExceptionHandlerProvider,
1363
+ $log: angular.mock.$LogProvider,
1364
+ $httpBackend: angular.mock.$HttpBackendProvider,
1365
+ $rootElement: angular.mock.$RootElementProvider
1366
+ }).config(function($provide) {
1367
+ $provide.decorator('$timeout', function($delegate, $browser) {
1368
+ $delegate.flush = function() {
1369
+ $browser.defer.flush();
1370
+ };
1371
+ return $delegate;
1372
+ });
1373
+ });
1374
+
1375
+
1376
+ /**
1377
+ * @ngdoc overview
1378
+ * @name ngMockE2E
1379
+ * @description
1380
+ *
1381
+ * The `ngMockE2E` is an angular module which contains mocks suitable for end-to-end testing.
1382
+ * Currently there is only one mock present in this module -
1383
+ * the {@link ngMockE2E.$httpBackend e2e $httpBackend} mock.
1384
+ */
1385
+ angular.module('ngMockE2E', ['ng']).config(function($provide) {
1386
+ $provide.decorator('$httpBackend', angular.mock.e2e.$httpBackendDecorator);
1387
+ });
1388
+
1389
+ /**
1390
+ * @ngdoc object
1391
+ * @name ngMockE2E.$httpBackend
1392
+ * @description
1393
+ * Fake HTTP backend implementation suitable for end-to-end testing or backend-less development of
1394
+ * applications that use the {@link ng.$http $http service}.
1395
+ *
1396
+ * *Note*: For fake http backend implementation suitable for unit testing please see
1397
+ * {@link ngMock.$httpBackend unit-testing $httpBackend mock}.
1398
+ *
1399
+ * This implementation can be used to respond with static or dynamic responses via the `when` api
1400
+ * and its shortcuts (`whenGET`, `whenPOST`, etc) and optionally pass through requests to the
1401
+ * real $httpBackend for specific requests (e.g. to interact with certain remote apis or to fetch
1402
+ * templates from a webserver).
1403
+ *
1404
+ * As opposed to unit-testing, in an end-to-end testing scenario or in scenario when an application
1405
+ * is being developed with the real backend api replaced with a mock, it is often desirable for
1406
+ * certain category of requests to bypass the mock and issue a real http request (e.g. to fetch
1407
+ * templates or static files from the webserver). To configure the backend with this behavior
1408
+ * use the `passThrough` request handler of `when` instead of `respond`.
1409
+ *
1410
+ * Additionally, we don't want to manually have to flush mocked out requests like we do during unit
1411
+ * testing. For this reason the e2e $httpBackend automatically flushes mocked out requests
1412
+ * automatically, closely simulating the behavior of the XMLHttpRequest object.
1413
+ *
1414
+ * To setup the application to run with this http backend, you have to create a module that depends
1415
+ * on the `ngMockE2E` and your application modules and defines the fake backend:
1416
+ *
1417
+ * <pre>
1418
+ * myAppDev = angular.module('myAppDev', ['myApp', 'ngMockE2E']);
1419
+ * myAppDev.run(function($httpBackend) {
1420
+ * phones = [{name: 'phone1'}, {name: 'phone2'}];
1421
+ *
1422
+ * // returns the current list of phones
1423
+ * $httpBackend.whenGET('/phones').respond(phones);
1424
+ *
1425
+ * // adds a new phone to the phones array
1426
+ * $httpBackend.whenPOST('/phones').respond(function(method, url, data) {
1427
+ * phones.push(angular.fromJSON(data));
1428
+ * });
1429
+ * $httpBackend.whenGET(/^\/templates\//).passThrough();
1430
+ * //...
1431
+ * });
1432
+ * </pre>
1433
+ *
1434
+ * Afterwards, bootstrap your app with this new module.
1435
+ */
1436
+
1437
+ /**
1438
+ * @ngdoc method
1439
+ * @name ngMockE2E.$httpBackend#when
1440
+ * @methodOf ngMockE2E.$httpBackend
1441
+ * @description
1442
+ * Creates a new backend definition.
1443
+ *
1444
+ * @param {string} method HTTP method.
1445
+ * @param {string|RegExp} url HTTP url.
1446
+ * @param {(string|RegExp)=} data HTTP request body.
1447
+ * @param {(Object|function(Object))=} headers HTTP headers or function that receives http header
1448
+ * object and returns true if the headers match the current definition.
1449
+ * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
1450
+ * control how a matched request is handled.
1451
+ *
1452
+ * - respond – `{function([status,] data[, headers])|function(function(method, url, data, headers)}`
1453
+ * – The respond method takes a set of static data to be returned or a function that can return
1454
+ * an array containing response status (number), response data (string) and response headers
1455
+ * (Object).
1456
+ * - passThrough – `{function()}` – Any request matching a backend definition with `passThrough`
1457
+ * handler, will be pass through to the real backend (an XHR request will be made to the
1458
+ * server.
1459
+ */
1460
+
1461
+ /**
1462
+ * @ngdoc method
1463
+ * @name ngMockE2E.$httpBackend#whenGET
1464
+ * @methodOf ngMockE2E.$httpBackend
1465
+ * @description
1466
+ * Creates a new backend definition for GET requests. For more info see `when()`.
1467
+ *
1468
+ * @param {string|RegExp} url HTTP url.
1469
+ * @param {(Object|function(Object))=} headers HTTP headers.
1470
+ * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
1471
+ * control how a matched request is handled.
1472
+ */
1473
+
1474
+ /**
1475
+ * @ngdoc method
1476
+ * @name ngMockE2E.$httpBackend#whenHEAD
1477
+ * @methodOf ngMockE2E.$httpBackend
1478
+ * @description
1479
+ * Creates a new backend definition for HEAD requests. For more info see `when()`.
1480
+ *
1481
+ * @param {string|RegExp} url HTTP url.
1482
+ * @param {(Object|function(Object))=} headers HTTP headers.
1483
+ * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
1484
+ * control how a matched request is handled.
1485
+ */
1486
+
1487
+ /**
1488
+ * @ngdoc method
1489
+ * @name ngMockE2E.$httpBackend#whenDELETE
1490
+ * @methodOf ngMockE2E.$httpBackend
1491
+ * @description
1492
+ * Creates a new backend definition for DELETE requests. For more info see `when()`.
1493
+ *
1494
+ * @param {string|RegExp} url HTTP url.
1495
+ * @param {(Object|function(Object))=} headers HTTP headers.
1496
+ * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
1497
+ * control how a matched request is handled.
1498
+ */
1499
+
1500
+ /**
1501
+ * @ngdoc method
1502
+ * @name ngMockE2E.$httpBackend#whenPOST
1503
+ * @methodOf ngMockE2E.$httpBackend
1504
+ * @description
1505
+ * Creates a new backend definition for POST requests. For more info see `when()`.
1506
+ *
1507
+ * @param {string|RegExp} url HTTP url.
1508
+ * @param {(string|RegExp)=} data HTTP request body.
1509
+ * @param {(Object|function(Object))=} headers HTTP headers.
1510
+ * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
1511
+ * control how a matched request is handled.
1512
+ */
1513
+
1514
+ /**
1515
+ * @ngdoc method
1516
+ * @name ngMockE2E.$httpBackend#whenPUT
1517
+ * @methodOf ngMockE2E.$httpBackend
1518
+ * @description
1519
+ * Creates a new backend definition for PUT requests. For more info see `when()`.
1520
+ *
1521
+ * @param {string|RegExp} url HTTP url.
1522
+ * @param {(string|RegExp)=} data HTTP request body.
1523
+ * @param {(Object|function(Object))=} headers HTTP headers.
1524
+ * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
1525
+ * control how a matched request is handled.
1526
+ */
1527
+
1528
+ /**
1529
+ * @ngdoc method
1530
+ * @name ngMockE2E.$httpBackend#whenPATCH
1531
+ * @methodOf ngMockE2E.$httpBackend
1532
+ * @description
1533
+ * Creates a new backend definition for PATCH requests. For more info see `when()`.
1534
+ *
1535
+ * @param {string|RegExp} url HTTP url.
1536
+ * @param {(string|RegExp)=} data HTTP request body.
1537
+ * @param {(Object|function(Object))=} headers HTTP headers.
1538
+ * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
1539
+ * control how a matched request is handled.
1540
+ */
1541
+
1542
+ /**
1543
+ * @ngdoc method
1544
+ * @name ngMockE2E.$httpBackend#whenJSONP
1545
+ * @methodOf ngMockE2E.$httpBackend
1546
+ * @description
1547
+ * Creates a new backend definition for JSONP requests. For more info see `when()`.
1548
+ *
1549
+ * @param {string|RegExp} url HTTP url.
1550
+ * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
1551
+ * control how a matched request is handled.
1552
+ */
1553
+ angular.mock.e2e = {};
1554
+ angular.mock.e2e.$httpBackendDecorator = ['$delegate', '$browser', createHttpBackendMock];
1555
+
1556
+
1557
+ angular.mock.clearDataCache = function() {
1558
+ var key,
1559
+ cache = angular.element.cache;
1560
+
1561
+ for(key in cache) {
1562
+ if (cache.hasOwnProperty(key)) {
1563
+ var handle = cache[key].handle;
1564
+
1565
+ handle && angular.element(handle.elem).unbind();
1566
+ delete cache[key];
1567
+ }
1568
+ }
1569
+ };
1570
+
1571
+
1572
+ window.jstestdriver && (function(window) {
1573
+ /**
1574
+ * Global method to output any number of objects into JSTD console. Useful for debugging.
1575
+ */
1576
+ window.dump = function() {
1577
+ var args = [];
1578
+ angular.forEach(arguments, function(arg) {
1579
+ args.push(angular.mock.dump(arg));
1580
+ });
1581
+ jstestdriver.console.log.apply(jstestdriver.console, args);
1582
+ if (window.console) {
1583
+ window.console.log.apply(window.console, args);
1584
+ }
1585
+ };
1586
+ })(window);
1587
+
1588
+
1589
+ window.jasmine && (function(window) {
1590
+
1591
+ afterEach(function() {
1592
+ var spec = getCurrentSpec();
1593
+ var injector = spec.$injector;
1594
+
1595
+ spec.$injector = null;
1596
+ spec.$modules = null;
1597
+
1598
+ if (injector) {
1599
+ injector.get('$rootElement').unbind();
1600
+ injector.get('$browser').pollFns.length = 0;
1601
+ }
1602
+
1603
+ angular.mock.clearDataCache();
1604
+
1605
+ // clean up jquery's fragment cache
1606
+ angular.forEach(angular.element.fragments, function(val, key) {
1607
+ delete angular.element.fragments[key];
1608
+ });
1609
+
1610
+ MockXhr.$$lastInstance = null;
1611
+
1612
+ angular.forEach(angular.callbacks, function(val, key) {
1613
+ delete angular.callbacks[key];
1614
+ });
1615
+ angular.callbacks.counter = 0;
1616
+ });
1617
+
1618
+ function getCurrentSpec() {
1619
+ return jasmine.getEnv().currentSpec;
1620
+ }
1621
+
1622
+ function isSpecRunning() {
1623
+ var spec = getCurrentSpec();
1624
+ return spec && spec.queue.running;
1625
+ }
1626
+
1627
+ /**
1628
+ * @ngdoc function
1629
+ * @name angular.mock.module
1630
+ * @description
1631
+ *
1632
+ * *NOTE*: This is function is also published on window for easy access.<br>
1633
+ * *NOTE*: Only available with {@link http://pivotal.github.com/jasmine/ jasmine}.
1634
+ *
1635
+ * This function registers a module configuration code. It collects the configuration information
1636
+ * which will be used when the injector is created by {@link angular.mock.inject inject}.
1637
+ *
1638
+ * See {@link angular.mock.inject inject} for usage example
1639
+ *
1640
+ * @param {...(string|Function)} fns any number of modules which are represented as string
1641
+ * aliases or as anonymous module initialization functions. The modules are used to
1642
+ * configure the injector. The 'ng' and 'ngMock' modules are automatically loaded.
1643
+ */
1644
+ window.module = angular.mock.module = function() {
1645
+ var moduleFns = Array.prototype.slice.call(arguments, 0);
1646
+ return isSpecRunning() ? workFn() : workFn;
1647
+ /////////////////////
1648
+ function workFn() {
1649
+ var spec = getCurrentSpec();
1650
+ if (spec.$injector) {
1651
+ throw Error('Injector already created, can not register a module!');
1652
+ } else {
1653
+ var modules = spec.$modules || (spec.$modules = []);
1654
+ angular.forEach(moduleFns, function(module) {
1655
+ modules.push(module);
1656
+ });
1657
+ }
1658
+ }
1659
+ };
1660
+
1661
+ /**
1662
+ * @ngdoc function
1663
+ * @name angular.mock.inject
1664
+ * @description
1665
+ *
1666
+ * *NOTE*: This is function is also published on window for easy access.<br>
1667
+ * *NOTE*: Only available with {@link http://pivotal.github.com/jasmine/ jasmine}.
1668
+ *
1669
+ * The inject function wraps a function into an injectable function. The inject() creates new
1670
+ * instance of {@link AUTO.$injector $injector} per test, which is then used for
1671
+ * resolving references.
1672
+ *
1673
+ * See also {@link angular.mock.module module}
1674
+ *
1675
+ * Example of what a typical jasmine tests looks like with the inject method.
1676
+ * <pre>
1677
+ *
1678
+ * angular.module('myApplicationModule', [])
1679
+ * .value('mode', 'app')
1680
+ * .value('version', 'v1.0.1');
1681
+ *
1682
+ *
1683
+ * describe('MyApp', function() {
1684
+ *
1685
+ * // You need to load modules that you want to test,
1686
+ * // it loads only the "ng" module by default.
1687
+ * beforeEach(module('myApplicationModule'));
1688
+ *
1689
+ *
1690
+ * // inject() is used to inject arguments of all given functions
1691
+ * it('should provide a version', inject(function(mode, version) {
1692
+ * expect(version).toEqual('v1.0.1');
1693
+ * expect(mode).toEqual('app');
1694
+ * }));
1695
+ *
1696
+ *
1697
+ * // The inject and module method can also be used inside of the it or beforeEach
1698
+ * it('should override a version and test the new version is injected', function() {
1699
+ * // module() takes functions or strings (module aliases)
1700
+ * module(function($provide) {
1701
+ * $provide.value('version', 'overridden'); // override version here
1702
+ * });
1703
+ *
1704
+ * inject(function(version) {
1705
+ * expect(version).toEqual('overridden');
1706
+ * });
1707
+ * ));
1708
+ * });
1709
+ *
1710
+ * </pre>
1711
+ *
1712
+ * @param {...Function} fns any number of functions which will be injected using the injector.
1713
+ */
1714
+ window.inject = angular.mock.inject = function() {
1715
+ var blockFns = Array.prototype.slice.call(arguments, 0);
1716
+ var errorForStack = new Error('Declaration Location');
1717
+ return isSpecRunning() ? workFn() : workFn;
1718
+ /////////////////////
1719
+ function workFn() {
1720
+ var spec = getCurrentSpec();
1721
+ var modules = spec.$modules || [];
1722
+ modules.unshift('ngMock');
1723
+ modules.unshift('ng');
1724
+ var injector = spec.$injector;
1725
+ if (!injector) {
1726
+ injector = spec.$injector = angular.injector(modules);
1727
+ }
1728
+ for(var i = 0, ii = blockFns.length; i < ii; i++) {
1729
+ try {
1730
+ injector.invoke(blockFns[i] || angular.noop, this);
1731
+ } catch (e) {
1732
+ if(e.stack) e.stack += '\n' + errorForStack.stack;
1733
+ throw e;
1734
+ } finally {
1735
+ errorForStack = null;
1736
+ }
1737
+ }
1738
+ }
1739
+ };
1740
+ })(window);