motion-juxtapose 0.1.0

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