material_raingular 0.2 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 0da8e34bdf3bd3f3e7fbb4802eeae30cbb3e0e37
4
- data.tar.gz: c8f5bb5cb11b0116bbdab77427e76ba48a71173c
3
+ metadata.gz: cb0a77791416d98f7f37c555f1c6f7bf6f92c70c
4
+ data.tar.gz: 8f234f2de2bc17390e8c9664b46cb54f214b5b3a
5
5
  SHA512:
6
- metadata.gz: f750651f1a186f99dc253ec2500ba62d7d435cb1dc77c224cc52cf3d46bb27ac8c21362371d65cb4d33b4fc68b643c4314a229408d6b655214b536498cb9743c
7
- data.tar.gz: 86f95b39d99dea9008e7b800f5bbbae5dd50ddb0a9c5661cdf83a898999533a23a61f6444d9668e5f4b9040908c31186b682856fd0e3ff70fb8369355881a307
6
+ metadata.gz: 60e710430ca763326bd0676e4db59bea7da703fb79dc3d90ad29da58970fa020432c519253852311681bec9b6058d6ceb3db588181377ee4aec0f28a36b94d20
7
+ data.tar.gz: 0b970ccea18a10d2c88f09c067afe63a3b17f19f5bae7b2ae0f4ef577236a399fcebc0f69d69995de9edfd30d31b3c69f1b7c407da73a25331961653926e85d4
@@ -1,3 +1,3 @@
1
1
  module MaterialRaingular
2
- VERSION = "0.2"
2
+ VERSION = "0.2.1"
3
3
  end
@@ -0,0 +1,2974 @@
1
+ /**
2
+ * @license AngularJS v1.5.3
3
+ * (c) 2010-2016 Google, Inc. http://angularjs.org
4
+ * License: MIT
5
+ */
6
+ (function(window, angular, undefined) {
7
+
8
+ 'use strict';
9
+
10
+ /**
11
+ * @ngdoc object
12
+ * @name angular.mock
13
+ * @description
14
+ *
15
+ * Namespace from 'angular-mocks.js' which contains testing related code.
16
+ */
17
+ angular.mock = {};
18
+
19
+ /**
20
+ * ! This is a private undocumented service !
21
+ *
22
+ * @name $browser
23
+ *
24
+ * @description
25
+ * This service is a mock implementation of {@link ng.$browser}. It provides fake
26
+ * implementation for commonly used browser apis that are hard to test, e.g. setTimeout, xhr,
27
+ * cookies, etc...
28
+ *
29
+ * The api of this service is the same as that of the real {@link ng.$browser $browser}, except
30
+ * that there are several helper methods available which can be used in tests.
31
+ */
32
+ angular.mock.$BrowserProvider = function() {
33
+ this.$get = function() {
34
+ return new angular.mock.$Browser();
35
+ };
36
+ };
37
+
38
+ angular.mock.$Browser = function() {
39
+ var self = this;
40
+
41
+ this.isMock = true;
42
+ self.$$url = "http://server/";
43
+ self.$$lastUrl = self.$$url; // used by url polling fn
44
+ self.pollFns = [];
45
+
46
+ // TODO(vojta): remove this temporary api
47
+ self.$$completeOutstandingRequest = angular.noop;
48
+ self.$$incOutstandingRequestCount = angular.noop;
49
+
50
+
51
+ // register url polling fn
52
+
53
+ self.onUrlChange = function(listener) {
54
+ self.pollFns.push(
55
+ function() {
56
+ if (self.$$lastUrl !== self.$$url || self.$$state !== self.$$lastState) {
57
+ self.$$lastUrl = self.$$url;
58
+ self.$$lastState = self.$$state;
59
+ listener(self.$$url, self.$$state);
60
+ }
61
+ }
62
+ );
63
+
64
+ return listener;
65
+ };
66
+
67
+ self.$$applicationDestroyed = angular.noop;
68
+ self.$$checkUrlChange = angular.noop;
69
+
70
+ self.deferredFns = [];
71
+ self.deferredNextId = 0;
72
+
73
+ self.defer = function(fn, delay) {
74
+ delay = delay || 0;
75
+ self.deferredFns.push({time:(self.defer.now + delay), fn:fn, id: self.deferredNextId});
76
+ self.deferredFns.sort(function(a, b) { return a.time - b.time;});
77
+ return self.deferredNextId++;
78
+ };
79
+
80
+
81
+ /**
82
+ * @name $browser#defer.now
83
+ *
84
+ * @description
85
+ * Current milliseconds mock time.
86
+ */
87
+ self.defer.now = 0;
88
+
89
+
90
+ self.defer.cancel = function(deferId) {
91
+ var fnIndex;
92
+
93
+ angular.forEach(self.deferredFns, function(fn, index) {
94
+ if (fn.id === deferId) fnIndex = index;
95
+ });
96
+
97
+ if (angular.isDefined(fnIndex)) {
98
+ self.deferredFns.splice(fnIndex, 1);
99
+ return true;
100
+ }
101
+
102
+ return false;
103
+ };
104
+
105
+
106
+ /**
107
+ * @name $browser#defer.flush
108
+ *
109
+ * @description
110
+ * Flushes all pending requests and executes the defer callbacks.
111
+ *
112
+ * @param {number=} number of milliseconds to flush. See {@link #defer.now}
113
+ */
114
+ self.defer.flush = function(delay) {
115
+ if (angular.isDefined(delay)) {
116
+ self.defer.now += delay;
117
+ } else {
118
+ if (self.deferredFns.length) {
119
+ self.defer.now = self.deferredFns[self.deferredFns.length - 1].time;
120
+ } else {
121
+ throw new Error('No deferred tasks to be flushed');
122
+ }
123
+ }
124
+
125
+ while (self.deferredFns.length && self.deferredFns[0].time <= self.defer.now) {
126
+ self.deferredFns.shift().fn();
127
+ }
128
+ };
129
+
130
+ self.$$baseHref = '/';
131
+ self.baseHref = function() {
132
+ return this.$$baseHref;
133
+ };
134
+ };
135
+ angular.mock.$Browser.prototype = {
136
+
137
+ /**
138
+ * @name $browser#poll
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
+ url: function(url, replace, state) {
150
+ if (angular.isUndefined(state)) {
151
+ state = null;
152
+ }
153
+ if (url) {
154
+ this.$$url = url;
155
+ // Native pushState serializes & copies the object; simulate it.
156
+ this.$$state = angular.copy(state);
157
+ return this;
158
+ }
159
+
160
+ return this.$$url;
161
+ },
162
+
163
+ state: function() {
164
+ return this.$$state;
165
+ },
166
+
167
+ notifyWhenNoOutstandingRequests: function(fn) {
168
+ fn();
169
+ }
170
+ };
171
+
172
+
173
+ /**
174
+ * @ngdoc provider
175
+ * @name $exceptionHandlerProvider
176
+ *
177
+ * @description
178
+ * Configures the mock implementation of {@link ng.$exceptionHandler} to rethrow or to log errors
179
+ * passed to the `$exceptionHandler`.
180
+ */
181
+
182
+ /**
183
+ * @ngdoc service
184
+ * @name $exceptionHandler
185
+ *
186
+ * @description
187
+ * Mock implementation of {@link ng.$exceptionHandler} that rethrows or logs errors passed
188
+ * to it. See {@link ngMock.$exceptionHandlerProvider $exceptionHandlerProvider} for configuration
189
+ * information.
190
+ *
191
+ *
192
+ * ```js
193
+ * describe('$exceptionHandlerProvider', function() {
194
+ *
195
+ * it('should capture log messages and exceptions', function() {
196
+ *
197
+ * module(function($exceptionHandlerProvider) {
198
+ * $exceptionHandlerProvider.mode('log');
199
+ * });
200
+ *
201
+ * inject(function($log, $exceptionHandler, $timeout) {
202
+ * $timeout(function() { $log.log(1); });
203
+ * $timeout(function() { $log.log(2); throw 'banana peel'; });
204
+ * $timeout(function() { $log.log(3); });
205
+ * expect($exceptionHandler.errors).toEqual([]);
206
+ * expect($log.assertEmpty());
207
+ * $timeout.flush();
208
+ * expect($exceptionHandler.errors).toEqual(['banana peel']);
209
+ * expect($log.log.logs).toEqual([[1], [2], [3]]);
210
+ * });
211
+ * });
212
+ * });
213
+ * ```
214
+ */
215
+
216
+ angular.mock.$ExceptionHandlerProvider = function() {
217
+ var handler;
218
+
219
+ /**
220
+ * @ngdoc method
221
+ * @name $exceptionHandlerProvider#mode
222
+ *
223
+ * @description
224
+ * Sets the logging mode.
225
+ *
226
+ * @param {string} mode Mode of operation, defaults to `rethrow`.
227
+ *
228
+ * - `log`: Sometimes it is desirable to test that an error is thrown, for this case the `log`
229
+ * mode stores an array of errors in `$exceptionHandler.errors`, to allow later
230
+ * assertion of them. See {@link ngMock.$log#assertEmpty assertEmpty()} and
231
+ * {@link ngMock.$log#reset reset()}
232
+ * - `rethrow`: If any errors are passed to the handler in tests, it typically means that there
233
+ * is a bug in the application or test, so this mock will make these tests fail.
234
+ * For any implementations that expect exceptions to be thrown, the `rethrow` mode
235
+ * will also maintain a log of thrown errors.
236
+ */
237
+ this.mode = function(mode) {
238
+
239
+ switch (mode) {
240
+ case 'log':
241
+ case 'rethrow':
242
+ var errors = [];
243
+ handler = function(e) {
244
+ if (arguments.length == 1) {
245
+ errors.push(e);
246
+ } else {
247
+ errors.push([].slice.call(arguments, 0));
248
+ }
249
+ if (mode === "rethrow") {
250
+ throw e;
251
+ }
252
+ };
253
+ handler.errors = errors;
254
+ break;
255
+ default:
256
+ throw new Error("Unknown mode '" + mode + "', only 'log'/'rethrow' modes are allowed!");
257
+ }
258
+ };
259
+
260
+ this.$get = function() {
261
+ return handler;
262
+ };
263
+
264
+ this.mode('rethrow');
265
+ };
266
+
267
+
268
+ /**
269
+ * @ngdoc service
270
+ * @name $log
271
+ *
272
+ * @description
273
+ * Mock implementation of {@link ng.$log} that gathers all logged messages in arrays
274
+ * (one array per logging level). These arrays are exposed as `logs` property of each of the
275
+ * level-specific log function, e.g. for level `error` the array is exposed as `$log.error.logs`.
276
+ *
277
+ */
278
+ angular.mock.$LogProvider = function() {
279
+ var debug = true;
280
+
281
+ function concat(array1, array2, index) {
282
+ return array1.concat(Array.prototype.slice.call(array2, index));
283
+ }
284
+
285
+ this.debugEnabled = function(flag) {
286
+ if (angular.isDefined(flag)) {
287
+ debug = flag;
288
+ return this;
289
+ } else {
290
+ return debug;
291
+ }
292
+ };
293
+
294
+ this.$get = function() {
295
+ var $log = {
296
+ log: function() { $log.log.logs.push(concat([], arguments, 0)); },
297
+ warn: function() { $log.warn.logs.push(concat([], arguments, 0)); },
298
+ info: function() { $log.info.logs.push(concat([], arguments, 0)); },
299
+ error: function() { $log.error.logs.push(concat([], arguments, 0)); },
300
+ debug: function() {
301
+ if (debug) {
302
+ $log.debug.logs.push(concat([], arguments, 0));
303
+ }
304
+ }
305
+ };
306
+
307
+ /**
308
+ * @ngdoc method
309
+ * @name $log#reset
310
+ *
311
+ * @description
312
+ * Reset all of the logging arrays to empty.
313
+ */
314
+ $log.reset = function() {
315
+ /**
316
+ * @ngdoc property
317
+ * @name $log#log.logs
318
+ *
319
+ * @description
320
+ * Array of messages logged using {@link ng.$log#log `log()`}.
321
+ *
322
+ * @example
323
+ * ```js
324
+ * $log.log('Some Log');
325
+ * var first = $log.log.logs.unshift();
326
+ * ```
327
+ */
328
+ $log.log.logs = [];
329
+ /**
330
+ * @ngdoc property
331
+ * @name $log#info.logs
332
+ *
333
+ * @description
334
+ * Array of messages logged using {@link ng.$log#info `info()`}.
335
+ *
336
+ * @example
337
+ * ```js
338
+ * $log.info('Some Info');
339
+ * var first = $log.info.logs.unshift();
340
+ * ```
341
+ */
342
+ $log.info.logs = [];
343
+ /**
344
+ * @ngdoc property
345
+ * @name $log#warn.logs
346
+ *
347
+ * @description
348
+ * Array of messages logged using {@link ng.$log#warn `warn()`}.
349
+ *
350
+ * @example
351
+ * ```js
352
+ * $log.warn('Some Warning');
353
+ * var first = $log.warn.logs.unshift();
354
+ * ```
355
+ */
356
+ $log.warn.logs = [];
357
+ /**
358
+ * @ngdoc property
359
+ * @name $log#error.logs
360
+ *
361
+ * @description
362
+ * Array of messages logged using {@link ng.$log#error `error()`}.
363
+ *
364
+ * @example
365
+ * ```js
366
+ * $log.error('Some Error');
367
+ * var first = $log.error.logs.unshift();
368
+ * ```
369
+ */
370
+ $log.error.logs = [];
371
+ /**
372
+ * @ngdoc property
373
+ * @name $log#debug.logs
374
+ *
375
+ * @description
376
+ * Array of messages logged using {@link ng.$log#debug `debug()`}.
377
+ *
378
+ * @example
379
+ * ```js
380
+ * $log.debug('Some Error');
381
+ * var first = $log.debug.logs.unshift();
382
+ * ```
383
+ */
384
+ $log.debug.logs = [];
385
+ };
386
+
387
+ /**
388
+ * @ngdoc method
389
+ * @name $log#assertEmpty
390
+ *
391
+ * @description
392
+ * Assert that all of the logging methods have no logged messages. If any messages are present,
393
+ * an exception is thrown.
394
+ */
395
+ $log.assertEmpty = function() {
396
+ var errors = [];
397
+ angular.forEach(['error', 'warn', 'info', 'log', 'debug'], function(logLevel) {
398
+ angular.forEach($log[logLevel].logs, function(log) {
399
+ angular.forEach(log, function(logItem) {
400
+ errors.push('MOCK $log (' + logLevel + '): ' + String(logItem) + '\n' +
401
+ (logItem.stack || ''));
402
+ });
403
+ });
404
+ });
405
+ if (errors.length) {
406
+ errors.unshift("Expected $log to be empty! Either a message was logged unexpectedly, or " +
407
+ "an expected log message was not checked and removed:");
408
+ errors.push('');
409
+ throw new Error(errors.join('\n---------\n'));
410
+ }
411
+ };
412
+
413
+ $log.reset();
414
+ return $log;
415
+ };
416
+ };
417
+
418
+
419
+ /**
420
+ * @ngdoc service
421
+ * @name $interval
422
+ *
423
+ * @description
424
+ * Mock implementation of the $interval service.
425
+ *
426
+ * Use {@link ngMock.$interval#flush `$interval.flush(millis)`} to
427
+ * move forward by `millis` milliseconds and trigger any functions scheduled to run in that
428
+ * time.
429
+ *
430
+ * @param {function()} fn A function that should be called repeatedly.
431
+ * @param {number} delay Number of milliseconds between each function call.
432
+ * @param {number=} [count=0] Number of times to repeat. If not set, or 0, will repeat
433
+ * indefinitely.
434
+ * @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise
435
+ * will invoke `fn` within the {@link ng.$rootScope.Scope#$apply $apply} block.
436
+ * @param {...*=} Pass additional parameters to the executed function.
437
+ * @returns {promise} A promise which will be notified on each iteration.
438
+ */
439
+ angular.mock.$IntervalProvider = function() {
440
+ this.$get = ['$browser', '$rootScope', '$q', '$$q',
441
+ function($browser, $rootScope, $q, $$q) {
442
+ var repeatFns = [],
443
+ nextRepeatId = 0,
444
+ now = 0;
445
+
446
+ var $interval = function(fn, delay, count, invokeApply) {
447
+ var hasParams = arguments.length > 4,
448
+ args = hasParams ? Array.prototype.slice.call(arguments, 4) : [],
449
+ iteration = 0,
450
+ skipApply = (angular.isDefined(invokeApply) && !invokeApply),
451
+ deferred = (skipApply ? $$q : $q).defer(),
452
+ promise = deferred.promise;
453
+
454
+ count = (angular.isDefined(count)) ? count : 0;
455
+ promise.then(null, null, (!hasParams) ? fn : function() {
456
+ fn.apply(null, args);
457
+ });
458
+
459
+ promise.$$intervalId = nextRepeatId;
460
+
461
+ function tick() {
462
+ deferred.notify(iteration++);
463
+
464
+ if (count > 0 && iteration >= count) {
465
+ var fnIndex;
466
+ deferred.resolve(iteration);
467
+
468
+ angular.forEach(repeatFns, function(fn, index) {
469
+ if (fn.id === promise.$$intervalId) fnIndex = index;
470
+ });
471
+
472
+ if (angular.isDefined(fnIndex)) {
473
+ repeatFns.splice(fnIndex, 1);
474
+ }
475
+ }
476
+
477
+ if (skipApply) {
478
+ $browser.defer.flush();
479
+ } else {
480
+ $rootScope.$apply();
481
+ }
482
+ }
483
+
484
+ repeatFns.push({
485
+ nextTime:(now + delay),
486
+ delay: delay,
487
+ fn: tick,
488
+ id: nextRepeatId,
489
+ deferred: deferred
490
+ });
491
+ repeatFns.sort(function(a, b) { return a.nextTime - b.nextTime;});
492
+
493
+ nextRepeatId++;
494
+ return promise;
495
+ };
496
+ /**
497
+ * @ngdoc method
498
+ * @name $interval#cancel
499
+ *
500
+ * @description
501
+ * Cancels a task associated with the `promise`.
502
+ *
503
+ * @param {promise} promise A promise from calling the `$interval` function.
504
+ * @returns {boolean} Returns `true` if the task was successfully cancelled.
505
+ */
506
+ $interval.cancel = function(promise) {
507
+ if (!promise) return false;
508
+ var fnIndex;
509
+
510
+ angular.forEach(repeatFns, function(fn, index) {
511
+ if (fn.id === promise.$$intervalId) fnIndex = index;
512
+ });
513
+
514
+ if (angular.isDefined(fnIndex)) {
515
+ repeatFns[fnIndex].deferred.reject('canceled');
516
+ repeatFns.splice(fnIndex, 1);
517
+ return true;
518
+ }
519
+
520
+ return false;
521
+ };
522
+
523
+ /**
524
+ * @ngdoc method
525
+ * @name $interval#flush
526
+ * @description
527
+ *
528
+ * Runs interval tasks scheduled to be run in the next `millis` milliseconds.
529
+ *
530
+ * @param {number=} millis maximum timeout amount to flush up until.
531
+ *
532
+ * @return {number} The amount of time moved forward.
533
+ */
534
+ $interval.flush = function(millis) {
535
+ now += millis;
536
+ while (repeatFns.length && repeatFns[0].nextTime <= now) {
537
+ var task = repeatFns[0];
538
+ task.fn();
539
+ task.nextTime += task.delay;
540
+ repeatFns.sort(function(a, b) { return a.nextTime - b.nextTime;});
541
+ }
542
+ return millis;
543
+ };
544
+
545
+ return $interval;
546
+ }];
547
+ };
548
+
549
+
550
+ /* jshint -W101 */
551
+ /* The R_ISO8061_STR regex is never going to fit into the 100 char limit!
552
+ * This directive should go inside the anonymous function but a bug in JSHint means that it would
553
+ * not be enacted early enough to prevent the warning.
554
+ */
555
+ var R_ISO8061_STR = /^(-?\d{4})-?(\d\d)-?(\d\d)(?:T(\d\d)(?:\:?(\d\d)(?:\:?(\d\d)(?:\.(\d{3}))?)?)?(Z|([+-])(\d\d):?(\d\d)))?$/;
556
+
557
+ function jsonStringToDate(string) {
558
+ var match;
559
+ if (match = string.match(R_ISO8061_STR)) {
560
+ var date = new Date(0),
561
+ tzHour = 0,
562
+ tzMin = 0;
563
+ if (match[9]) {
564
+ tzHour = toInt(match[9] + match[10]);
565
+ tzMin = toInt(match[9] + match[11]);
566
+ }
567
+ date.setUTCFullYear(toInt(match[1]), toInt(match[2]) - 1, toInt(match[3]));
568
+ date.setUTCHours(toInt(match[4] || 0) - tzHour,
569
+ toInt(match[5] || 0) - tzMin,
570
+ toInt(match[6] || 0),
571
+ toInt(match[7] || 0));
572
+ return date;
573
+ }
574
+ return string;
575
+ }
576
+
577
+ function toInt(str) {
578
+ return parseInt(str, 10);
579
+ }
580
+
581
+ function padNumberInMock(num, digits, trim) {
582
+ var neg = '';
583
+ if (num < 0) {
584
+ neg = '-';
585
+ num = -num;
586
+ }
587
+ num = '' + num;
588
+ while (num.length < digits) num = '0' + num;
589
+ if (trim) {
590
+ num = num.substr(num.length - digits);
591
+ }
592
+ return neg + num;
593
+ }
594
+
595
+
596
+ /**
597
+ * @ngdoc type
598
+ * @name angular.mock.TzDate
599
+ * @description
600
+ *
601
+ * *NOTE*: this is not an injectable instance, just a globally available mock class of `Date`.
602
+ *
603
+ * Mock of the Date type which has its timezone specified via constructor arg.
604
+ *
605
+ * The main purpose is to create Date-like instances with timezone fixed to the specified timezone
606
+ * offset, so that we can test code that depends on local timezone settings without dependency on
607
+ * the time zone settings of the machine where the code is running.
608
+ *
609
+ * @param {number} offset Offset of the *desired* timezone in hours (fractions will be honored)
610
+ * @param {(number|string)} timestamp Timestamp representing the desired time in *UTC*
611
+ *
612
+ * @example
613
+ * !!!! WARNING !!!!!
614
+ * This is not a complete Date object so only methods that were implemented can be called safely.
615
+ * To make matters worse, TzDate instances inherit stuff from Date via a prototype.
616
+ *
617
+ * We do our best to intercept calls to "unimplemented" methods, but since the list of methods is
618
+ * incomplete we might be missing some non-standard methods. This can result in errors like:
619
+ * "Date.prototype.foo called on incompatible Object".
620
+ *
621
+ * ```js
622
+ * var newYearInBratislava = new TzDate(-1, '2009-12-31T23:00:00Z');
623
+ * newYearInBratislava.getTimezoneOffset() => -60;
624
+ * newYearInBratislava.getFullYear() => 2010;
625
+ * newYearInBratislava.getMonth() => 0;
626
+ * newYearInBratislava.getDate() => 1;
627
+ * newYearInBratislava.getHours() => 0;
628
+ * newYearInBratislava.getMinutes() => 0;
629
+ * newYearInBratislava.getSeconds() => 0;
630
+ * ```
631
+ *
632
+ */
633
+ angular.mock.TzDate = function(offset, timestamp) {
634
+ var self = new Date(0);
635
+ if (angular.isString(timestamp)) {
636
+ var tsStr = timestamp;
637
+
638
+ self.origDate = jsonStringToDate(timestamp);
639
+
640
+ timestamp = self.origDate.getTime();
641
+ if (isNaN(timestamp)) {
642
+ throw {
643
+ name: "Illegal Argument",
644
+ message: "Arg '" + tsStr + "' passed into TzDate constructor is not a valid date string"
645
+ };
646
+ }
647
+ } else {
648
+ self.origDate = new Date(timestamp);
649
+ }
650
+
651
+ var localOffset = new Date(timestamp).getTimezoneOffset();
652
+ self.offsetDiff = localOffset * 60 * 1000 - offset * 1000 * 60 * 60;
653
+ self.date = new Date(timestamp + self.offsetDiff);
654
+
655
+ self.getTime = function() {
656
+ return self.date.getTime() - self.offsetDiff;
657
+ };
658
+
659
+ self.toLocaleDateString = function() {
660
+ return self.date.toLocaleDateString();
661
+ };
662
+
663
+ self.getFullYear = function() {
664
+ return self.date.getFullYear();
665
+ };
666
+
667
+ self.getMonth = function() {
668
+ return self.date.getMonth();
669
+ };
670
+
671
+ self.getDate = function() {
672
+ return self.date.getDate();
673
+ };
674
+
675
+ self.getHours = function() {
676
+ return self.date.getHours();
677
+ };
678
+
679
+ self.getMinutes = function() {
680
+ return self.date.getMinutes();
681
+ };
682
+
683
+ self.getSeconds = function() {
684
+ return self.date.getSeconds();
685
+ };
686
+
687
+ self.getMilliseconds = function() {
688
+ return self.date.getMilliseconds();
689
+ };
690
+
691
+ self.getTimezoneOffset = function() {
692
+ return offset * 60;
693
+ };
694
+
695
+ self.getUTCFullYear = function() {
696
+ return self.origDate.getUTCFullYear();
697
+ };
698
+
699
+ self.getUTCMonth = function() {
700
+ return self.origDate.getUTCMonth();
701
+ };
702
+
703
+ self.getUTCDate = function() {
704
+ return self.origDate.getUTCDate();
705
+ };
706
+
707
+ self.getUTCHours = function() {
708
+ return self.origDate.getUTCHours();
709
+ };
710
+
711
+ self.getUTCMinutes = function() {
712
+ return self.origDate.getUTCMinutes();
713
+ };
714
+
715
+ self.getUTCSeconds = function() {
716
+ return self.origDate.getUTCSeconds();
717
+ };
718
+
719
+ self.getUTCMilliseconds = function() {
720
+ return self.origDate.getUTCMilliseconds();
721
+ };
722
+
723
+ self.getDay = function() {
724
+ return self.date.getDay();
725
+ };
726
+
727
+ // provide this method only on browsers that already have it
728
+ if (self.toISOString) {
729
+ self.toISOString = function() {
730
+ return padNumberInMock(self.origDate.getUTCFullYear(), 4) + '-' +
731
+ padNumberInMock(self.origDate.getUTCMonth() + 1, 2) + '-' +
732
+ padNumberInMock(self.origDate.getUTCDate(), 2) + 'T' +
733
+ padNumberInMock(self.origDate.getUTCHours(), 2) + ':' +
734
+ padNumberInMock(self.origDate.getUTCMinutes(), 2) + ':' +
735
+ padNumberInMock(self.origDate.getUTCSeconds(), 2) + '.' +
736
+ padNumberInMock(self.origDate.getUTCMilliseconds(), 3) + 'Z';
737
+ };
738
+ }
739
+
740
+ //hide all methods not implemented in this mock that the Date prototype exposes
741
+ var unimplementedMethods = ['getUTCDay',
742
+ 'getYear', 'setDate', 'setFullYear', 'setHours', 'setMilliseconds',
743
+ 'setMinutes', 'setMonth', 'setSeconds', 'setTime', 'setUTCDate', 'setUTCFullYear',
744
+ 'setUTCHours', 'setUTCMilliseconds', 'setUTCMinutes', 'setUTCMonth', 'setUTCSeconds',
745
+ 'setYear', 'toDateString', 'toGMTString', 'toJSON', 'toLocaleFormat', 'toLocaleString',
746
+ 'toLocaleTimeString', 'toSource', 'toString', 'toTimeString', 'toUTCString', 'valueOf'];
747
+
748
+ angular.forEach(unimplementedMethods, function(methodName) {
749
+ self[methodName] = function() {
750
+ throw new Error("Method '" + methodName + "' is not implemented in the TzDate mock");
751
+ };
752
+ });
753
+
754
+ return self;
755
+ };
756
+
757
+ //make "tzDateInstance instanceof Date" return true
758
+ angular.mock.TzDate.prototype = Date.prototype;
759
+ /* jshint +W101 */
760
+
761
+
762
+ /**
763
+ * @ngdoc service
764
+ * @name $animate
765
+ *
766
+ * @description
767
+ * Mock implementation of the {@link ng.$animate `$animate`} service. Exposes two additional methods
768
+ * for testing animations.
769
+ */
770
+ angular.mock.animate = angular.module('ngAnimateMock', ['ng'])
771
+
772
+ .config(['$provide', function($provide) {
773
+
774
+ $provide.factory('$$forceReflow', function() {
775
+ function reflowFn() {
776
+ reflowFn.totalReflows++;
777
+ }
778
+ reflowFn.totalReflows = 0;
779
+ return reflowFn;
780
+ });
781
+
782
+ $provide.factory('$$animateAsyncRun', function() {
783
+ var queue = [];
784
+ var queueFn = function() {
785
+ return function(fn) {
786
+ queue.push(fn);
787
+ };
788
+ };
789
+ queueFn.flush = function() {
790
+ if (queue.length === 0) return false;
791
+
792
+ for (var i = 0; i < queue.length; i++) {
793
+ queue[i]();
794
+ }
795
+ queue = [];
796
+
797
+ return true;
798
+ };
799
+ return queueFn;
800
+ });
801
+
802
+ $provide.decorator('$$animateJs', ['$delegate', function($delegate) {
803
+ var runners = [];
804
+
805
+ var animateJsConstructor = function() {
806
+ var animator = $delegate.apply($delegate, arguments);
807
+ // If no javascript animation is found, animator is undefined
808
+ if (animator) {
809
+ runners.push(animator);
810
+ }
811
+ return animator;
812
+ };
813
+
814
+ animateJsConstructor.$closeAndFlush = function() {
815
+ runners.forEach(function(runner) {
816
+ runner.end();
817
+ });
818
+ runners = [];
819
+ };
820
+
821
+ return animateJsConstructor;
822
+ }]);
823
+
824
+ $provide.decorator('$animateCss', ['$delegate', function($delegate) {
825
+ var runners = [];
826
+
827
+ var animateCssConstructor = function(element, options) {
828
+ var animator = $delegate(element, options);
829
+ runners.push(animator);
830
+ return animator;
831
+ };
832
+
833
+ animateCssConstructor.$closeAndFlush = function() {
834
+ runners.forEach(function(runner) {
835
+ runner.end();
836
+ });
837
+ runners = [];
838
+ };
839
+
840
+ return animateCssConstructor;
841
+ }]);
842
+
843
+ $provide.decorator('$animate', ['$delegate', '$timeout', '$browser', '$$rAF', '$animateCss', '$$animateJs',
844
+ '$$forceReflow', '$$animateAsyncRun', '$rootScope',
845
+ function($delegate, $timeout, $browser, $$rAF, $animateCss, $$animateJs,
846
+ $$forceReflow, $$animateAsyncRun, $rootScope) {
847
+ var animate = {
848
+ queue: [],
849
+ cancel: $delegate.cancel,
850
+ on: $delegate.on,
851
+ off: $delegate.off,
852
+ pin: $delegate.pin,
853
+ get reflows() {
854
+ return $$forceReflow.totalReflows;
855
+ },
856
+ enabled: $delegate.enabled,
857
+ /**
858
+ * @ngdoc method
859
+ * @name $animate#closeAndFlush
860
+ * @description
861
+ *
862
+ * This method will close all pending animations (both {@link ngAnimate#javascript-based-animations Javascript}
863
+ * and {@link ngAnimate.$animateCss CSS}) and it will also flush any remaining animation frames and/or callbacks.
864
+ */
865
+ closeAndFlush: function() {
866
+ // we allow the flush command to swallow the errors
867
+ // because depending on whether CSS or JS animations are
868
+ // used, there may not be a RAF flush. The primary flush
869
+ // at the end of this function must throw an exception
870
+ // because it will track if there were pending animations
871
+ this.flush(true);
872
+ $animateCss.$closeAndFlush();
873
+ $$animateJs.$closeAndFlush();
874
+ this.flush();
875
+ },
876
+ /**
877
+ * @ngdoc method
878
+ * @name $animate#flush
879
+ * @description
880
+ *
881
+ * This method is used to flush the pending callbacks and animation frames to either start
882
+ * an animation or conclude an animation. Note that this will not actually close an
883
+ * actively running animation (see {@link ngMock.$animate#closeAndFlush `closeAndFlush()`} for that).
884
+ */
885
+ flush: function(hideErrors) {
886
+ $rootScope.$digest();
887
+
888
+ var doNextRun, somethingFlushed = false;
889
+ do {
890
+ doNextRun = false;
891
+
892
+ if ($$rAF.queue.length) {
893
+ $$rAF.flush();
894
+ doNextRun = somethingFlushed = true;
895
+ }
896
+
897
+ if ($$animateAsyncRun.flush()) {
898
+ doNextRun = somethingFlushed = true;
899
+ }
900
+ } while (doNextRun);
901
+
902
+ if (!somethingFlushed && !hideErrors) {
903
+ throw new Error('No pending animations ready to be closed or flushed');
904
+ }
905
+
906
+ $rootScope.$digest();
907
+ }
908
+ };
909
+
910
+ angular.forEach(
911
+ ['animate','enter','leave','move','addClass','removeClass','setClass'], function(method) {
912
+ animate[method] = function() {
913
+ animate.queue.push({
914
+ event: method,
915
+ element: arguments[0],
916
+ options: arguments[arguments.length - 1],
917
+ args: arguments
918
+ });
919
+ return $delegate[method].apply($delegate, arguments);
920
+ };
921
+ });
922
+
923
+ return animate;
924
+ }]);
925
+
926
+ }]);
927
+
928
+
929
+ /**
930
+ * @ngdoc function
931
+ * @name angular.mock.dump
932
+ * @description
933
+ *
934
+ * *NOTE*: this is not an injectable instance, just a globally available function.
935
+ *
936
+ * Method for serializing common angular objects (scope, elements, etc..) into strings, useful for
937
+ * debugging.
938
+ *
939
+ * This method is also available on window, where it can be used to display objects on debug
940
+ * console.
941
+ *
942
+ * @param {*} object - any object to turn into string.
943
+ * @return {string} a serialized string of the argument
944
+ */
945
+ angular.mock.dump = function(object) {
946
+ return serialize(object);
947
+
948
+ function serialize(object) {
949
+ var out;
950
+
951
+ if (angular.isElement(object)) {
952
+ object = angular.element(object);
953
+ out = angular.element('<div></div>');
954
+ angular.forEach(object, function(element) {
955
+ out.append(angular.element(element).clone());
956
+ });
957
+ out = out.html();
958
+ } else if (angular.isArray(object)) {
959
+ out = [];
960
+ angular.forEach(object, function(o) {
961
+ out.push(serialize(o));
962
+ });
963
+ out = '[ ' + out.join(', ') + ' ]';
964
+ } else if (angular.isObject(object)) {
965
+ if (angular.isFunction(object.$eval) && angular.isFunction(object.$apply)) {
966
+ out = serializeScope(object);
967
+ } else if (object instanceof Error) {
968
+ out = object.stack || ('' + object.name + ': ' + object.message);
969
+ } else {
970
+ // TODO(i): this prevents methods being logged,
971
+ // we should have a better way to serialize objects
972
+ out = angular.toJson(object, true);
973
+ }
974
+ } else {
975
+ out = String(object);
976
+ }
977
+
978
+ return out;
979
+ }
980
+
981
+ function serializeScope(scope, offset) {
982
+ offset = offset || ' ';
983
+ var log = [offset + 'Scope(' + scope.$id + '): {'];
984
+ for (var key in scope) {
985
+ if (Object.prototype.hasOwnProperty.call(scope, key) && !key.match(/^(\$|this)/)) {
986
+ log.push(' ' + key + ': ' + angular.toJson(scope[key]));
987
+ }
988
+ }
989
+ var child = scope.$$childHead;
990
+ while (child) {
991
+ log.push(serializeScope(child, offset + ' '));
992
+ child = child.$$nextSibling;
993
+ }
994
+ log.push('}');
995
+ return log.join('\n' + offset);
996
+ }
997
+ };
998
+
999
+ /**
1000
+ * @ngdoc service
1001
+ * @name $httpBackend
1002
+ * @description
1003
+ * Fake HTTP backend implementation suitable for unit testing applications that use the
1004
+ * {@link ng.$http $http service}.
1005
+ *
1006
+ * *Note*: For fake HTTP backend implementation suitable for end-to-end testing or backend-less
1007
+ * development please see {@link ngMockE2E.$httpBackend e2e $httpBackend mock}.
1008
+ *
1009
+ * During unit testing, we want our unit tests to run quickly and have no external dependencies so
1010
+ * we don’t want to send [XHR](https://developer.mozilla.org/en/xmlhttprequest) or
1011
+ * [JSONP](http://en.wikipedia.org/wiki/JSONP) requests to a real server. All we really need is
1012
+ * to verify whether a certain request has been sent or not, or alternatively just let the
1013
+ * application make requests, respond with pre-trained responses and assert that the end result is
1014
+ * what we expect it to be.
1015
+ *
1016
+ * This mock implementation can be used to respond with static or dynamic responses via the
1017
+ * `expect` and `when` apis and their shortcuts (`expectGET`, `whenPOST`, etc).
1018
+ *
1019
+ * When an Angular application needs some data from a server, it calls the $http service, which
1020
+ * sends the request to a real server using $httpBackend service. With dependency injection, it is
1021
+ * easy to inject $httpBackend mock (which has the same API as $httpBackend) and use it to verify
1022
+ * the requests and respond with some testing data without sending a request to a real server.
1023
+ *
1024
+ * There are two ways to specify what test data should be returned as http responses by the mock
1025
+ * backend when the code under test makes http requests:
1026
+ *
1027
+ * - `$httpBackend.expect` - specifies a request expectation
1028
+ * - `$httpBackend.when` - specifies a backend definition
1029
+ *
1030
+ *
1031
+ * ## Request Expectations vs Backend Definitions
1032
+ *
1033
+ * Request expectations provide a way to make assertions about requests made by the application and
1034
+ * to define responses for those requests. The test will fail if the expected requests are not made
1035
+ * or they are made in the wrong order.
1036
+ *
1037
+ * Backend definitions allow you to define a fake backend for your application which doesn't assert
1038
+ * if a particular request was made or not, it just returns a trained response if a request is made.
1039
+ * The test will pass whether or not the request gets made during testing.
1040
+ *
1041
+ *
1042
+ * <table class="table">
1043
+ * <tr><th width="220px"></th><th>Request expectations</th><th>Backend definitions</th></tr>
1044
+ * <tr>
1045
+ * <th>Syntax</th>
1046
+ * <td>.expect(...).respond(...)</td>
1047
+ * <td>.when(...).respond(...)</td>
1048
+ * </tr>
1049
+ * <tr>
1050
+ * <th>Typical usage</th>
1051
+ * <td>strict unit tests</td>
1052
+ * <td>loose (black-box) unit testing</td>
1053
+ * </tr>
1054
+ * <tr>
1055
+ * <th>Fulfills multiple requests</th>
1056
+ * <td>NO</td>
1057
+ * <td>YES</td>
1058
+ * </tr>
1059
+ * <tr>
1060
+ * <th>Order of requests matters</th>
1061
+ * <td>YES</td>
1062
+ * <td>NO</td>
1063
+ * </tr>
1064
+ * <tr>
1065
+ * <th>Request required</th>
1066
+ * <td>YES</td>
1067
+ * <td>NO</td>
1068
+ * </tr>
1069
+ * <tr>
1070
+ * <th>Response required</th>
1071
+ * <td>optional (see below)</td>
1072
+ * <td>YES</td>
1073
+ * </tr>
1074
+ * </table>
1075
+ *
1076
+ * In cases where both backend definitions and request expectations are specified during unit
1077
+ * testing, the request expectations are evaluated first.
1078
+ *
1079
+ * If a request expectation has no response specified, the algorithm will search your backend
1080
+ * definitions for an appropriate response.
1081
+ *
1082
+ * If a request didn't match any expectation or if the expectation doesn't have the response
1083
+ * defined, the backend definitions are evaluated in sequential order to see if any of them match
1084
+ * the request. The response from the first matched definition is returned.
1085
+ *
1086
+ *
1087
+ * ## Flushing HTTP requests
1088
+ *
1089
+ * The $httpBackend used in production always responds to requests asynchronously. If we preserved
1090
+ * this behavior in unit testing, we'd have to create async unit tests, which are hard to write,
1091
+ * to follow and to maintain. But neither can the testing mock respond synchronously; that would
1092
+ * change the execution of the code under test. For this reason, the mock $httpBackend has a
1093
+ * `flush()` method, which allows the test to explicitly flush pending requests. This preserves
1094
+ * the async api of the backend, while allowing the test to execute synchronously.
1095
+ *
1096
+ *
1097
+ * ## Unit testing with mock $httpBackend
1098
+ * The following code shows how to setup and use the mock backend when unit testing a controller.
1099
+ * First we create the controller under test:
1100
+ *
1101
+ ```js
1102
+ // The module code
1103
+ angular
1104
+ .module('MyApp', [])
1105
+ .controller('MyController', MyController);
1106
+
1107
+ // The controller code
1108
+ function MyController($scope, $http) {
1109
+ var authToken;
1110
+
1111
+ $http.get('/auth.py').then(function(response) {
1112
+ authToken = response.headers('A-Token');
1113
+ $scope.user = response.data;
1114
+ });
1115
+
1116
+ $scope.saveMessage = function(message) {
1117
+ var headers = { 'Authorization': authToken };
1118
+ $scope.status = 'Saving...';
1119
+
1120
+ $http.post('/add-msg.py', message, { headers: headers } ).then(function(response) {
1121
+ $scope.status = '';
1122
+ }).catch(function() {
1123
+ $scope.status = 'Failed...';
1124
+ });
1125
+ };
1126
+ }
1127
+ ```
1128
+ *
1129
+ * Now we setup the mock backend and create the test specs:
1130
+ *
1131
+ ```js
1132
+ // testing controller
1133
+ describe('MyController', function() {
1134
+ var $httpBackend, $rootScope, createController, authRequestHandler;
1135
+
1136
+ // Set up the module
1137
+ beforeEach(module('MyApp'));
1138
+
1139
+ beforeEach(inject(function($injector) {
1140
+ // Set up the mock http service responses
1141
+ $httpBackend = $injector.get('$httpBackend');
1142
+ // backend definition common for all tests
1143
+ authRequestHandler = $httpBackend.when('GET', '/auth.py')
1144
+ .respond({userId: 'userX'}, {'A-Token': 'xxx'});
1145
+
1146
+ // Get hold of a scope (i.e. the root scope)
1147
+ $rootScope = $injector.get('$rootScope');
1148
+ // The $controller service is used to create instances of controllers
1149
+ var $controller = $injector.get('$controller');
1150
+
1151
+ createController = function() {
1152
+ return $controller('MyController', {'$scope' : $rootScope });
1153
+ };
1154
+ }));
1155
+
1156
+
1157
+ afterEach(function() {
1158
+ $httpBackend.verifyNoOutstandingExpectation();
1159
+ $httpBackend.verifyNoOutstandingRequest();
1160
+ });
1161
+
1162
+
1163
+ it('should fetch authentication token', function() {
1164
+ $httpBackend.expectGET('/auth.py');
1165
+ var controller = createController();
1166
+ $httpBackend.flush();
1167
+ });
1168
+
1169
+
1170
+ it('should fail authentication', function() {
1171
+
1172
+ // Notice how you can change the response even after it was set
1173
+ authRequestHandler.respond(401, '');
1174
+
1175
+ $httpBackend.expectGET('/auth.py');
1176
+ var controller = createController();
1177
+ $httpBackend.flush();
1178
+ expect($rootScope.status).toBe('Failed...');
1179
+ });
1180
+
1181
+
1182
+ it('should send msg to server', function() {
1183
+ var controller = createController();
1184
+ $httpBackend.flush();
1185
+
1186
+ // now you don’t care about the authentication, but
1187
+ // the controller will still send the request and
1188
+ // $httpBackend will respond without you having to
1189
+ // specify the expectation and response for this request
1190
+
1191
+ $httpBackend.expectPOST('/add-msg.py', 'message content').respond(201, '');
1192
+ $rootScope.saveMessage('message content');
1193
+ expect($rootScope.status).toBe('Saving...');
1194
+ $httpBackend.flush();
1195
+ expect($rootScope.status).toBe('');
1196
+ });
1197
+
1198
+
1199
+ it('should send auth header', function() {
1200
+ var controller = createController();
1201
+ $httpBackend.flush();
1202
+
1203
+ $httpBackend.expectPOST('/add-msg.py', undefined, function(headers) {
1204
+ // check if the header was sent, if it wasn't the expectation won't
1205
+ // match the request and the test will fail
1206
+ return headers['Authorization'] == 'xxx';
1207
+ }).respond(201, '');
1208
+
1209
+ $rootScope.saveMessage('whatever');
1210
+ $httpBackend.flush();
1211
+ });
1212
+ });
1213
+ ```
1214
+ *
1215
+ * ## Dynamic responses
1216
+ *
1217
+ * You define a response to a request by chaining a call to `respond()` onto a definition or expectation.
1218
+ * If you provide a **callback** as the first parameter to `respond(callback)` then you can dynamically generate
1219
+ * a response based on the properties of the request.
1220
+ *
1221
+ * The `callback` function should be of the form `function(method, url, data, headers, params)`.
1222
+ *
1223
+ * ### Query parameters
1224
+ *
1225
+ * By default, query parameters on request URLs are parsed into the `params` object. So a request URL
1226
+ * of `/list?q=searchstr&orderby=-name` would set `params` to be `{q: 'searchstr', orderby: '-name'}`.
1227
+ *
1228
+ * ### Regex parameter matching
1229
+ *
1230
+ * If an expectation or definition uses a **regex** to match the URL, you can provide an array of **keys** via a
1231
+ * `params` argument. The index of each **key** in the array will match the index of a **group** in the
1232
+ * **regex**.
1233
+ *
1234
+ * The `params` object in the **callback** will now have properties with these keys, which hold the value of the
1235
+ * corresponding **group** in the **regex**.
1236
+ *
1237
+ * This also applies to the `when` and `expect` shortcut methods.
1238
+ *
1239
+ *
1240
+ * ```js
1241
+ * $httpBackend.expect('GET', /\/user\/(.+)/, undefined, undefined, ['id'])
1242
+ * .respond(function(method, url, data, headers, params) {
1243
+ * // for requested url of '/user/1234' params is {id: '1234'}
1244
+ * });
1245
+ *
1246
+ * $httpBackend.whenPATCH(/\/user\/(.+)\/article\/(.+)/, undefined, undefined, ['user', 'article'])
1247
+ * .respond(function(method, url, data, headers, params) {
1248
+ * // for url of '/user/1234/article/567' params is {user: '1234', article: '567'}
1249
+ * });
1250
+ * ```
1251
+ *
1252
+ * ## Matching route requests
1253
+ *
1254
+ * For extra convenience, `whenRoute` and `expectRoute` shortcuts are available. These methods offer colon
1255
+ * delimited matching of the url path, ignoring the query string. This allows declarations
1256
+ * similar to how application routes are configured with `$routeProvider`. Because these methods convert
1257
+ * the definition url to regex, declaration order is important. Combined with query parameter parsing,
1258
+ * the following is possible:
1259
+ *
1260
+ ```js
1261
+ $httpBackend.whenRoute('GET', '/users/:id')
1262
+ .respond(function(method, url, data, headers, params) {
1263
+ return [200, MockUserList[Number(params.id)]];
1264
+ });
1265
+
1266
+ $httpBackend.whenRoute('GET', '/users')
1267
+ .respond(function(method, url, data, headers, params) {
1268
+ var userList = angular.copy(MockUserList),
1269
+ defaultSort = 'lastName',
1270
+ count, pages, isPrevious, isNext;
1271
+
1272
+ // paged api response '/v1/users?page=2'
1273
+ params.page = Number(params.page) || 1;
1274
+
1275
+ // query for last names '/v1/users?q=Archer'
1276
+ if (params.q) {
1277
+ userList = $filter('filter')({lastName: params.q});
1278
+ }
1279
+
1280
+ pages = Math.ceil(userList.length / pagingLength);
1281
+ isPrevious = params.page > 1;
1282
+ isNext = params.page < pages;
1283
+
1284
+ return [200, {
1285
+ count: userList.length,
1286
+ previous: isPrevious,
1287
+ next: isNext,
1288
+ // sort field -> '/v1/users?sortBy=firstName'
1289
+ results: $filter('orderBy')(userList, params.sortBy || defaultSort)
1290
+ .splice((params.page - 1) * pagingLength, pagingLength)
1291
+ }];
1292
+ });
1293
+ ```
1294
+ */
1295
+ angular.mock.$HttpBackendProvider = function() {
1296
+ this.$get = ['$rootScope', '$timeout', createHttpBackendMock];
1297
+ };
1298
+
1299
+ /**
1300
+ * General factory function for $httpBackend mock.
1301
+ * Returns instance for unit testing (when no arguments specified):
1302
+ * - passing through is disabled
1303
+ * - auto flushing is disabled
1304
+ *
1305
+ * Returns instance for e2e testing (when `$delegate` and `$browser` specified):
1306
+ * - passing through (delegating request to real backend) is enabled
1307
+ * - auto flushing is enabled
1308
+ *
1309
+ * @param {Object=} $delegate Real $httpBackend instance (allow passing through if specified)
1310
+ * @param {Object=} $browser Auto-flushing enabled if specified
1311
+ * @return {Object} Instance of $httpBackend mock
1312
+ */
1313
+ function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) {
1314
+ var definitions = [],
1315
+ expectations = [],
1316
+ responses = [],
1317
+ responsesPush = angular.bind(responses, responses.push),
1318
+ copy = angular.copy;
1319
+
1320
+ function createResponse(status, data, headers, statusText) {
1321
+ if (angular.isFunction(status)) return status;
1322
+
1323
+ return function() {
1324
+ return angular.isNumber(status)
1325
+ ? [status, data, headers, statusText]
1326
+ : [200, status, data, headers];
1327
+ };
1328
+ }
1329
+
1330
+ // TODO(vojta): change params to: method, url, data, headers, callback
1331
+ function $httpBackend(method, url, data, callback, headers, timeout, withCredentials, responseType) {
1332
+
1333
+ var xhr = new MockXhr(),
1334
+ expectation = expectations[0],
1335
+ wasExpected = false;
1336
+
1337
+ function prettyPrint(data) {
1338
+ return (angular.isString(data) || angular.isFunction(data) || data instanceof RegExp)
1339
+ ? data
1340
+ : angular.toJson(data);
1341
+ }
1342
+
1343
+ function wrapResponse(wrapped) {
1344
+ if (!$browser && timeout) {
1345
+ timeout.then ? timeout.then(handleTimeout) : $timeout(handleTimeout, timeout);
1346
+ }
1347
+
1348
+ return handleResponse;
1349
+
1350
+ function handleResponse() {
1351
+ var response = wrapped.response(method, url, data, headers, wrapped.params(url));
1352
+ xhr.$$respHeaders = response[2];
1353
+ callback(copy(response[0]), copy(response[1]), xhr.getAllResponseHeaders(),
1354
+ copy(response[3] || ''));
1355
+ }
1356
+
1357
+ function handleTimeout() {
1358
+ for (var i = 0, ii = responses.length; i < ii; i++) {
1359
+ if (responses[i] === handleResponse) {
1360
+ responses.splice(i, 1);
1361
+ callback(-1, undefined, '');
1362
+ break;
1363
+ }
1364
+ }
1365
+ }
1366
+ }
1367
+
1368
+ if (expectation && expectation.match(method, url)) {
1369
+ if (!expectation.matchData(data)) {
1370
+ throw new Error('Expected ' + expectation + ' with different data\n' +
1371
+ 'EXPECTED: ' + prettyPrint(expectation.data) + '\nGOT: ' + data);
1372
+ }
1373
+
1374
+ if (!expectation.matchHeaders(headers)) {
1375
+ throw new Error('Expected ' + expectation + ' with different headers\n' +
1376
+ 'EXPECTED: ' + prettyPrint(expectation.headers) + '\nGOT: ' +
1377
+ prettyPrint(headers));
1378
+ }
1379
+
1380
+ expectations.shift();
1381
+
1382
+ if (expectation.response) {
1383
+ responses.push(wrapResponse(expectation));
1384
+ return;
1385
+ }
1386
+ wasExpected = true;
1387
+ }
1388
+
1389
+ var i = -1, definition;
1390
+ while ((definition = definitions[++i])) {
1391
+ if (definition.match(method, url, data, headers || {})) {
1392
+ if (definition.response) {
1393
+ // if $browser specified, we do auto flush all requests
1394
+ ($browser ? $browser.defer : responsesPush)(wrapResponse(definition));
1395
+ } else if (definition.passThrough) {
1396
+ $delegate(method, url, data, callback, headers, timeout, withCredentials, responseType);
1397
+ } else throw new Error('No response defined !');
1398
+ return;
1399
+ }
1400
+ }
1401
+ throw wasExpected ?
1402
+ new Error('No response defined !') :
1403
+ new Error('Unexpected request: ' + method + ' ' + url + '\n' +
1404
+ (expectation ? 'Expected ' + expectation : 'No more request expected'));
1405
+ }
1406
+
1407
+ /**
1408
+ * @ngdoc method
1409
+ * @name $httpBackend#when
1410
+ * @description
1411
+ * Creates a new backend definition.
1412
+ *
1413
+ * @param {string} method HTTP method.
1414
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
1415
+ * and returns true if the url matches the current definition.
1416
+ * @param {(string|RegExp|function(string))=} data HTTP request body or function that receives
1417
+ * data string and returns true if the data is as expected.
1418
+ * @param {(Object|function(Object))=} headers HTTP headers or function that receives http header
1419
+ * object and returns true if the headers match the current definition.
1420
+ * @param {(Array)=} keys Array of keys to assign to regex matches in request url described above.
1421
+ * @returns {requestHandler} Returns an object with `respond` method that controls how a matched
1422
+ * request is handled. You can save this object for later use and invoke `respond` again in
1423
+ * order to change how a matched request is handled.
1424
+ *
1425
+ * - respond –
1426
+ * `{function([status,] data[, headers, statusText])
1427
+ * | function(function(method, url, data, headers, params)}`
1428
+ * – The respond method takes a set of static data to be returned or a function that can
1429
+ * return an array containing response status (number), response data (string), response
1430
+ * headers (Object), and the text for the status (string). The respond method returns the
1431
+ * `requestHandler` object for possible overrides.
1432
+ */
1433
+ $httpBackend.when = function(method, url, data, headers, keys) {
1434
+ var definition = new MockHttpExpectation(method, url, data, headers, keys),
1435
+ chain = {
1436
+ respond: function(status, data, headers, statusText) {
1437
+ definition.passThrough = undefined;
1438
+ definition.response = createResponse(status, data, headers, statusText);
1439
+ return chain;
1440
+ }
1441
+ };
1442
+
1443
+ if ($browser) {
1444
+ chain.passThrough = function() {
1445
+ definition.response = undefined;
1446
+ definition.passThrough = true;
1447
+ return chain;
1448
+ };
1449
+ }
1450
+
1451
+ definitions.push(definition);
1452
+ return chain;
1453
+ };
1454
+
1455
+ /**
1456
+ * @ngdoc method
1457
+ * @name $httpBackend#whenGET
1458
+ * @description
1459
+ * Creates a new backend definition for GET requests. For more info see `when()`.
1460
+ *
1461
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
1462
+ * and returns true if the url matches the current definition.
1463
+ * @param {(Object|function(Object))=} headers HTTP headers.
1464
+ * @param {(Array)=} keys Array of keys to assign to regex matches in request url described above.
1465
+ * @returns {requestHandler} Returns an object with `respond` method that controls how a matched
1466
+ * request is handled. You can save this object for later use and invoke `respond` again in
1467
+ * order to change how a matched request is handled.
1468
+ */
1469
+
1470
+ /**
1471
+ * @ngdoc method
1472
+ * @name $httpBackend#whenHEAD
1473
+ * @description
1474
+ * Creates a new backend definition for HEAD requests. For more info see `when()`.
1475
+ *
1476
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
1477
+ * and returns true if the url matches the current definition.
1478
+ * @param {(Object|function(Object))=} headers HTTP headers.
1479
+ * @param {(Array)=} keys Array of keys to assign to regex matches in request url described above.
1480
+ * @returns {requestHandler} Returns an object with `respond` method that controls how a matched
1481
+ * request is handled. You can save this object for later use and invoke `respond` again in
1482
+ * order to change how a matched request is handled.
1483
+ */
1484
+
1485
+ /**
1486
+ * @ngdoc method
1487
+ * @name $httpBackend#whenDELETE
1488
+ * @description
1489
+ * Creates a new backend definition for DELETE requests. For more info see `when()`.
1490
+ *
1491
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
1492
+ * and returns true if the url matches the current definition.
1493
+ * @param {(Object|function(Object))=} headers HTTP headers.
1494
+ * @param {(Array)=} keys Array of keys to assign to regex matches in request url described above.
1495
+ * @returns {requestHandler} Returns an object with `respond` method that controls how a matched
1496
+ * request is handled. You can save this object for later use and invoke `respond` again in
1497
+ * order to change how a matched request is handled.
1498
+ */
1499
+
1500
+ /**
1501
+ * @ngdoc method
1502
+ * @name $httpBackend#whenPOST
1503
+ * @description
1504
+ * Creates a new backend definition for POST requests. For more info see `when()`.
1505
+ *
1506
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
1507
+ * and returns true if the url matches the current definition.
1508
+ * @param {(string|RegExp|function(string))=} data HTTP request body or function that receives
1509
+ * data string and returns true if the data is as expected.
1510
+ * @param {(Object|function(Object))=} headers HTTP headers.
1511
+ * @param {(Array)=} keys Array of keys to assign to regex matches in request url described above.
1512
+ * @returns {requestHandler} Returns an object with `respond` method that controls how a matched
1513
+ * request is handled. You can save this object for later use and invoke `respond` again in
1514
+ * order to change how a matched request is handled.
1515
+ */
1516
+
1517
+ /**
1518
+ * @ngdoc method
1519
+ * @name $httpBackend#whenPUT
1520
+ * @description
1521
+ * Creates a new backend definition for PUT requests. For more info see `when()`.
1522
+ *
1523
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
1524
+ * and returns true if the url matches the current definition.
1525
+ * @param {(string|RegExp|function(string))=} data HTTP request body or function that receives
1526
+ * data string and returns true if the data is as expected.
1527
+ * @param {(Object|function(Object))=} headers HTTP headers.
1528
+ * @param {(Array)=} keys Array of keys to assign to regex matches in request url described above.
1529
+ * @returns {requestHandler} Returns an object with `respond` method that controls how a matched
1530
+ * request is handled. You can save this object for later use and invoke `respond` again in
1531
+ * order to change how a matched request is handled.
1532
+ */
1533
+
1534
+ /**
1535
+ * @ngdoc method
1536
+ * @name $httpBackend#whenJSONP
1537
+ * @description
1538
+ * Creates a new backend definition for JSONP requests. For more info see `when()`.
1539
+ *
1540
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
1541
+ * and returns true if the url matches the current definition.
1542
+ * @param {(Array)=} keys Array of keys to assign to regex matches in request url described above.
1543
+ * @returns {requestHandler} Returns an object with `respond` method that controls how a matched
1544
+ * request is handled. You can save this object for later use and invoke `respond` again in
1545
+ * order to change how a matched request is handled.
1546
+ */
1547
+ createShortMethods('when');
1548
+
1549
+ /**
1550
+ * @ngdoc method
1551
+ * @name $httpBackend#whenRoute
1552
+ * @description
1553
+ * Creates a new backend definition that compares only with the requested route.
1554
+ *
1555
+ * @param {string} method HTTP method.
1556
+ * @param {string} url HTTP url string that supports colon param matching.
1557
+ * @returns {requestHandler} Returns an object with `respond` method that controls how a matched
1558
+ * request is handled. You can save this object for later use and invoke `respond` again in
1559
+ * order to change how a matched request is handled. See #when for more info.
1560
+ */
1561
+ $httpBackend.whenRoute = function(method, url) {
1562
+ var pathObj = parseRoute(url);
1563
+ return $httpBackend.when(method, pathObj.regexp, undefined, undefined, pathObj.keys);
1564
+ };
1565
+
1566
+ function parseRoute(url) {
1567
+ var ret = {
1568
+ regexp: url
1569
+ },
1570
+ keys = ret.keys = [];
1571
+
1572
+ if (!url || !angular.isString(url)) return ret;
1573
+
1574
+ url = url
1575
+ .replace(/([().])/g, '\\$1')
1576
+ .replace(/(\/)?:(\w+)([\?\*])?/g, function(_, slash, key, option) {
1577
+ var optional = option === '?' ? option : null;
1578
+ var star = option === '*' ? option : null;
1579
+ keys.push({ name: key, optional: !!optional });
1580
+ slash = slash || '';
1581
+ return ''
1582
+ + (optional ? '' : slash)
1583
+ + '(?:'
1584
+ + (optional ? slash : '')
1585
+ + (star && '(.+?)' || '([^/]+)')
1586
+ + (optional || '')
1587
+ + ')'
1588
+ + (optional || '');
1589
+ })
1590
+ .replace(/([\/$\*])/g, '\\$1');
1591
+
1592
+ ret.regexp = new RegExp('^' + url, 'i');
1593
+ return ret;
1594
+ }
1595
+
1596
+ /**
1597
+ * @ngdoc method
1598
+ * @name $httpBackend#expect
1599
+ * @description
1600
+ * Creates a new request expectation.
1601
+ *
1602
+ * @param {string} method HTTP method.
1603
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
1604
+ * and returns true if the url matches the current definition.
1605
+ * @param {(string|RegExp|function(string)|Object)=} data HTTP request body or function that
1606
+ * receives data string and returns true if the data is as expected, or Object if request body
1607
+ * is in JSON format.
1608
+ * @param {(Object|function(Object))=} headers HTTP headers or function that receives http header
1609
+ * object and returns true if the headers match the current expectation.
1610
+ * @param {(Array)=} keys Array of keys to assign to regex matches in request url described above.
1611
+ * @returns {requestHandler} Returns an object with `respond` method that controls how a matched
1612
+ * request is handled. You can save this object for later use and invoke `respond` again in
1613
+ * order to change how a matched request is handled.
1614
+ *
1615
+ * - respond –
1616
+ * `{function([status,] data[, headers, statusText])
1617
+ * | function(function(method, url, data, headers, params)}`
1618
+ * – The respond method takes a set of static data to be returned or a function that can
1619
+ * return an array containing response status (number), response data (string), response
1620
+ * headers (Object), and the text for the status (string). The respond method returns the
1621
+ * `requestHandler` object for possible overrides.
1622
+ */
1623
+ $httpBackend.expect = function(method, url, data, headers, keys) {
1624
+ var expectation = new MockHttpExpectation(method, url, data, headers, keys),
1625
+ chain = {
1626
+ respond: function(status, data, headers, statusText) {
1627
+ expectation.response = createResponse(status, data, headers, statusText);
1628
+ return chain;
1629
+ }
1630
+ };
1631
+
1632
+ expectations.push(expectation);
1633
+ return chain;
1634
+ };
1635
+
1636
+ /**
1637
+ * @ngdoc method
1638
+ * @name $httpBackend#expectGET
1639
+ * @description
1640
+ * Creates a new request expectation for GET requests. For more info see `expect()`.
1641
+ *
1642
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
1643
+ * and returns true if the url matches the current definition.
1644
+ * @param {Object=} headers HTTP headers.
1645
+ * @param {(Array)=} keys Array of keys to assign to regex matches in request url described above.
1646
+ * @returns {requestHandler} Returns an object with `respond` method that controls how a matched
1647
+ * request is handled. You can save this object for later use and invoke `respond` again in
1648
+ * order to change how a matched request is handled. See #expect for more info.
1649
+ */
1650
+
1651
+ /**
1652
+ * @ngdoc method
1653
+ * @name $httpBackend#expectHEAD
1654
+ * @description
1655
+ * Creates a new request expectation for HEAD requests. For more info see `expect()`.
1656
+ *
1657
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
1658
+ * and returns true if the url matches the current definition.
1659
+ * @param {Object=} headers HTTP headers.
1660
+ * @param {(Array)=} keys Array of keys to assign to regex matches in request url described above.
1661
+ * @returns {requestHandler} Returns an object with `respond` method that controls how a matched
1662
+ * request is handled. You can save this object for later use and invoke `respond` again in
1663
+ * order to change how a matched request is handled.
1664
+ */
1665
+
1666
+ /**
1667
+ * @ngdoc method
1668
+ * @name $httpBackend#expectDELETE
1669
+ * @description
1670
+ * Creates a new request expectation for DELETE requests. For more info see `expect()`.
1671
+ *
1672
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
1673
+ * and returns true if the url matches the current definition.
1674
+ * @param {Object=} headers HTTP headers.
1675
+ * @param {(Array)=} keys Array of keys to assign to regex matches in request url described above.
1676
+ * @returns {requestHandler} Returns an object with `respond` method that controls how a matched
1677
+ * request is handled. You can save this object for later use and invoke `respond` again in
1678
+ * order to change how a matched request is handled.
1679
+ */
1680
+
1681
+ /**
1682
+ * @ngdoc method
1683
+ * @name $httpBackend#expectPOST
1684
+ * @description
1685
+ * Creates a new request expectation for POST requests. For more info see `expect()`.
1686
+ *
1687
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
1688
+ * and returns true if the url matches the current definition.
1689
+ * @param {(string|RegExp|function(string)|Object)=} data HTTP request body or function that
1690
+ * receives data string and returns true if the data is as expected, or Object if request body
1691
+ * is in JSON format.
1692
+ * @param {Object=} headers HTTP headers.
1693
+ * @param {(Array)=} keys Array of keys to assign to regex matches in request url described above.
1694
+ * @returns {requestHandler} Returns an object with `respond` method that controls how a matched
1695
+ * request is handled. You can save this object for later use and invoke `respond` again in
1696
+ * order to change how a matched request is handled.
1697
+ */
1698
+
1699
+ /**
1700
+ * @ngdoc method
1701
+ * @name $httpBackend#expectPUT
1702
+ * @description
1703
+ * Creates a new request expectation for PUT requests. For more info see `expect()`.
1704
+ *
1705
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
1706
+ * and returns true if the url matches the current definition.
1707
+ * @param {(string|RegExp|function(string)|Object)=} data HTTP request body or function that
1708
+ * receives data string and returns true if the data is as expected, or Object if request body
1709
+ * is in JSON format.
1710
+ * @param {Object=} headers HTTP headers.
1711
+ * @param {(Array)=} keys Array of keys to assign to regex matches in request url described above.
1712
+ * @returns {requestHandler} Returns an object with `respond` method that controls how a matched
1713
+ * request is handled. You can save this object for later use and invoke `respond` again in
1714
+ * order to change how a matched request is handled.
1715
+ */
1716
+
1717
+ /**
1718
+ * @ngdoc method
1719
+ * @name $httpBackend#expectPATCH
1720
+ * @description
1721
+ * Creates a new request expectation for PATCH requests. For more info see `expect()`.
1722
+ *
1723
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
1724
+ * and returns true if the url matches the current definition.
1725
+ * @param {(string|RegExp|function(string)|Object)=} data HTTP request body or function that
1726
+ * receives data string and returns true if the data is as expected, or Object if request body
1727
+ * is in JSON format.
1728
+ * @param {Object=} headers HTTP headers.
1729
+ * @param {(Array)=} keys Array of keys to assign to regex matches in request url described above.
1730
+ * @returns {requestHandler} Returns an object with `respond` method that controls how a matched
1731
+ * request is handled. You can save this object for later use and invoke `respond` again in
1732
+ * order to change how a matched request is handled.
1733
+ */
1734
+
1735
+ /**
1736
+ * @ngdoc method
1737
+ * @name $httpBackend#expectJSONP
1738
+ * @description
1739
+ * Creates a new request expectation for JSONP requests. For more info see `expect()`.
1740
+ *
1741
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives an url
1742
+ * and returns true if the url matches the current definition.
1743
+ * @param {(Array)=} keys Array of keys to assign to regex matches in request url described above.
1744
+ * @returns {requestHandler} Returns an object with `respond` method that controls how a matched
1745
+ * request is handled. You can save this object for later use and invoke `respond` again in
1746
+ * order to change how a matched request is handled.
1747
+ */
1748
+ createShortMethods('expect');
1749
+
1750
+ /**
1751
+ * @ngdoc method
1752
+ * @name $httpBackend#expectRoute
1753
+ * @description
1754
+ * Creates a new request expectation that compares only with the requested route.
1755
+ *
1756
+ * @param {string} method HTTP method.
1757
+ * @param {string} url HTTP url string that supports colon param matching.
1758
+ * @returns {requestHandler} Returns an object with `respond` method that controls how a matched
1759
+ * request is handled. You can save this object for later use and invoke `respond` again in
1760
+ * order to change how a matched request is handled. See #expect for more info.
1761
+ */
1762
+ $httpBackend.expectRoute = function(method, url) {
1763
+ var pathObj = parseRoute(url);
1764
+ return $httpBackend.expect(method, pathObj.regexp, undefined, undefined, pathObj.keys);
1765
+ };
1766
+
1767
+
1768
+ /**
1769
+ * @ngdoc method
1770
+ * @name $httpBackend#flush
1771
+ * @description
1772
+ * Flushes all pending requests using the trained responses.
1773
+ *
1774
+ * @param {number=} count Number of responses to flush (in the order they arrived). If undefined,
1775
+ * all pending requests will be flushed. If there are no pending requests when the flush method
1776
+ * is called an exception is thrown (as this typically a sign of programming error).
1777
+ */
1778
+ $httpBackend.flush = function(count, digest) {
1779
+ if (digest !== false) $rootScope.$digest();
1780
+ if (!responses.length) throw new Error('No pending request to flush !');
1781
+
1782
+ if (angular.isDefined(count) && count !== null) {
1783
+ while (count--) {
1784
+ if (!responses.length) throw new Error('No more pending request to flush !');
1785
+ responses.shift()();
1786
+ }
1787
+ } else {
1788
+ while (responses.length) {
1789
+ responses.shift()();
1790
+ }
1791
+ }
1792
+ $httpBackend.verifyNoOutstandingExpectation(digest);
1793
+ };
1794
+
1795
+
1796
+ /**
1797
+ * @ngdoc method
1798
+ * @name $httpBackend#verifyNoOutstandingExpectation
1799
+ * @description
1800
+ * Verifies that all of the requests defined via the `expect` api were made. If any of the
1801
+ * requests were not made, verifyNoOutstandingExpectation throws an exception.
1802
+ *
1803
+ * Typically, you would call this method following each test case that asserts requests using an
1804
+ * "afterEach" clause.
1805
+ *
1806
+ * ```js
1807
+ * afterEach($httpBackend.verifyNoOutstandingExpectation);
1808
+ * ```
1809
+ */
1810
+ $httpBackend.verifyNoOutstandingExpectation = function(digest) {
1811
+ if (digest !== false) $rootScope.$digest();
1812
+ if (expectations.length) {
1813
+ throw new Error('Unsatisfied requests: ' + expectations.join(', '));
1814
+ }
1815
+ };
1816
+
1817
+
1818
+ /**
1819
+ * @ngdoc method
1820
+ * @name $httpBackend#verifyNoOutstandingRequest
1821
+ * @description
1822
+ * Verifies that there are no outstanding requests that need to be flushed.
1823
+ *
1824
+ * Typically, you would call this method following each test case that asserts requests using an
1825
+ * "afterEach" clause.
1826
+ *
1827
+ * ```js
1828
+ * afterEach($httpBackend.verifyNoOutstandingRequest);
1829
+ * ```
1830
+ */
1831
+ $httpBackend.verifyNoOutstandingRequest = function() {
1832
+ if (responses.length) {
1833
+ throw new Error('Unflushed requests: ' + responses.length);
1834
+ }
1835
+ };
1836
+
1837
+
1838
+ /**
1839
+ * @ngdoc method
1840
+ * @name $httpBackend#resetExpectations
1841
+ * @description
1842
+ * Resets all request expectations, but preserves all backend definitions. Typically, you would
1843
+ * call resetExpectations during a multiple-phase test when you want to reuse the same instance of
1844
+ * $httpBackend mock.
1845
+ */
1846
+ $httpBackend.resetExpectations = function() {
1847
+ expectations.length = 0;
1848
+ responses.length = 0;
1849
+ };
1850
+
1851
+ return $httpBackend;
1852
+
1853
+
1854
+ function createShortMethods(prefix) {
1855
+ angular.forEach(['GET', 'DELETE', 'JSONP', 'HEAD'], function(method) {
1856
+ $httpBackend[prefix + method] = function(url, headers, keys) {
1857
+ return $httpBackend[prefix](method, url, undefined, headers, keys);
1858
+ };
1859
+ });
1860
+
1861
+ angular.forEach(['PUT', 'POST', 'PATCH'], function(method) {
1862
+ $httpBackend[prefix + method] = function(url, data, headers, keys) {
1863
+ return $httpBackend[prefix](method, url, data, headers, keys);
1864
+ };
1865
+ });
1866
+ }
1867
+ }
1868
+
1869
+ function MockHttpExpectation(method, url, data, headers, keys) {
1870
+
1871
+ this.data = data;
1872
+ this.headers = headers;
1873
+
1874
+ this.match = function(m, u, d, h) {
1875
+ if (method != m) return false;
1876
+ if (!this.matchUrl(u)) return false;
1877
+ if (angular.isDefined(d) && !this.matchData(d)) return false;
1878
+ if (angular.isDefined(h) && !this.matchHeaders(h)) return false;
1879
+ return true;
1880
+ };
1881
+
1882
+ this.matchUrl = function(u) {
1883
+ if (!url) return true;
1884
+ if (angular.isFunction(url.test)) return url.test(u);
1885
+ if (angular.isFunction(url)) return url(u);
1886
+ return url == u;
1887
+ };
1888
+
1889
+ this.matchHeaders = function(h) {
1890
+ if (angular.isUndefined(headers)) return true;
1891
+ if (angular.isFunction(headers)) return headers(h);
1892
+ return angular.equals(headers, h);
1893
+ };
1894
+
1895
+ this.matchData = function(d) {
1896
+ if (angular.isUndefined(data)) return true;
1897
+ if (data && angular.isFunction(data.test)) return data.test(d);
1898
+ if (data && angular.isFunction(data)) return data(d);
1899
+ if (data && !angular.isString(data)) {
1900
+ return angular.equals(angular.fromJson(angular.toJson(data)), angular.fromJson(d));
1901
+ }
1902
+ return data == d;
1903
+ };
1904
+
1905
+ this.toString = function() {
1906
+ return method + ' ' + url;
1907
+ };
1908
+
1909
+ this.params = function(u) {
1910
+ return angular.extend(parseQuery(), pathParams());
1911
+
1912
+ function pathParams() {
1913
+ var keyObj = {};
1914
+ if (!url || !angular.isFunction(url.test) || !keys || keys.length === 0) return keyObj;
1915
+
1916
+ var m = url.exec(u);
1917
+ if (!m) return keyObj;
1918
+ for (var i = 1, len = m.length; i < len; ++i) {
1919
+ var key = keys[i - 1];
1920
+ var val = m[i];
1921
+ if (key && val) {
1922
+ keyObj[key.name || key] = val;
1923
+ }
1924
+ }
1925
+
1926
+ return keyObj;
1927
+ }
1928
+
1929
+ function parseQuery() {
1930
+ var obj = {}, key_value, key,
1931
+ queryStr = u.indexOf('?') > -1
1932
+ ? u.substring(u.indexOf('?') + 1)
1933
+ : "";
1934
+
1935
+ angular.forEach(queryStr.split('&'), function(keyValue) {
1936
+ if (keyValue) {
1937
+ key_value = keyValue.replace(/\+/g,'%20').split('=');
1938
+ key = tryDecodeURIComponent(key_value[0]);
1939
+ if (angular.isDefined(key)) {
1940
+ var val = angular.isDefined(key_value[1]) ? tryDecodeURIComponent(key_value[1]) : true;
1941
+ if (!hasOwnProperty.call(obj, key)) {
1942
+ obj[key] = val;
1943
+ } else if (angular.isArray(obj[key])) {
1944
+ obj[key].push(val);
1945
+ } else {
1946
+ obj[key] = [obj[key],val];
1947
+ }
1948
+ }
1949
+ }
1950
+ });
1951
+ return obj;
1952
+ }
1953
+ function tryDecodeURIComponent(value) {
1954
+ try {
1955
+ return decodeURIComponent(value);
1956
+ } catch (e) {
1957
+ // Ignore any invalid uri component
1958
+ }
1959
+ }
1960
+ };
1961
+ }
1962
+
1963
+ function createMockXhr() {
1964
+ return new MockXhr();
1965
+ }
1966
+
1967
+ function MockXhr() {
1968
+
1969
+ // hack for testing $http, $httpBackend
1970
+ MockXhr.$$lastInstance = this;
1971
+
1972
+ this.open = function(method, url, async) {
1973
+ this.$$method = method;
1974
+ this.$$url = url;
1975
+ this.$$async = async;
1976
+ this.$$reqHeaders = {};
1977
+ this.$$respHeaders = {};
1978
+ };
1979
+
1980
+ this.send = function(data) {
1981
+ this.$$data = data;
1982
+ };
1983
+
1984
+ this.setRequestHeader = function(key, value) {
1985
+ this.$$reqHeaders[key] = value;
1986
+ };
1987
+
1988
+ this.getResponseHeader = function(name) {
1989
+ // the lookup must be case insensitive,
1990
+ // that's why we try two quick lookups first and full scan last
1991
+ var header = this.$$respHeaders[name];
1992
+ if (header) return header;
1993
+
1994
+ name = angular.lowercase(name);
1995
+ header = this.$$respHeaders[name];
1996
+ if (header) return header;
1997
+
1998
+ header = undefined;
1999
+ angular.forEach(this.$$respHeaders, function(headerVal, headerName) {
2000
+ if (!header && angular.lowercase(headerName) == name) header = headerVal;
2001
+ });
2002
+ return header;
2003
+ };
2004
+
2005
+ this.getAllResponseHeaders = function() {
2006
+ var lines = [];
2007
+
2008
+ angular.forEach(this.$$respHeaders, function(value, key) {
2009
+ lines.push(key + ': ' + value);
2010
+ });
2011
+ return lines.join('\n');
2012
+ };
2013
+
2014
+ this.abort = angular.noop;
2015
+ }
2016
+
2017
+
2018
+ /**
2019
+ * @ngdoc service
2020
+ * @name $timeout
2021
+ * @description
2022
+ *
2023
+ * This service is just a simple decorator for {@link ng.$timeout $timeout} service
2024
+ * that adds a "flush" and "verifyNoPendingTasks" methods.
2025
+ */
2026
+
2027
+ angular.mock.$TimeoutDecorator = ['$delegate', '$browser', function($delegate, $browser) {
2028
+
2029
+ /**
2030
+ * @ngdoc method
2031
+ * @name $timeout#flush
2032
+ * @description
2033
+ *
2034
+ * Flushes the queue of pending tasks.
2035
+ *
2036
+ * @param {number=} delay maximum timeout amount to flush up until
2037
+ */
2038
+ $delegate.flush = function(delay) {
2039
+ $browser.defer.flush(delay);
2040
+ };
2041
+
2042
+ /**
2043
+ * @ngdoc method
2044
+ * @name $timeout#verifyNoPendingTasks
2045
+ * @description
2046
+ *
2047
+ * Verifies that there are no pending tasks that need to be flushed.
2048
+ */
2049
+ $delegate.verifyNoPendingTasks = function() {
2050
+ if ($browser.deferredFns.length) {
2051
+ throw new Error('Deferred tasks to flush (' + $browser.deferredFns.length + '): ' +
2052
+ formatPendingTasksAsString($browser.deferredFns));
2053
+ }
2054
+ };
2055
+
2056
+ function formatPendingTasksAsString(tasks) {
2057
+ var result = [];
2058
+ angular.forEach(tasks, function(task) {
2059
+ result.push('{id: ' + task.id + ', ' + 'time: ' + task.time + '}');
2060
+ });
2061
+
2062
+ return result.join(', ');
2063
+ }
2064
+
2065
+ return $delegate;
2066
+ }];
2067
+
2068
+ angular.mock.$RAFDecorator = ['$delegate', function($delegate) {
2069
+ var rafFn = function(fn) {
2070
+ var index = rafFn.queue.length;
2071
+ rafFn.queue.push(fn);
2072
+ return function() {
2073
+ rafFn.queue.splice(index, 1);
2074
+ };
2075
+ };
2076
+
2077
+ rafFn.queue = [];
2078
+ rafFn.supported = $delegate.supported;
2079
+
2080
+ rafFn.flush = function() {
2081
+ if (rafFn.queue.length === 0) {
2082
+ throw new Error('No rAF callbacks present');
2083
+ }
2084
+
2085
+ var length = rafFn.queue.length;
2086
+ for (var i = 0; i < length; i++) {
2087
+ rafFn.queue[i]();
2088
+ }
2089
+
2090
+ rafFn.queue = rafFn.queue.slice(i);
2091
+ };
2092
+
2093
+ return rafFn;
2094
+ }];
2095
+
2096
+ /**
2097
+ *
2098
+ */
2099
+ var originalRootElement;
2100
+ angular.mock.$RootElementProvider = function() {
2101
+ this.$get = ['$injector', function($injector) {
2102
+ originalRootElement = angular.element('<div ng-app></div>').data('$injector', $injector);
2103
+ return originalRootElement;
2104
+ }];
2105
+ };
2106
+
2107
+ /**
2108
+ * @ngdoc service
2109
+ * @name $controller
2110
+ * @description
2111
+ * A decorator for {@link ng.$controller} with additional `bindings` parameter, useful when testing
2112
+ * controllers of directives that use {@link $compile#-bindtocontroller- `bindToController`}.
2113
+ *
2114
+ *
2115
+ * ## Example
2116
+ *
2117
+ * ```js
2118
+ *
2119
+ * // Directive definition ...
2120
+ *
2121
+ * myMod.directive('myDirective', {
2122
+ * controller: 'MyDirectiveController',
2123
+ * bindToController: {
2124
+ * name: '@'
2125
+ * }
2126
+ * });
2127
+ *
2128
+ *
2129
+ * // Controller definition ...
2130
+ *
2131
+ * myMod.controller('MyDirectiveController', ['$log', function($log) {
2132
+ * $log.info(this.name);
2133
+ * }]);
2134
+ *
2135
+ *
2136
+ * // In a test ...
2137
+ *
2138
+ * describe('myDirectiveController', function() {
2139
+ * it('should write the bound name to the log', inject(function($controller, $log) {
2140
+ * var ctrl = $controller('MyDirectiveController', { /* no locals &#42;/ }, { name: 'Clark Kent' });
2141
+ * expect(ctrl.name).toEqual('Clark Kent');
2142
+ * expect($log.info.logs).toEqual(['Clark Kent']);
2143
+ * }));
2144
+ * });
2145
+ *
2146
+ * ```
2147
+ *
2148
+ * @param {Function|string} constructor If called with a function then it's considered to be the
2149
+ * controller constructor function. Otherwise it's considered to be a string which is used
2150
+ * to retrieve the controller constructor using the following steps:
2151
+ *
2152
+ * * check if a controller with given name is registered via `$controllerProvider`
2153
+ * * check if evaluating the string on the current scope returns a constructor
2154
+ * * if $controllerProvider#allowGlobals, check `window[constructor]` on the global
2155
+ * `window` object (not recommended)
2156
+ *
2157
+ * The string can use the `controller as property` syntax, where the controller instance is published
2158
+ * as the specified property on the `scope`; the `scope` must be injected into `locals` param for this
2159
+ * to work correctly.
2160
+ *
2161
+ * @param {Object} locals Injection locals for Controller.
2162
+ * @param {Object=} bindings Properties to add to the controller before invoking the constructor. This is used
2163
+ * to simulate the `bindToController` feature and simplify certain kinds of tests.
2164
+ * @return {Object} Instance of given controller.
2165
+ */
2166
+ angular.mock.$ControllerDecorator = ['$delegate', function($delegate) {
2167
+ return function(expression, locals, later, ident) {
2168
+ if (later && typeof later === 'object') {
2169
+ var create = $delegate(expression, locals, true, ident);
2170
+ angular.extend(create.instance, later);
2171
+ return create();
2172
+ }
2173
+ return $delegate(expression, locals, later, ident);
2174
+ };
2175
+ }];
2176
+
2177
+ /**
2178
+ * @ngdoc service
2179
+ * @name $componentController
2180
+ * @description
2181
+ * A service that can be used to create instances of component controllers.
2182
+ * <div class="alert alert-info">
2183
+ * Be aware that the controller will be instantiated and attached to the scope as specified in
2184
+ * the component definition object. That means that you must always provide a `$scope` object
2185
+ * in the `locals` param.
2186
+ * </div>
2187
+ * @param {string} componentName the name of the component whose controller we want to instantiate
2188
+ * @param {Object} locals Injection locals for Controller.
2189
+ * @param {Object=} bindings Properties to add to the controller before invoking the constructor. This is used
2190
+ * to simulate the `bindToController` feature and simplify certain kinds of tests.
2191
+ * @param {string=} ident Override the property name to use when attaching the controller to the scope.
2192
+ * @return {Object} Instance of requested controller.
2193
+ */
2194
+ angular.mock.$ComponentControllerProvider = ['$compileProvider', function($compileProvider) {
2195
+ this.$get = ['$controller','$injector', function($controller,$injector) {
2196
+ return function $componentController(componentName, locals, bindings, ident) {
2197
+ // get all directives associated to the component name
2198
+ var directives = $injector.get(componentName + 'Directive');
2199
+ // look for those directives that are components
2200
+ var candidateDirectives = directives.filter(function(directiveInfo) {
2201
+ // components have controller, controllerAs and restrict:'E'
2202
+ return directiveInfo.controller && directiveInfo.controllerAs && directiveInfo.restrict === 'E';
2203
+ });
2204
+ // check if valid directives found
2205
+ if (candidateDirectives.length === 0) {
2206
+ throw new Error('No component found');
2207
+ }
2208
+ if (candidateDirectives.length > 1) {
2209
+ throw new Error('Too many components found');
2210
+ }
2211
+ // get the info of the component
2212
+ var directiveInfo = candidateDirectives[0];
2213
+ return $controller(directiveInfo.controller, locals, bindings, ident || directiveInfo.controllerAs);
2214
+ };
2215
+ }];
2216
+ }];
2217
+
2218
+
2219
+ /**
2220
+ * @ngdoc module
2221
+ * @name ngMock
2222
+ * @packageName angular-mocks
2223
+ * @description
2224
+ *
2225
+ * # ngMock
2226
+ *
2227
+ * The `ngMock` module provides support to inject and mock Angular services into unit tests.
2228
+ * In addition, ngMock also extends various core ng services such that they can be
2229
+ * inspected and controlled in a synchronous manner within test code.
2230
+ *
2231
+ *
2232
+ * <div doc-module-components="ngMock"></div>
2233
+ *
2234
+ */
2235
+ angular.module('ngMock', ['ng']).provider({
2236
+ $browser: angular.mock.$BrowserProvider,
2237
+ $exceptionHandler: angular.mock.$ExceptionHandlerProvider,
2238
+ $log: angular.mock.$LogProvider,
2239
+ $interval: angular.mock.$IntervalProvider,
2240
+ $httpBackend: angular.mock.$HttpBackendProvider,
2241
+ $rootElement: angular.mock.$RootElementProvider,
2242
+ $componentController: angular.mock.$ComponentControllerProvider
2243
+ }).config(['$provide', function($provide) {
2244
+ $provide.decorator('$timeout', angular.mock.$TimeoutDecorator);
2245
+ $provide.decorator('$$rAF', angular.mock.$RAFDecorator);
2246
+ $provide.decorator('$rootScope', angular.mock.$RootScopeDecorator);
2247
+ $provide.decorator('$controller', angular.mock.$ControllerDecorator);
2248
+ }]);
2249
+
2250
+ /**
2251
+ * @ngdoc module
2252
+ * @name ngMockE2E
2253
+ * @module ngMockE2E
2254
+ * @packageName angular-mocks
2255
+ * @description
2256
+ *
2257
+ * The `ngMockE2E` is an angular module which contains mocks suitable for end-to-end testing.
2258
+ * Currently there is only one mock present in this module -
2259
+ * the {@link ngMockE2E.$httpBackend e2e $httpBackend} mock.
2260
+ */
2261
+ angular.module('ngMockE2E', ['ng']).config(['$provide', function($provide) {
2262
+ $provide.decorator('$httpBackend', angular.mock.e2e.$httpBackendDecorator);
2263
+ }]);
2264
+
2265
+ /**
2266
+ * @ngdoc service
2267
+ * @name $httpBackend
2268
+ * @module ngMockE2E
2269
+ * @description
2270
+ * Fake HTTP backend implementation suitable for end-to-end testing or backend-less development of
2271
+ * applications that use the {@link ng.$http $http service}.
2272
+ *
2273
+ * *Note*: For fake http backend implementation suitable for unit testing please see
2274
+ * {@link ngMock.$httpBackend unit-testing $httpBackend mock}.
2275
+ *
2276
+ * This implementation can be used to respond with static or dynamic responses via the `when` api
2277
+ * and its shortcuts (`whenGET`, `whenPOST`, etc) and optionally pass through requests to the
2278
+ * real $httpBackend for specific requests (e.g. to interact with certain remote apis or to fetch
2279
+ * templates from a webserver).
2280
+ *
2281
+ * As opposed to unit-testing, in an end-to-end testing scenario or in scenario when an application
2282
+ * is being developed with the real backend api replaced with a mock, it is often desirable for
2283
+ * certain category of requests to bypass the mock and issue a real http request (e.g. to fetch
2284
+ * templates or static files from the webserver). To configure the backend with this behavior
2285
+ * use the `passThrough` request handler of `when` instead of `respond`.
2286
+ *
2287
+ * Additionally, we don't want to manually have to flush mocked out requests like we do during unit
2288
+ * testing. For this reason the e2e $httpBackend flushes mocked out requests
2289
+ * automatically, closely simulating the behavior of the XMLHttpRequest object.
2290
+ *
2291
+ * To setup the application to run with this http backend, you have to create a module that depends
2292
+ * on the `ngMockE2E` and your application modules and defines the fake backend:
2293
+ *
2294
+ * ```js
2295
+ * myAppDev = angular.module('myAppDev', ['myApp', 'ngMockE2E']);
2296
+ * myAppDev.run(function($httpBackend) {
2297
+ * phones = [{name: 'phone1'}, {name: 'phone2'}];
2298
+ *
2299
+ * // returns the current list of phones
2300
+ * $httpBackend.whenGET('/phones').respond(phones);
2301
+ *
2302
+ * // adds a new phone to the phones array
2303
+ * $httpBackend.whenPOST('/phones').respond(function(method, url, data) {
2304
+ * var phone = angular.fromJson(data);
2305
+ * phones.push(phone);
2306
+ * return [200, phone, {}];
2307
+ * });
2308
+ * $httpBackend.whenGET(/^\/templates\//).passThrough();
2309
+ * //...
2310
+ * });
2311
+ * ```
2312
+ *
2313
+ * Afterwards, bootstrap your app with this new module.
2314
+ */
2315
+
2316
+ /**
2317
+ * @ngdoc method
2318
+ * @name $httpBackend#when
2319
+ * @module ngMockE2E
2320
+ * @description
2321
+ * Creates a new backend definition.
2322
+ *
2323
+ * @param {string} method HTTP method.
2324
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
2325
+ * and returns true if the url matches the current definition.
2326
+ * @param {(string|RegExp)=} data HTTP request body.
2327
+ * @param {(Object|function(Object))=} headers HTTP headers or function that receives http header
2328
+ * object and returns true if the headers match the current definition.
2329
+ * @param {(Array)=} keys Array of keys to assign to regex matches in request url described on
2330
+ * {@link ngMock.$httpBackend $httpBackend mock}.
2331
+ * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
2332
+ * control how a matched request is handled. You can save this object for later use and invoke
2333
+ * `respond` or `passThrough` again in order to change how a matched request is handled.
2334
+ *
2335
+ * - respond –
2336
+ * `{function([status,] data[, headers, statusText])
2337
+ * | function(function(method, url, data, headers, params)}`
2338
+ * – The respond method takes a set of static data to be returned or a function that can return
2339
+ * an array containing response status (number), response data (string), response headers
2340
+ * (Object), and the text for the status (string).
2341
+ * - passThrough – `{function()}` – Any request matching a backend definition with
2342
+ * `passThrough` handler will be passed through to the real backend (an XHR request will be made
2343
+ * to the server.)
2344
+ * - Both methods return the `requestHandler` object for possible overrides.
2345
+ */
2346
+
2347
+ /**
2348
+ * @ngdoc method
2349
+ * @name $httpBackend#whenGET
2350
+ * @module ngMockE2E
2351
+ * @description
2352
+ * Creates a new backend definition for GET requests. For more info see `when()`.
2353
+ *
2354
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
2355
+ * and returns true if the url matches the current definition.
2356
+ * @param {(Object|function(Object))=} headers HTTP headers.
2357
+ * @param {(Array)=} keys Array of keys to assign to regex matches in request url described on
2358
+ * {@link ngMock.$httpBackend $httpBackend mock}.
2359
+ * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
2360
+ * control how a matched request is handled. You can save this object for later use and invoke
2361
+ * `respond` or `passThrough` again in order to change how a matched request is handled.
2362
+ */
2363
+
2364
+ /**
2365
+ * @ngdoc method
2366
+ * @name $httpBackend#whenHEAD
2367
+ * @module ngMockE2E
2368
+ * @description
2369
+ * Creates a new backend definition for HEAD requests. For more info see `when()`.
2370
+ *
2371
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
2372
+ * and returns true if the url matches the current definition.
2373
+ * @param {(Object|function(Object))=} headers HTTP headers.
2374
+ * @param {(Array)=} keys Array of keys to assign to regex matches in request url described on
2375
+ * {@link ngMock.$httpBackend $httpBackend mock}.
2376
+ * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
2377
+ * control how a matched request is handled. You can save this object for later use and invoke
2378
+ * `respond` or `passThrough` again in order to change how a matched request is handled.
2379
+ */
2380
+
2381
+ /**
2382
+ * @ngdoc method
2383
+ * @name $httpBackend#whenDELETE
2384
+ * @module ngMockE2E
2385
+ * @description
2386
+ * Creates a new backend definition for DELETE requests. For more info see `when()`.
2387
+ *
2388
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
2389
+ * and returns true if the url matches the current definition.
2390
+ * @param {(Object|function(Object))=} headers HTTP headers.
2391
+ * @param {(Array)=} keys Array of keys to assign to regex matches in request url described on
2392
+ * {@link ngMock.$httpBackend $httpBackend mock}.
2393
+ * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
2394
+ * control how a matched request is handled. You can save this object for later use and invoke
2395
+ * `respond` or `passThrough` again in order to change how a matched request is handled.
2396
+ */
2397
+
2398
+ /**
2399
+ * @ngdoc method
2400
+ * @name $httpBackend#whenPOST
2401
+ * @module ngMockE2E
2402
+ * @description
2403
+ * Creates a new backend definition for POST requests. For more info see `when()`.
2404
+ *
2405
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
2406
+ * and returns true if the url matches the current definition.
2407
+ * @param {(string|RegExp)=} data HTTP request body.
2408
+ * @param {(Object|function(Object))=} headers HTTP headers.
2409
+ * @param {(Array)=} keys Array of keys to assign to regex matches in request url described on
2410
+ * {@link ngMock.$httpBackend $httpBackend mock}.
2411
+ * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
2412
+ * control how a matched request is handled. You can save this object for later use and invoke
2413
+ * `respond` or `passThrough` again in order to change how a matched request is handled.
2414
+ */
2415
+
2416
+ /**
2417
+ * @ngdoc method
2418
+ * @name $httpBackend#whenPUT
2419
+ * @module ngMockE2E
2420
+ * @description
2421
+ * Creates a new backend definition for PUT requests. For more info see `when()`.
2422
+ *
2423
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
2424
+ * and returns true if the url matches the current definition.
2425
+ * @param {(string|RegExp)=} data HTTP request body.
2426
+ * @param {(Object|function(Object))=} headers HTTP headers.
2427
+ * @param {(Array)=} keys Array of keys to assign to regex matches in request url described on
2428
+ * {@link ngMock.$httpBackend $httpBackend mock}.
2429
+ * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
2430
+ * control how a matched request is handled. You can save this object for later use and invoke
2431
+ * `respond` or `passThrough` again in order to change how a matched request is handled.
2432
+ */
2433
+
2434
+ /**
2435
+ * @ngdoc method
2436
+ * @name $httpBackend#whenPATCH
2437
+ * @module ngMockE2E
2438
+ * @description
2439
+ * Creates a new backend definition for PATCH requests. For more info see `when()`.
2440
+ *
2441
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
2442
+ * and returns true if the url matches the current definition.
2443
+ * @param {(string|RegExp)=} data HTTP request body.
2444
+ * @param {(Object|function(Object))=} headers HTTP headers.
2445
+ * @param {(Array)=} keys Array of keys to assign to regex matches in request url described on
2446
+ * {@link ngMock.$httpBackend $httpBackend mock}.
2447
+ * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
2448
+ * control how a matched request is handled. You can save this object for later use and invoke
2449
+ * `respond` or `passThrough` again in order to change how a matched request is handled.
2450
+ */
2451
+
2452
+ /**
2453
+ * @ngdoc method
2454
+ * @name $httpBackend#whenJSONP
2455
+ * @module ngMockE2E
2456
+ * @description
2457
+ * Creates a new backend definition for JSONP requests. For more info see `when()`.
2458
+ *
2459
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
2460
+ * and returns true if the url matches the current definition.
2461
+ * @param {(Array)=} keys Array of keys to assign to regex matches in request url described on
2462
+ * {@link ngMock.$httpBackend $httpBackend mock}.
2463
+ * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
2464
+ * control how a matched request is handled. You can save this object for later use and invoke
2465
+ * `respond` or `passThrough` again in order to change how a matched request is handled.
2466
+ */
2467
+ /**
2468
+ * @ngdoc method
2469
+ * @name $httpBackend#whenRoute
2470
+ * @module ngMockE2E
2471
+ * @description
2472
+ * Creates a new backend definition that compares only with the requested route.
2473
+ *
2474
+ * @param {string} method HTTP method.
2475
+ * @param {string} url HTTP url string that supports colon param matching.
2476
+ * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
2477
+ * control how a matched request is handled. You can save this object for later use and invoke
2478
+ * `respond` or `passThrough` again in order to change how a matched request is handled.
2479
+ */
2480
+ angular.mock.e2e = {};
2481
+ angular.mock.e2e.$httpBackendDecorator =
2482
+ ['$rootScope', '$timeout', '$delegate', '$browser', createHttpBackendMock];
2483
+
2484
+
2485
+ /**
2486
+ * @ngdoc type
2487
+ * @name $rootScope.Scope
2488
+ * @module ngMock
2489
+ * @description
2490
+ * {@link ng.$rootScope.Scope Scope} type decorated with helper methods useful for testing. These
2491
+ * methods are automatically available on any {@link ng.$rootScope.Scope Scope} instance when
2492
+ * `ngMock` module is loaded.
2493
+ *
2494
+ * In addition to all the regular `Scope` methods, the following helper methods are available:
2495
+ */
2496
+ angular.mock.$RootScopeDecorator = ['$delegate', function($delegate) {
2497
+
2498
+ var $rootScopePrototype = Object.getPrototypeOf($delegate);
2499
+
2500
+ $rootScopePrototype.$countChildScopes = countChildScopes;
2501
+ $rootScopePrototype.$countWatchers = countWatchers;
2502
+
2503
+ return $delegate;
2504
+
2505
+ // ------------------------------------------------------------------------------------------ //
2506
+
2507
+ /**
2508
+ * @ngdoc method
2509
+ * @name $rootScope.Scope#$countChildScopes
2510
+ * @module ngMock
2511
+ * @description
2512
+ * Counts all the direct and indirect child scopes of the current scope.
2513
+ *
2514
+ * The current scope is excluded from the count. The count includes all isolate child scopes.
2515
+ *
2516
+ * @returns {number} Total number of child scopes.
2517
+ */
2518
+ function countChildScopes() {
2519
+ // jshint validthis: true
2520
+ var count = 0; // exclude the current scope
2521
+ var pendingChildHeads = [this.$$childHead];
2522
+ var currentScope;
2523
+
2524
+ while (pendingChildHeads.length) {
2525
+ currentScope = pendingChildHeads.shift();
2526
+
2527
+ while (currentScope) {
2528
+ count += 1;
2529
+ pendingChildHeads.push(currentScope.$$childHead);
2530
+ currentScope = currentScope.$$nextSibling;
2531
+ }
2532
+ }
2533
+
2534
+ return count;
2535
+ }
2536
+
2537
+
2538
+ /**
2539
+ * @ngdoc method
2540
+ * @name $rootScope.Scope#$countWatchers
2541
+ * @module ngMock
2542
+ * @description
2543
+ * Counts all the watchers of direct and indirect child scopes of the current scope.
2544
+ *
2545
+ * The watchers of the current scope are included in the count and so are all the watchers of
2546
+ * isolate child scopes.
2547
+ *
2548
+ * @returns {number} Total number of watchers.
2549
+ */
2550
+ function countWatchers() {
2551
+ // jshint validthis: true
2552
+ var count = this.$$watchers ? this.$$watchers.length : 0; // include the current scope
2553
+ var pendingChildHeads = [this.$$childHead];
2554
+ var currentScope;
2555
+
2556
+ while (pendingChildHeads.length) {
2557
+ currentScope = pendingChildHeads.shift();
2558
+
2559
+ while (currentScope) {
2560
+ count += currentScope.$$watchers ? currentScope.$$watchers.length : 0;
2561
+ pendingChildHeads.push(currentScope.$$childHead);
2562
+ currentScope = currentScope.$$nextSibling;
2563
+ }
2564
+ }
2565
+
2566
+ return count;
2567
+ }
2568
+ }];
2569
+
2570
+
2571
+ !(function(jasmineOrMocha) {
2572
+
2573
+ if (!jasmineOrMocha) {
2574
+ return;
2575
+ }
2576
+
2577
+ var currentSpec = null,
2578
+ injectorState = new InjectorState(),
2579
+ annotatedFunctions = [],
2580
+ wasInjectorCreated = function() {
2581
+ return !!currentSpec;
2582
+ };
2583
+
2584
+ angular.mock.$$annotate = angular.injector.$$annotate;
2585
+ angular.injector.$$annotate = function(fn) {
2586
+ if (typeof fn === 'function' && !fn.$inject) {
2587
+ annotatedFunctions.push(fn);
2588
+ }
2589
+ return angular.mock.$$annotate.apply(this, arguments);
2590
+ };
2591
+
2592
+ /**
2593
+ * @ngdoc function
2594
+ * @name angular.mock.module
2595
+ * @description
2596
+ *
2597
+ * *NOTE*: This function is also published on window for easy access.<br>
2598
+ * *NOTE*: This function is declared ONLY WHEN running tests with jasmine or mocha
2599
+ *
2600
+ * This function registers a module configuration code. It collects the configuration information
2601
+ * which will be used when the injector is created by {@link angular.mock.inject inject}.
2602
+ *
2603
+ * See {@link angular.mock.inject inject} for usage example
2604
+ *
2605
+ * @param {...(string|Function|Object)} fns any number of modules which are represented as string
2606
+ * aliases or as anonymous module initialization functions. The modules are used to
2607
+ * configure the injector. The 'ng' and 'ngMock' modules are automatically loaded. If an
2608
+ * object literal is passed each key-value pair will be registered on the module via
2609
+ * {@link auto.$provide $provide}.value, the key being the string name (or token) to associate
2610
+ * with the value on the injector.
2611
+ */
2612
+ var module = window.module = angular.mock.module = function() {
2613
+ var moduleFns = Array.prototype.slice.call(arguments, 0);
2614
+ return wasInjectorCreated() ? workFn() : workFn;
2615
+ /////////////////////
2616
+ function workFn() {
2617
+ if (currentSpec.$injector) {
2618
+ throw new Error('Injector already created, can not register a module!');
2619
+ } else {
2620
+ var fn, modules = currentSpec.$modules || (currentSpec.$modules = []);
2621
+ angular.forEach(moduleFns, function(module) {
2622
+ if (angular.isObject(module) && !angular.isArray(module)) {
2623
+ fn = ['$provide', function($provide) {
2624
+ angular.forEach(module, function(value, key) {
2625
+ $provide.value(key, value);
2626
+ });
2627
+ }];
2628
+ } else {
2629
+ fn = module;
2630
+ }
2631
+ if (currentSpec.$providerInjector) {
2632
+ currentSpec.$providerInjector.invoke(fn);
2633
+ } else {
2634
+ modules.push(fn);
2635
+ }
2636
+ });
2637
+ }
2638
+ }
2639
+ };
2640
+
2641
+ module.$$beforeAllHook = (window.before || window.beforeAll);
2642
+ module.$$afterAllHook = (window.after || window.afterAll);
2643
+
2644
+ // purely for testing ngMock itself
2645
+ module.$$currentSpec = function(to) {
2646
+ if (arguments.length === 0) return to;
2647
+ currentSpec = to;
2648
+ };
2649
+
2650
+ /**
2651
+ * @ngdoc function
2652
+ * @name angular.mock.module.sharedInjector
2653
+ * @description
2654
+ *
2655
+ * *NOTE*: This function is declared ONLY WHEN running tests with jasmine or mocha
2656
+ *
2657
+ * This function ensures a single injector will be used for all tests in a given describe context.
2658
+ * This contrasts with the default behaviour where a new injector is created per test case.
2659
+ *
2660
+ * Use sharedInjector when you want to take advantage of Jasmine's `beforeAll()`, or mocha's
2661
+ * `before()` methods. Call `module.sharedInjector()` before you setup any other hooks that
2662
+ * will create (i.e call `module()`) or use (i.e call `inject()`) the injector.
2663
+ *
2664
+ * You cannot call `sharedInjector()` from within a context already using `sharedInjector()`.
2665
+ *
2666
+ * ## Example
2667
+ *
2668
+ * Typically beforeAll is used to make many assertions about a single operation. This can
2669
+ * cut down test run-time as the test setup doesn't need to be re-run, and enabling focussed
2670
+ * tests each with a single assertion.
2671
+ *
2672
+ * ```js
2673
+ * describe("Deep Thought", function() {
2674
+ *
2675
+ * module.sharedInjector();
2676
+ *
2677
+ * beforeAll(module("UltimateQuestion"));
2678
+ *
2679
+ * beforeAll(inject(function(DeepThought) {
2680
+ * expect(DeepThought.answer).toBeUndefined();
2681
+ * DeepThought.generateAnswer();
2682
+ * }));
2683
+ *
2684
+ * it("has calculated the answer correctly", inject(function(DeepThought) {
2685
+ * // Because of sharedInjector, we have access to the instance of the DeepThought service
2686
+ * // that was provided to the beforeAll() hook. Therefore we can test the generated answer
2687
+ * expect(DeepThought.answer).toBe(42);
2688
+ * }));
2689
+ *
2690
+ * it("has calculated the answer within the expected time", inject(function(DeepThought) {
2691
+ * expect(DeepThought.runTimeMillennia).toBeLessThan(8000);
2692
+ * }));
2693
+ *
2694
+ * it("has double checked the answer", inject(function(DeepThought) {
2695
+ * expect(DeepThought.absolutelySureItIsTheRightAnswer).toBe(true);
2696
+ * }));
2697
+ *
2698
+ * });
2699
+ *
2700
+ * ```
2701
+ */
2702
+ module.sharedInjector = function() {
2703
+ if (!(module.$$beforeAllHook && module.$$afterAllHook)) {
2704
+ throw Error("sharedInjector() cannot be used unless your test runner defines beforeAll/afterAll");
2705
+ }
2706
+
2707
+ var initialized = false;
2708
+
2709
+ module.$$beforeAllHook(function() {
2710
+ if (injectorState.shared) {
2711
+ injectorState.sharedError = Error("sharedInjector() cannot be called inside a context that has already called sharedInjector()");
2712
+ throw injectorState.sharedError;
2713
+ }
2714
+ initialized = true;
2715
+ currentSpec = this;
2716
+ injectorState.shared = true;
2717
+ });
2718
+
2719
+ module.$$afterAllHook(function() {
2720
+ if (initialized) {
2721
+ injectorState = new InjectorState();
2722
+ module.$$cleanup();
2723
+ } else {
2724
+ injectorState.sharedError = null;
2725
+ }
2726
+ });
2727
+ };
2728
+
2729
+ module.$$beforeEach = function() {
2730
+ if (injectorState.shared && currentSpec && currentSpec != this) {
2731
+ var state = currentSpec;
2732
+ currentSpec = this;
2733
+ angular.forEach(["$injector","$modules","$providerInjector", "$injectorStrict"], function(k) {
2734
+ currentSpec[k] = state[k];
2735
+ state[k] = null;
2736
+ });
2737
+ } else {
2738
+ currentSpec = this;
2739
+ originalRootElement = null;
2740
+ annotatedFunctions = [];
2741
+ }
2742
+ };
2743
+
2744
+ module.$$afterEach = function() {
2745
+ if (injectorState.cleanupAfterEach()) {
2746
+ module.$$cleanup();
2747
+ }
2748
+ };
2749
+
2750
+ module.$$cleanup = function() {
2751
+ var injector = currentSpec.$injector;
2752
+
2753
+ annotatedFunctions.forEach(function(fn) {
2754
+ delete fn.$inject;
2755
+ });
2756
+
2757
+ angular.forEach(currentSpec.$modules, function(module) {
2758
+ if (module && module.$$hashKey) {
2759
+ module.$$hashKey = undefined;
2760
+ }
2761
+ });
2762
+
2763
+ currentSpec.$injector = null;
2764
+ currentSpec.$modules = null;
2765
+ currentSpec.$providerInjector = null;
2766
+ currentSpec = null;
2767
+
2768
+ if (injector) {
2769
+ // Ensure `$rootElement` is instantiated, before checking `originalRootElement`
2770
+ var $rootElement = injector.get('$rootElement');
2771
+ var rootNode = $rootElement && $rootElement[0];
2772
+ var cleanUpNodes = !originalRootElement ? [] : [originalRootElement[0]];
2773
+ if (rootNode && (!originalRootElement || rootNode !== originalRootElement[0])) {
2774
+ cleanUpNodes.push(rootNode);
2775
+ }
2776
+ angular.element.cleanData(cleanUpNodes);
2777
+
2778
+ // Ensure `$destroy()` is available, before calling it
2779
+ // (a mocked `$rootScope` might not implement it (or not even be an object at all))
2780
+ var $rootScope = injector.get('$rootScope');
2781
+ if ($rootScope && $rootScope.$destroy) $rootScope.$destroy();
2782
+ }
2783
+
2784
+ // clean up jquery's fragment cache
2785
+ angular.forEach(angular.element.fragments, function(val, key) {
2786
+ delete angular.element.fragments[key];
2787
+ });
2788
+
2789
+ MockXhr.$$lastInstance = null;
2790
+
2791
+ angular.forEach(angular.callbacks, function(val, key) {
2792
+ delete angular.callbacks[key];
2793
+ });
2794
+ angular.callbacks.counter = 0;
2795
+ };
2796
+
2797
+ (window.beforeEach || window.setup)(module.$$beforeEach);
2798
+ (window.afterEach || window.teardown)(module.$$afterEach);
2799
+
2800
+ /**
2801
+ * @ngdoc function
2802
+ * @name angular.mock.inject
2803
+ * @description
2804
+ *
2805
+ * *NOTE*: This function is also published on window for easy access.<br>
2806
+ * *NOTE*: This function is declared ONLY WHEN running tests with jasmine or mocha
2807
+ *
2808
+ * The inject function wraps a function into an injectable function. The inject() creates new
2809
+ * instance of {@link auto.$injector $injector} per test, which is then used for
2810
+ * resolving references.
2811
+ *
2812
+ *
2813
+ * ## Resolving References (Underscore Wrapping)
2814
+ * Often, we would like to inject a reference once, in a `beforeEach()` block and reuse this
2815
+ * in multiple `it()` clauses. To be able to do this we must assign the reference to a variable
2816
+ * that is declared in the scope of the `describe()` block. Since we would, most likely, want
2817
+ * the variable to have the same name of the reference we have a problem, since the parameter
2818
+ * to the `inject()` function would hide the outer variable.
2819
+ *
2820
+ * To help with this, the injected parameters can, optionally, be enclosed with underscores.
2821
+ * These are ignored by the injector when the reference name is resolved.
2822
+ *
2823
+ * For example, the parameter `_myService_` would be resolved as the reference `myService`.
2824
+ * Since it is available in the function body as _myService_, we can then assign it to a variable
2825
+ * defined in an outer scope.
2826
+ *
2827
+ * ```
2828
+ * // Defined out reference variable outside
2829
+ * var myService;
2830
+ *
2831
+ * // Wrap the parameter in underscores
2832
+ * beforeEach( inject( function(_myService_){
2833
+ * myService = _myService_;
2834
+ * }));
2835
+ *
2836
+ * // Use myService in a series of tests.
2837
+ * it('makes use of myService', function() {
2838
+ * myService.doStuff();
2839
+ * });
2840
+ *
2841
+ * ```
2842
+ *
2843
+ * See also {@link angular.mock.module angular.mock.module}
2844
+ *
2845
+ * ## Example
2846
+ * Example of what a typical jasmine tests looks like with the inject method.
2847
+ * ```js
2848
+ *
2849
+ * angular.module('myApplicationModule', [])
2850
+ * .value('mode', 'app')
2851
+ * .value('version', 'v1.0.1');
2852
+ *
2853
+ *
2854
+ * describe('MyApp', function() {
2855
+ *
2856
+ * // You need to load modules that you want to test,
2857
+ * // it loads only the "ng" module by default.
2858
+ * beforeEach(module('myApplicationModule'));
2859
+ *
2860
+ *
2861
+ * // inject() is used to inject arguments of all given functions
2862
+ * it('should provide a version', inject(function(mode, version) {
2863
+ * expect(version).toEqual('v1.0.1');
2864
+ * expect(mode).toEqual('app');
2865
+ * }));
2866
+ *
2867
+ *
2868
+ * // The inject and module method can also be used inside of the it or beforeEach
2869
+ * it('should override a version and test the new version is injected', function() {
2870
+ * // module() takes functions or strings (module aliases)
2871
+ * module(function($provide) {
2872
+ * $provide.value('version', 'overridden'); // override version here
2873
+ * });
2874
+ *
2875
+ * inject(function(version) {
2876
+ * expect(version).toEqual('overridden');
2877
+ * });
2878
+ * });
2879
+ * });
2880
+ *
2881
+ * ```
2882
+ *
2883
+ * @param {...Function} fns any number of functions which will be injected using the injector.
2884
+ */
2885
+
2886
+
2887
+
2888
+ var ErrorAddingDeclarationLocationStack = function(e, errorForStack) {
2889
+ this.message = e.message;
2890
+ this.name = e.name;
2891
+ if (e.line) this.line = e.line;
2892
+ if (e.sourceId) this.sourceId = e.sourceId;
2893
+ if (e.stack && errorForStack)
2894
+ this.stack = e.stack + '\n' + errorForStack.stack;
2895
+ if (e.stackArray) this.stackArray = e.stackArray;
2896
+ };
2897
+ ErrorAddingDeclarationLocationStack.prototype.toString = Error.prototype.toString;
2898
+
2899
+ window.inject = angular.mock.inject = function() {
2900
+ var blockFns = Array.prototype.slice.call(arguments, 0);
2901
+ var errorForStack = new Error('Declaration Location');
2902
+ return wasInjectorCreated() ? workFn.call(currentSpec) : workFn;
2903
+ /////////////////////
2904
+ function workFn() {
2905
+ var modules = currentSpec.$modules || [];
2906
+ var strictDi = !!currentSpec.$injectorStrict;
2907
+ modules.unshift(['$injector', function($injector) {
2908
+ currentSpec.$providerInjector = $injector;
2909
+ }]);
2910
+ modules.unshift('ngMock');
2911
+ modules.unshift('ng');
2912
+ var injector = currentSpec.$injector;
2913
+ if (!injector) {
2914
+ if (strictDi) {
2915
+ // If strictDi is enabled, annotate the providerInjector blocks
2916
+ angular.forEach(modules, function(moduleFn) {
2917
+ if (typeof moduleFn === "function") {
2918
+ angular.injector.$$annotate(moduleFn);
2919
+ }
2920
+ });
2921
+ }
2922
+ injector = currentSpec.$injector = angular.injector(modules, strictDi);
2923
+ currentSpec.$injectorStrict = strictDi;
2924
+ }
2925
+ for (var i = 0, ii = blockFns.length; i < ii; i++) {
2926
+ if (currentSpec.$injectorStrict) {
2927
+ // If the injector is strict / strictDi, and the spec wants to inject using automatic
2928
+ // annotation, then annotate the function here.
2929
+ injector.annotate(blockFns[i]);
2930
+ }
2931
+ try {
2932
+ /* jshint -W040 *//* Jasmine explicitly provides a `this` object when calling functions */
2933
+ injector.invoke(blockFns[i] || angular.noop, this);
2934
+ /* jshint +W040 */
2935
+ } catch (e) {
2936
+ if (e.stack && errorForStack) {
2937
+ throw new ErrorAddingDeclarationLocationStack(e, errorForStack);
2938
+ }
2939
+ throw e;
2940
+ } finally {
2941
+ errorForStack = null;
2942
+ }
2943
+ }
2944
+ }
2945
+ };
2946
+
2947
+
2948
+ angular.mock.inject.strictDi = function(value) {
2949
+ value = arguments.length ? !!value : true;
2950
+ return wasInjectorCreated() ? workFn() : workFn;
2951
+
2952
+ function workFn() {
2953
+ if (value !== currentSpec.$injectorStrict) {
2954
+ if (currentSpec.$injector) {
2955
+ throw new Error('Injector already created, can not modify strict annotations');
2956
+ } else {
2957
+ currentSpec.$injectorStrict = value;
2958
+ }
2959
+ }
2960
+ }
2961
+ };
2962
+
2963
+ function InjectorState() {
2964
+ this.shared = false;
2965
+ this.sharedError = null;
2966
+
2967
+ this.cleanupAfterEach = function() {
2968
+ return !this.shared || this.sharedError;
2969
+ };
2970
+ }
2971
+ })(window.jasmine || window.mocha);
2972
+
2973
+
2974
+ })(window, window.angular);