angularjs-rails 1.5.8 → 1.6.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license AngularJS v1.5.8
2
+ * @license AngularJS v1.6.0
3
3
  * (c) 2010-2016 Google, Inc. http://angularjs.org
4
4
  * License: MIT
5
5
  */
@@ -69,7 +69,7 @@ var jqLite;
69
69
  * By default, `ngMessages` will only display one message for a particular key/value collection at any time. If more
70
70
  * than one message (or error) key is currently true, then which message is shown is determined by the order of messages
71
71
  * in the HTML template code (messages declared first are prioritised). This mechanism means the developer does not have
72
- * to prioritise messages using custom JavaScript code.
72
+ * to prioritize messages using custom JavaScript code.
73
73
  *
74
74
  * Given the following error object for our example (which informs us that the field `myField` currently has both the
75
75
  * `required` and `email` errors):
@@ -352,7 +352,7 @@ angular.module('ngMessages', [], function initAngularHelpers() {
352
352
  return {
353
353
  require: 'ngMessages',
354
354
  restrict: 'AE',
355
- controller: ['$element', '$scope', '$attrs', function($element, $scope, $attrs) {
355
+ controller: ['$element', '$scope', '$attrs', function NgMessagesCtrl($element, $scope, $attrs) {
356
356
  var ctrl = this;
357
357
  var latestKey = 0;
358
358
  var nextAttachId = 0;
@@ -412,9 +412,11 @@ angular.module('ngMessages', [], function initAngularHelpers() {
412
412
  messageCtrl.detach();
413
413
  });
414
414
 
415
- unmatchedMessages.length !== totalMessages
416
- ? $animate.setClass($element, ACTIVE_CLASS, INACTIVE_CLASS)
417
- : $animate.setClass($element, INACTIVE_CLASS, ACTIVE_CLASS);
415
+ if (unmatchedMessages.length !== totalMessages) {
416
+ $animate.setClass($element, ACTIVE_CLASS, INACTIVE_CLASS);
417
+ } else {
418
+ $animate.setClass($element, INACTIVE_CLASS, ACTIVE_CLASS);
419
+ }
418
420
  };
419
421
 
420
422
  $scope.$watchCollection($attrs.ngMessages || $attrs['for'], ctrl.render);
@@ -430,8 +432,8 @@ angular.module('ngMessages', [], function initAngularHelpers() {
430
432
  if (!renderLater) {
431
433
  renderLater = true;
432
434
  $scope.$evalAsync(function() {
433
- if (renderLater) {
434
- cachedCollection && ctrl.render(cachedCollection);
435
+ if (renderLater && cachedCollection) {
436
+ ctrl.render(cachedCollection);
435
437
  }
436
438
  });
437
439
  }
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license AngularJS v1.5.8
2
+ * @license AngularJS v1.6.0
3
3
  * (c) 2010-2016 Google, Inc. http://angularjs.org
4
4
  * License: MIT
5
5
  */
@@ -40,7 +40,7 @@ angular.mock.$Browser = function() {
40
40
  var self = this;
41
41
 
42
42
  this.isMock = true;
43
- self.$$url = "http://server/";
43
+ self.$$url = 'http://server/';
44
44
  self.$$lastUrl = self.$$url; // used by url polling fn
45
45
  self.pollFns = [];
46
46
 
@@ -252,19 +252,19 @@ angular.mock.$ExceptionHandlerProvider = function() {
252
252
  case 'rethrow':
253
253
  var errors = [];
254
254
  handler = function(e) {
255
- if (arguments.length == 1) {
255
+ if (arguments.length === 1) {
256
256
  errors.push(e);
257
257
  } else {
258
258
  errors.push([].slice.call(arguments, 0));
259
259
  }
260
- if (mode === "rethrow") {
260
+ if (mode === 'rethrow') {
261
261
  throw e;
262
262
  }
263
263
  };
264
264
  handler.errors = errors;
265
265
  break;
266
266
  default:
267
- throw new Error("Unknown mode '" + mode + "', only 'log'/'rethrow' modes are allowed!");
267
+ throw new Error('Unknown mode \'' + mode + '\', only \'log\'/\'rethrow\' modes are allowed!');
268
268
  }
269
269
  };
270
270
 
@@ -414,8 +414,8 @@ angular.mock.$LogProvider = function() {
414
414
  });
415
415
  });
416
416
  if (errors.length) {
417
- errors.unshift("Expected $log to be empty! Either a message was logged unexpectedly, or " +
418
- "an expected log message was not checked and removed:");
417
+ errors.unshift('Expected $log to be empty! Either a message was logged unexpectedly, or ' +
418
+ 'an expected log message was not checked and removed:');
419
419
  errors.push('');
420
420
  throw new Error(errors.join('\n---------\n'));
421
421
  }
@@ -463,7 +463,7 @@ angular.mock.$IntervalProvider = function() {
463
463
  promise = deferred.promise;
464
464
 
465
465
  count = (angular.isDefined(count)) ? count : 0;
466
- promise.then(null, null, (!hasParams) ? fn : function() {
466
+ promise.then(null, function() {}, (!hasParams) ? fn : function() {
467
467
  fn.apply(null, args);
468
468
  });
469
469
 
@@ -523,6 +523,7 @@ angular.mock.$IntervalProvider = function() {
523
523
  });
524
524
 
525
525
  if (angular.isDefined(fnIndex)) {
526
+ repeatFns[fnIndex].deferred.promise.then(undefined, function() {});
526
527
  repeatFns[fnIndex].deferred.reject('canceled');
527
528
  repeatFns.splice(fnIndex, 1);
528
529
  return true;
@@ -558,16 +559,13 @@ angular.mock.$IntervalProvider = function() {
558
559
  };
559
560
 
560
561
 
561
- /* jshint -W101 */
562
- /* The R_ISO8061_STR regex is never going to fit into the 100 char limit!
563
- * This directive should go inside the anonymous function but a bug in JSHint means that it would
564
- * not be enacted early enough to prevent the warning.
565
- */
566
- var R_ISO8061_STR = /^(-?\d{4})-?(\d\d)-?(\d\d)(?:T(\d\d)(?:\:?(\d\d)(?:\:?(\d\d)(?:\.(\d{3}))?)?)?(Z|([+-])(\d\d):?(\d\d)))?$/;
567
-
568
562
  function jsonStringToDate(string) {
563
+ // The R_ISO8061_STR regex is never going to fit into the 100 char limit!
564
+ // eslit-disable-next-line max-len
565
+ var R_ISO8061_STR = /^(-?\d{4})-?(\d\d)-?(\d\d)(?:T(\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d{3}))?)?)?(Z|([+-])(\d\d):?(\d\d)))?$/;
566
+
569
567
  var match;
570
- if (match = string.match(R_ISO8061_STR)) {
568
+ if ((match = string.match(R_ISO8061_STR))) {
571
569
  var date = new Date(0),
572
570
  tzHour = 0,
573
571
  tzMin = 0;
@@ -650,9 +648,10 @@ angular.mock.TzDate = function(offset, timestamp) {
650
648
 
651
649
  timestamp = self.origDate.getTime();
652
650
  if (isNaN(timestamp)) {
651
+ // eslint-disable-next-line no-throw-literal
653
652
  throw {
654
- name: "Illegal Argument",
655
- message: "Arg '" + tsStr + "' passed into TzDate constructor is not a valid date string"
653
+ name: 'Illegal Argument',
654
+ message: 'Arg \'' + tsStr + '\' passed into TzDate constructor is not a valid date string'
656
655
  };
657
656
  }
658
657
  } else {
@@ -758,7 +757,7 @@ angular.mock.TzDate = function(offset, timestamp) {
758
757
 
759
758
  angular.forEach(unimplementedMethods, function(methodName) {
760
759
  self[methodName] = function() {
761
- throw new Error("Method '" + methodName + "' is not implemented in the TzDate mock");
760
+ throw new Error('Method \'' + methodName + '\' is not implemented in the TzDate mock');
762
761
  };
763
762
  });
764
763
 
@@ -767,7 +766,6 @@ angular.mock.TzDate = function(offset, timestamp) {
767
766
 
768
767
  //make "tzDateInstance instanceof Date" return true
769
768
  angular.mock.TzDate.prototype = Date.prototype;
770
- /* jshint +W101 */
771
769
 
772
770
 
773
771
  /**
@@ -1215,7 +1213,7 @@ angular.mock.dump = function(object) {
1215
1213
  $httpBackend.expectPOST('/add-msg.py', undefined, function(headers) {
1216
1214
  // check if the header was sent, if it wasn't the expectation won't
1217
1215
  // match the request and the test will fail
1218
- return headers['Authorization'] == 'xxx';
1216
+ return headers['Authorization'] === 'xxx';
1219
1217
  }).respond(201, '');
1220
1218
 
1221
1219
  $rootScope.saveMessage('whatever');
@@ -1357,7 +1355,11 @@ function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) {
1357
1355
 
1358
1356
  function wrapResponse(wrapped) {
1359
1357
  if (!$browser && timeout) {
1360
- timeout.then ? timeout.then(handleTimeout) : $timeout(handleTimeout, timeout);
1358
+ if (timeout.then) {
1359
+ timeout.then(handleTimeout);
1360
+ } else {
1361
+ $timeout(handleTimeout, timeout);
1362
+ }
1361
1363
  }
1362
1364
 
1363
1365
  return handleResponse;
@@ -1426,7 +1428,7 @@ function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) {
1426
1428
  * Creates a new backend definition.
1427
1429
  *
1428
1430
  * @param {string} method HTTP method.
1429
- * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
1431
+ * @param {string|RegExp|function(string)=} url HTTP url or function that receives a url
1430
1432
  * and returns true if the url matches the current definition.
1431
1433
  * @param {(string|RegExp|function(string))=} data HTTP request body or function that receives
1432
1434
  * data string and returns true if the data is as expected.
@@ -1448,6 +1450,9 @@ function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) {
1448
1450
  * the `requestHandler` object for possible overrides.
1449
1451
  */
1450
1452
  $httpBackend.when = function(method, url, data, headers, keys) {
1453
+
1454
+ assertArgDefined(arguments, 1, 'url');
1455
+
1451
1456
  var definition = new MockHttpExpectation(method, url, data, headers, keys),
1452
1457
  chain = {
1453
1458
  respond: function(status, data, headers, statusText) {
@@ -1475,7 +1480,7 @@ function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) {
1475
1480
  * @description
1476
1481
  * Creates a new backend definition for GET requests. For more info see `when()`.
1477
1482
  *
1478
- * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
1483
+ * @param {string|RegExp|function(string)=} url HTTP url or function that receives a url
1479
1484
  * and returns true if the url matches the current definition.
1480
1485
  * @param {(Object|function(Object))=} headers HTTP headers.
1481
1486
  * @param {(Array)=} keys Array of keys to assign to regex matches in request url described above.
@@ -1490,7 +1495,7 @@ function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) {
1490
1495
  * @description
1491
1496
  * Creates a new backend definition for HEAD requests. For more info see `when()`.
1492
1497
  *
1493
- * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
1498
+ * @param {string|RegExp|function(string)=} url HTTP url or function that receives a url
1494
1499
  * and returns true if the url matches the current definition.
1495
1500
  * @param {(Object|function(Object))=} headers HTTP headers.
1496
1501
  * @param {(Array)=} keys Array of keys to assign to regex matches in request url described above.
@@ -1505,7 +1510,7 @@ function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) {
1505
1510
  * @description
1506
1511
  * Creates a new backend definition for DELETE requests. For more info see `when()`.
1507
1512
  *
1508
- * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
1513
+ * @param {string|RegExp|function(string)=} url HTTP url or function that receives a url
1509
1514
  * and returns true if the url matches the current definition.
1510
1515
  * @param {(Object|function(Object))=} headers HTTP headers.
1511
1516
  * @param {(Array)=} keys Array of keys to assign to regex matches in request url described above.
@@ -1520,7 +1525,7 @@ function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) {
1520
1525
  * @description
1521
1526
  * Creates a new backend definition for POST requests. For more info see `when()`.
1522
1527
  *
1523
- * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
1528
+ * @param {string|RegExp|function(string)=} url HTTP url or function that receives a url
1524
1529
  * and returns true if the url matches the current definition.
1525
1530
  * @param {(string|RegExp|function(string))=} data HTTP request body or function that receives
1526
1531
  * data string and returns true if the data is as expected.
@@ -1537,7 +1542,7 @@ function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) {
1537
1542
  * @description
1538
1543
  * Creates a new backend definition for PUT requests. For more info see `when()`.
1539
1544
  *
1540
- * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
1545
+ * @param {string|RegExp|function(string)=} url HTTP url or function that receives a url
1541
1546
  * and returns true if the url matches the current definition.
1542
1547
  * @param {(string|RegExp|function(string))=} data HTTP request body or function that receives
1543
1548
  * data string and returns true if the data is as expected.
@@ -1554,7 +1559,7 @@ function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) {
1554
1559
  * @description
1555
1560
  * Creates a new backend definition for JSONP requests. For more info see `when()`.
1556
1561
  *
1557
- * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
1562
+ * @param {string|RegExp|function(string)=} url HTTP url or function that receives a url
1558
1563
  * and returns true if the url matches the current definition.
1559
1564
  * @param {(Array)=} keys Array of keys to assign to regex matches in request url described above.
1560
1565
  * @returns {requestHandler} Returns an object with `respond` method that controls how a matched
@@ -1590,7 +1595,7 @@ function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) {
1590
1595
 
1591
1596
  url = url
1592
1597
  .replace(/([().])/g, '\\$1')
1593
- .replace(/(\/)?:(\w+)([\?\*])?/g, function(_, slash, key, option) {
1598
+ .replace(/(\/)?:(\w+)([?*])?/g, function(_, slash, key, option) {
1594
1599
  var optional = option === '?' ? option : null;
1595
1600
  var star = option === '*' ? option : null;
1596
1601
  keys.push({ name: key, optional: !!optional });
@@ -1604,7 +1609,7 @@ function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) {
1604
1609
  + ')'
1605
1610
  + (optional || '');
1606
1611
  })
1607
- .replace(/([\/$\*])/g, '\\$1');
1612
+ .replace(/([/$*])/g, '\\$1');
1608
1613
 
1609
1614
  ret.regexp = new RegExp('^' + url, 'i');
1610
1615
  return ret;
@@ -1617,7 +1622,7 @@ function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) {
1617
1622
  * Creates a new request expectation.
1618
1623
  *
1619
1624
  * @param {string} method HTTP method.
1620
- * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
1625
+ * @param {string|RegExp|function(string)=} url HTTP url or function that receives a url
1621
1626
  * and returns true if the url matches the current definition.
1622
1627
  * @param {(string|RegExp|function(string)|Object)=} data HTTP request body or function that
1623
1628
  * receives data string and returns true if the data is as expected, or Object if request body
@@ -1640,6 +1645,9 @@ function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) {
1640
1645
  * the `requestHandler` object for possible overrides.
1641
1646
  */
1642
1647
  $httpBackend.expect = function(method, url, data, headers, keys) {
1648
+
1649
+ assertArgDefined(arguments, 1, 'url');
1650
+
1643
1651
  var expectation = new MockHttpExpectation(method, url, data, headers, keys),
1644
1652
  chain = {
1645
1653
  respond: function(status, data, headers, statusText) {
@@ -1658,7 +1666,7 @@ function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) {
1658
1666
  * @description
1659
1667
  * Creates a new request expectation for GET requests. For more info see `expect()`.
1660
1668
  *
1661
- * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
1669
+ * @param {string|RegExp|function(string)=} url HTTP url or function that receives a url
1662
1670
  * and returns true if the url matches the current definition.
1663
1671
  * @param {Object=} headers HTTP headers.
1664
1672
  * @param {(Array)=} keys Array of keys to assign to regex matches in request url described above.
@@ -1673,7 +1681,7 @@ function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) {
1673
1681
  * @description
1674
1682
  * Creates a new request expectation for HEAD requests. For more info see `expect()`.
1675
1683
  *
1676
- * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
1684
+ * @param {string|RegExp|function(string)=} url HTTP url or function that receives a url
1677
1685
  * and returns true if the url matches the current definition.
1678
1686
  * @param {Object=} headers HTTP headers.
1679
1687
  * @param {(Array)=} keys Array of keys to assign to regex matches in request url described above.
@@ -1688,7 +1696,7 @@ function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) {
1688
1696
  * @description
1689
1697
  * Creates a new request expectation for DELETE requests. For more info see `expect()`.
1690
1698
  *
1691
- * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
1699
+ * @param {string|RegExp|function(string)=} url HTTP url or function that receives a url
1692
1700
  * and returns true if the url matches the current definition.
1693
1701
  * @param {Object=} headers HTTP headers.
1694
1702
  * @param {(Array)=} keys Array of keys to assign to regex matches in request url described above.
@@ -1703,7 +1711,7 @@ function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) {
1703
1711
  * @description
1704
1712
  * Creates a new request expectation for POST requests. For more info see `expect()`.
1705
1713
  *
1706
- * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
1714
+ * @param {string|RegExp|function(string)=} url HTTP url or function that receives a url
1707
1715
  * and returns true if the url matches the current definition.
1708
1716
  * @param {(string|RegExp|function(string)|Object)=} data HTTP request body or function that
1709
1717
  * receives data string and returns true if the data is as expected, or Object if request body
@@ -1721,7 +1729,7 @@ function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) {
1721
1729
  * @description
1722
1730
  * Creates a new request expectation for PUT requests. For more info see `expect()`.
1723
1731
  *
1724
- * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
1732
+ * @param {string|RegExp|function(string)=} url HTTP url or function that receives a url
1725
1733
  * and returns true if the url matches the current definition.
1726
1734
  * @param {(string|RegExp|function(string)|Object)=} data HTTP request body or function that
1727
1735
  * receives data string and returns true if the data is as expected, or Object if request body
@@ -1739,7 +1747,7 @@ function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) {
1739
1747
  * @description
1740
1748
  * Creates a new request expectation for PATCH requests. For more info see `expect()`.
1741
1749
  *
1742
- * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
1750
+ * @param {string|RegExp|function(string)=} url HTTP url or function that receives a url
1743
1751
  * and returns true if the url matches the current definition.
1744
1752
  * @param {(string|RegExp|function(string)|Object)=} data HTTP request body or function that
1745
1753
  * receives data string and returns true if the data is as expected, or Object if request body
@@ -1757,7 +1765,7 @@ function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) {
1757
1765
  * @description
1758
1766
  * Creates a new request expectation for JSONP requests. For more info see `expect()`.
1759
1767
  *
1760
- * @param {string|RegExp|function(string)} url HTTP url or function that receives an url
1768
+ * @param {string|RegExp|function(string)=} url HTTP url or function that receives an url
1761
1769
  * and returns true if the url matches the current definition.
1762
1770
  * @param {(Array)=} keys Array of keys to assign to regex matches in request url described above.
1763
1771
  * @returns {requestHandler} Returns an object with `respond` method that controls how a matched
@@ -1788,24 +1796,34 @@ function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) {
1788
1796
  * @ngdoc method
1789
1797
  * @name $httpBackend#flush
1790
1798
  * @description
1791
- * Flushes all pending requests using the trained responses.
1792
- *
1793
- * @param {number=} count Number of responses to flush (in the order they arrived). If undefined,
1794
- * all pending requests will be flushed. If there are no pending requests when the flush method
1795
- * is called an exception is thrown (as this typically a sign of programming error).
1799
+ * Flushes pending requests using the trained responses. Requests are flushed in the order they
1800
+ * were made, but it is also possible to skip one or more requests (for example to have them
1801
+ * flushed later). This is useful for simulating scenarios where responses arrive from the server
1802
+ * in any order.
1803
+ *
1804
+ * If there are no pending requests to flush when the method is called, an exception is thrown (as
1805
+ * this is typically a sign of programming error).
1806
+ *
1807
+ * @param {number=} count - Number of responses to flush. If undefined/null, all pending requests
1808
+ * (starting after `skip`) will be flushed.
1809
+ * @param {number=} [skip=0] - Number of pending requests to skip. For example, a value of `5`
1810
+ * would skip the first 5 pending requests and start flushing from the 6th onwards.
1796
1811
  */
1797
- $httpBackend.flush = function(count, digest) {
1812
+ $httpBackend.flush = function(count, skip, digest) {
1798
1813
  if (digest !== false) $rootScope.$digest();
1799
- if (!responses.length) throw new Error('No pending request to flush !');
1814
+
1815
+ skip = skip || 0;
1816
+ if (skip >= responses.length) throw new Error('No pending request to flush !');
1800
1817
 
1801
1818
  if (angular.isDefined(count) && count !== null) {
1802
1819
  while (count--) {
1803
- if (!responses.length) throw new Error('No more pending request to flush !');
1804
- responses.shift()();
1820
+ var part = responses.splice(skip, 1);
1821
+ if (!part.length) throw new Error('No more pending request to flush !');
1822
+ part[0]();
1805
1823
  }
1806
1824
  } else {
1807
- while (responses.length) {
1808
- responses.shift()();
1825
+ while (responses.length > skip) {
1826
+ responses.splice(skip, 1)[0]();
1809
1827
  }
1810
1828
  }
1811
1829
  $httpBackend.verifyNoOutstandingExpectation(digest);
@@ -1847,7 +1865,8 @@ function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) {
1847
1865
  * afterEach($httpBackend.verifyNoOutstandingRequest);
1848
1866
  * ```
1849
1867
  */
1850
- $httpBackend.verifyNoOutstandingRequest = function() {
1868
+ $httpBackend.verifyNoOutstandingRequest = function(digest) {
1869
+ if (digest !== false) $rootScope.$digest();
1851
1870
  if (responses.length) {
1852
1871
  throw new Error('Unflushed requests: ' + responses.length);
1853
1872
  }
@@ -1873,18 +1892,35 @@ function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) {
1873
1892
  function createShortMethods(prefix) {
1874
1893
  angular.forEach(['GET', 'DELETE', 'JSONP', 'HEAD'], function(method) {
1875
1894
  $httpBackend[prefix + method] = function(url, headers, keys) {
1895
+ assertArgDefined(arguments, 0, 'url');
1896
+
1897
+ // Change url to `null` if `undefined` to stop it throwing an exception further down
1898
+ if (angular.isUndefined(url)) url = null;
1899
+
1876
1900
  return $httpBackend[prefix](method, url, undefined, headers, keys);
1877
1901
  };
1878
1902
  });
1879
1903
 
1880
1904
  angular.forEach(['PUT', 'POST', 'PATCH'], function(method) {
1881
1905
  $httpBackend[prefix + method] = function(url, data, headers, keys) {
1906
+ assertArgDefined(arguments, 0, 'url');
1907
+
1908
+ // Change url to `null` if `undefined` to stop it throwing an exception further down
1909
+ if (angular.isUndefined(url)) url = null;
1910
+
1882
1911
  return $httpBackend[prefix](method, url, data, headers, keys);
1883
1912
  };
1884
1913
  });
1885
1914
  }
1886
1915
  }
1887
1916
 
1917
+ function assertArgDefined(args, index, name) {
1918
+ if (args.length > index && angular.isUndefined(args[index])) {
1919
+ throw new Error('Undefined argument `' + name + '`; the argument is provided but not defined');
1920
+ }
1921
+ }
1922
+
1923
+
1888
1924
  function MockHttpExpectation(method, url, data, headers, keys) {
1889
1925
 
1890
1926
  function getUrlParams(u) {
@@ -1893,14 +1929,15 @@ function MockHttpExpectation(method, url, data, headers, keys) {
1893
1929
  }
1894
1930
 
1895
1931
  function compareUrl(u) {
1896
- return (url.slice(0, url.indexOf('?')) == u.slice(0, u.indexOf('?')) && getUrlParams(url).join() == getUrlParams(u).join());
1932
+ return (url.slice(0, url.indexOf('?')) === u.slice(0, u.indexOf('?')) &&
1933
+ getUrlParams(url).join() === getUrlParams(u).join());
1897
1934
  }
1898
1935
 
1899
1936
  this.data = data;
1900
1937
  this.headers = headers;
1901
1938
 
1902
1939
  this.match = function(m, u, d, h) {
1903
- if (method != m) return false;
1940
+ if (method !== m) return false;
1904
1941
  if (!this.matchUrl(u)) return false;
1905
1942
  if (angular.isDefined(d) && !this.matchData(d)) return false;
1906
1943
  if (angular.isDefined(h) && !this.matchHeaders(h)) return false;
@@ -1911,7 +1948,7 @@ function MockHttpExpectation(method, url, data, headers, keys) {
1911
1948
  if (!url) return true;
1912
1949
  if (angular.isFunction(url.test)) return url.test(u);
1913
1950
  if (angular.isFunction(url)) return url(u);
1914
- return (url == u || compareUrl(u));
1951
+ return (url === u || compareUrl(u));
1915
1952
  };
1916
1953
 
1917
1954
  this.matchHeaders = function(h) {
@@ -1927,6 +1964,7 @@ function MockHttpExpectation(method, url, data, headers, keys) {
1927
1964
  if (data && !angular.isString(data)) {
1928
1965
  return angular.equals(angular.fromJson(angular.toJson(data)), angular.fromJson(d));
1929
1966
  }
1967
+ // eslint-disable-next-line eqeqeq
1930
1968
  return data == d;
1931
1969
  };
1932
1970
 
@@ -1958,7 +1996,7 @@ function MockHttpExpectation(method, url, data, headers, keys) {
1958
1996
  var obj = {}, key_value, key,
1959
1997
  queryStr = u.indexOf('?') > -1
1960
1998
  ? u.substring(u.indexOf('?') + 1)
1961
- : "";
1999
+ : '';
1962
2000
 
1963
2001
  angular.forEach(queryStr.split('&'), function(keyValue) {
1964
2002
  if (keyValue) {
@@ -2025,7 +2063,7 @@ function MockXhr() {
2025
2063
 
2026
2064
  header = undefined;
2027
2065
  angular.forEach(this.$$respHeaders, function(headerVal, headerName) {
2028
- if (!header && angular.lowercase(headerName) == name) header = headerVal;
2066
+ if (!header && angular.lowercase(headerName) === name) header = headerVal;
2029
2067
  });
2030
2068
  return header;
2031
2069
  };
@@ -2098,7 +2136,7 @@ angular.mock.$TimeoutDecorator = ['$delegate', '$browser', function($delegate, $
2098
2136
  function formatPendingTasksAsString(tasks) {
2099
2137
  var result = [];
2100
2138
  angular.forEach(tasks, function(task) {
2101
- result.push('{id: ' + task.id + ', ' + 'time: ' + task.time + '}');
2139
+ result.push('{id: ' + task.id + ', time: ' + task.time + '}');
2102
2140
  });
2103
2141
 
2104
2142
  return result.join(', ');
@@ -2153,6 +2191,10 @@ angular.mock.$RootElementProvider = function() {
2153
2191
  * A decorator for {@link ng.$controller} with additional `bindings` parameter, useful when testing
2154
2192
  * controllers of directives that use {@link $compile#-bindtocontroller- `bindToController`}.
2155
2193
  *
2194
+ * Depending on the value of
2195
+ * {@link ng.$compileProvider#preAssignBindingsEnabled `preAssignBindingsEnabled()`}, the properties
2196
+ * will be bound before or after invoking the constructor.
2197
+ *
2156
2198
  *
2157
2199
  * ## Example
2158
2200
  *
@@ -2171,18 +2213,24 @@ angular.mock.$RootElementProvider = function() {
2171
2213
  * // Controller definition ...
2172
2214
  *
2173
2215
  * myMod.controller('MyDirectiveController', ['$log', function($log) {
2174
- * $log.info(this.name);
2216
+ * this.log = function() {
2217
+ * $log.info(this.name);
2218
+ * };
2175
2219
  * }]);
2176
2220
  *
2177
2221
  *
2178
2222
  * // In a test ...
2179
2223
  *
2180
2224
  * describe('myDirectiveController', function() {
2181
- * it('should write the bound name to the log', inject(function($controller, $log) {
2182
- * var ctrl = $controller('MyDirectiveController', { /* no locals */ }, { name: 'Clark Kent' });
2183
- * expect(ctrl.name).toEqual('Clark Kent');
2184
- * expect($log.info.logs).toEqual(['Clark Kent']);
2185
- * }));
2225
+ * describe('log()', function() {
2226
+ * it('should write the bound name to the log', inject(function($controller, $log) {
2227
+ * var ctrl = $controller('MyDirectiveController', { /* no locals */ }, { name: 'Clark Kent' });
2228
+ * ctrl.log();
2229
+ *
2230
+ * expect(ctrl.name).toEqual('Clark Kent');
2231
+ * expect($log.info.logs).toEqual(['Clark Kent']);
2232
+ * }));
2233
+ * });
2186
2234
  * });
2187
2235
  *
2188
2236
  * ```
@@ -2194,44 +2242,61 @@ angular.mock.$RootElementProvider = function() {
2194
2242
  * * check if a controller with given name is registered via `$controllerProvider`
2195
2243
  * * check if evaluating the string on the current scope returns a constructor
2196
2244
  * * if $controllerProvider#allowGlobals, check `window[constructor]` on the global
2197
- * `window` object (not recommended)
2245
+ * `window` object (deprecated, not recommended)
2198
2246
  *
2199
2247
  * The string can use the `controller as property` syntax, where the controller instance is published
2200
2248
  * as the specified property on the `scope`; the `scope` must be injected into `locals` param for this
2201
2249
  * to work correctly.
2202
2250
  *
2203
2251
  * @param {Object} locals Injection locals for Controller.
2204
- * @param {Object=} bindings Properties to add to the controller before invoking the constructor. This is used
2205
- * to simulate the `bindToController` feature and simplify certain kinds of tests.
2252
+ * @param {Object=} bindings Properties to add to the controller instance. This is used to simulate
2253
+ * the `bindToController` feature and simplify certain kinds of tests.
2206
2254
  * @return {Object} Instance of given controller.
2207
2255
  */
2208
- angular.mock.$ControllerDecorator = ['$delegate', function($delegate) {
2209
- return function(expression, locals, later, ident) {
2210
- if (later && typeof later === 'object') {
2211
- var instantiate = $delegate(expression, locals, true, ident);
2212
- angular.extend(instantiate.instance, later);
2213
-
2214
- var instance = instantiate();
2215
- if (instance !== instantiate.instance) {
2216
- angular.extend(instance, later);
2256
+ function createControllerDecorator(compileProvider) {
2257
+ angular.mock.$ControllerDecorator = ['$delegate', function($delegate) {
2258
+ return function(expression, locals, later, ident) {
2259
+ if (later && typeof later === 'object') {
2260
+ var preAssignBindingsEnabled = compileProvider.preAssignBindingsEnabled();
2261
+
2262
+ var instantiate = $delegate(expression, locals, true, ident);
2263
+ if (preAssignBindingsEnabled) {
2264
+ angular.extend(instantiate.instance, later);
2265
+ }
2266
+
2267
+ var instance = instantiate();
2268
+ if (!preAssignBindingsEnabled || instance !== instantiate.instance) {
2269
+ angular.extend(instance, later);
2270
+ }
2271
+
2272
+ return instance;
2217
2273
  }
2274
+ return $delegate(expression, locals, later, ident);
2275
+ };
2276
+ }];
2218
2277
 
2219
- return instance;
2220
- }
2221
- return $delegate(expression, locals, later, ident);
2222
- };
2223
- }];
2278
+ return angular.mock.$ControllerDecorator;
2279
+ }
2224
2280
 
2225
2281
  /**
2226
2282
  * @ngdoc service
2227
2283
  * @name $componentController
2228
2284
  * @description
2229
- * A service that can be used to create instances of component controllers.
2230
- * <div class="alert alert-info">
2285
+ * A service that can be used to create instances of component controllers. Useful for unit-testing.
2286
+ *
2231
2287
  * Be aware that the controller will be instantiated and attached to the scope as specified in
2232
2288
  * the component definition object. If you do not provide a `$scope` object in the `locals` param
2233
2289
  * then the helper will create a new isolated scope as a child of `$rootScope`.
2234
- * </div>
2290
+ *
2291
+ * If you are using `$element` or `$attrs` in the controller, make sure to provide them as `locals`.
2292
+ * The `$element` must be a jqLite-wrapped DOM element, and `$attrs` should be an object that
2293
+ * has all properties / functions that you are using in the controller. If this is getting too complex,
2294
+ * you should compile the component instead and access the component's controller via the
2295
+ * {@link angular.element#methods `controller`} function.
2296
+ *
2297
+ * See also the section on {@link guide/component#unit-testing-component-controllers unit-testing component controllers}
2298
+ * in the guide.
2299
+ *
2235
2300
  * @param {string} componentName the name of the component whose controller we want to instantiate
2236
2301
  * @param {Object} locals Injection locals for Controller.
2237
2302
  * @param {Object=} bindings Properties to add to the controller before invoking the constructor. This is used
@@ -2239,7 +2304,8 @@ angular.mock.$ControllerDecorator = ['$delegate', function($delegate) {
2239
2304
  * @param {string=} ident Override the property name to use when attaching the controller to the scope.
2240
2305
  * @return {Object} Instance of requested controller.
2241
2306
  */
2242
- angular.mock.$ComponentControllerProvider = ['$compileProvider', function($compileProvider) {
2307
+ angular.mock.$ComponentControllerProvider = ['$compileProvider',
2308
+ function ComponentControllerProvider($compileProvider) {
2243
2309
  this.$get = ['$controller','$injector', '$rootScope', function($controller, $injector, $rootScope) {
2244
2310
  return function $componentController(componentName, locals, bindings, ident) {
2245
2311
  // get all directives associated to the component name
@@ -2288,6 +2354,7 @@ angular.mock.$ComponentControllerProvider = ['$compileProvider', function($compi
2288
2354
  * * [Google CDN](https://developers.google.com/speed/libraries/devguide#angularjs) e.g.
2289
2355
  * `"//ajax.googleapis.com/ajax/libs/angularjs/X.Y.Z/angular-mocks.js"`
2290
2356
  * * [NPM](https://www.npmjs.com/) e.g. `npm install angular-mocks@X.Y.Z`
2357
+ * * [Yarn](https://yarnpkg.com) e.g. `yarn add angular-mocks@X.Y.Z`
2291
2358
  * * [Bower](http://bower.io) e.g. `bower install angular-mocks#X.Y.Z`
2292
2359
  * * [code.angularjs.org](https://code.angularjs.org/) (discouraged for production use) e.g.
2293
2360
  * `"//code.angularjs.org/X.Y.Z/angular-mocks.js"`
@@ -2319,11 +2386,11 @@ angular.module('ngMock', ['ng']).provider({
2319
2386
  $httpBackend: angular.mock.$HttpBackendProvider,
2320
2387
  $rootElement: angular.mock.$RootElementProvider,
2321
2388
  $componentController: angular.mock.$ComponentControllerProvider
2322
- }).config(['$provide', function($provide) {
2389
+ }).config(['$provide', '$compileProvider', function($provide, $compileProvider) {
2323
2390
  $provide.decorator('$timeout', angular.mock.$TimeoutDecorator);
2324
2391
  $provide.decorator('$$rAF', angular.mock.$RAFDecorator);
2325
2392
  $provide.decorator('$rootScope', angular.mock.$RootScopeDecorator);
2326
- $provide.decorator('$controller', angular.mock.$ControllerDecorator);
2393
+ $provide.decorator('$controller', createControllerDecorator($compileProvider));
2327
2394
  }]);
2328
2395
 
2329
2396
  /**
@@ -2387,7 +2454,7 @@ angular.module('ngMockE2E', ['ng']).config(['$provide', function($provide) {
2387
2454
  * phones.push(phone);
2388
2455
  * return [200, phone, {}];
2389
2456
  * });
2390
- * $httpBackend.whenGET(/^\/templates\//).passThrough(); // Requests for templare are handled by the real server
2457
+ * $httpBackend.whenGET(/^\/templates\//).passThrough(); // Requests for templates are handled by the real server
2391
2458
  * //...
2392
2459
  * });
2393
2460
  * ```
@@ -2399,7 +2466,7 @@ angular.module('ngMockE2E', ['ng']).config(['$provide', function($provide) {
2399
2466
  * <file name="app.js">
2400
2467
  * var myApp = angular.module('myApp', []);
2401
2468
  *
2402
- * myApp.controller('main', function($http) {
2469
+ * myApp.controller('MainCtrl', function MainCtrl($http) {
2403
2470
  * var ctrl = this;
2404
2471
  *
2405
2472
  * ctrl.phones = [];
@@ -2441,7 +2508,7 @@ angular.module('ngMockE2E', ['ng']).config(['$provide', function($provide) {
2441
2508
  * });
2442
2509
  * </file>
2443
2510
  * <file name="index.html">
2444
- * <div ng-controller="main as $ctrl">
2511
+ * <div ng-controller="MainCtrl as $ctrl">
2445
2512
  * <form name="newPhoneForm" ng-submit="$ctrl.addPhone($ctrl.newPhone)">
2446
2513
  * <input type="text" ng-model="$ctrl.newPhone.name">
2447
2514
  * <input type="submit" value="Add Phone">
@@ -2465,7 +2532,7 @@ angular.module('ngMockE2E', ['ng']).config(['$provide', function($provide) {
2465
2532
  * Creates a new backend definition.
2466
2533
  *
2467
2534
  * @param {string} method HTTP method.
2468
- * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
2535
+ * @param {string|RegExp|function(string)=} url HTTP url or function that receives a url
2469
2536
  * and returns true if the url matches the current definition.
2470
2537
  * @param {(string|RegExp)=} data HTTP request body.
2471
2538
  * @param {(Object|function(Object))=} headers HTTP headers or function that receives http header
@@ -2497,7 +2564,7 @@ angular.module('ngMockE2E', ['ng']).config(['$provide', function($provide) {
2497
2564
  * @description
2498
2565
  * Creates a new backend definition for GET requests. For more info see `when()`.
2499
2566
  *
2500
- * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
2567
+ * @param {string|RegExp|function(string)=} url HTTP url or function that receives a url
2501
2568
  * and returns true if the url matches the current definition.
2502
2569
  * @param {(Object|function(Object))=} headers HTTP headers.
2503
2570
  * @param {(Array)=} keys Array of keys to assign to regex matches in request url described on
@@ -2514,7 +2581,7 @@ angular.module('ngMockE2E', ['ng']).config(['$provide', function($provide) {
2514
2581
  * @description
2515
2582
  * Creates a new backend definition for HEAD requests. For more info see `when()`.
2516
2583
  *
2517
- * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
2584
+ * @param {string|RegExp|function(string)=} url HTTP url or function that receives a url
2518
2585
  * and returns true if the url matches the current definition.
2519
2586
  * @param {(Object|function(Object))=} headers HTTP headers.
2520
2587
  * @param {(Array)=} keys Array of keys to assign to regex matches in request url described on
@@ -2531,7 +2598,7 @@ angular.module('ngMockE2E', ['ng']).config(['$provide', function($provide) {
2531
2598
  * @description
2532
2599
  * Creates a new backend definition for DELETE requests. For more info see `when()`.
2533
2600
  *
2534
- * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
2601
+ * @param {string|RegExp|function(string)=} url HTTP url or function that receives a url
2535
2602
  * and returns true if the url matches the current definition.
2536
2603
  * @param {(Object|function(Object))=} headers HTTP headers.
2537
2604
  * @param {(Array)=} keys Array of keys to assign to regex matches in request url described on
@@ -2548,7 +2615,7 @@ angular.module('ngMockE2E', ['ng']).config(['$provide', function($provide) {
2548
2615
  * @description
2549
2616
  * Creates a new backend definition for POST requests. For more info see `when()`.
2550
2617
  *
2551
- * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
2618
+ * @param {string|RegExp|function(string)=} url HTTP url or function that receives a url
2552
2619
  * and returns true if the url matches the current definition.
2553
2620
  * @param {(string|RegExp)=} data HTTP request body.
2554
2621
  * @param {(Object|function(Object))=} headers HTTP headers.
@@ -2566,7 +2633,7 @@ angular.module('ngMockE2E', ['ng']).config(['$provide', function($provide) {
2566
2633
  * @description
2567
2634
  * Creates a new backend definition for PUT requests. For more info see `when()`.
2568
2635
  *
2569
- * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
2636
+ * @param {string|RegExp|function(string)=} url HTTP url or function that receives a url
2570
2637
  * and returns true if the url matches the current definition.
2571
2638
  * @param {(string|RegExp)=} data HTTP request body.
2572
2639
  * @param {(Object|function(Object))=} headers HTTP headers.
@@ -2584,7 +2651,7 @@ angular.module('ngMockE2E', ['ng']).config(['$provide', function($provide) {
2584
2651
  * @description
2585
2652
  * Creates a new backend definition for PATCH requests. For more info see `when()`.
2586
2653
  *
2587
- * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
2654
+ * @param {string|RegExp|function(string)=} url HTTP url or function that receives a url
2588
2655
  * and returns true if the url matches the current definition.
2589
2656
  * @param {(string|RegExp)=} data HTTP request body.
2590
2657
  * @param {(Object|function(Object))=} headers HTTP headers.
@@ -2602,7 +2669,7 @@ angular.module('ngMockE2E', ['ng']).config(['$provide', function($provide) {
2602
2669
  * @description
2603
2670
  * Creates a new backend definition for JSONP requests. For more info see `when()`.
2604
2671
  *
2605
- * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
2672
+ * @param {string|RegExp|function(string)=} url HTTP url or function that receives a url
2606
2673
  * and returns true if the url matches the current definition.
2607
2674
  * @param {(Array)=} keys Array of keys to assign to regex matches in request url described on
2608
2675
  * {@link ngMock.$httpBackend $httpBackend mock}.
@@ -2654,6 +2721,7 @@ angular.mock.$RootScopeDecorator = ['$delegate', function($delegate) {
2654
2721
  * @ngdoc method
2655
2722
  * @name $rootScope.Scope#$countChildScopes
2656
2723
  * @module ngMock
2724
+ * @this $rootScope.Scope
2657
2725
  * @description
2658
2726
  * Counts all the direct and indirect child scopes of the current scope.
2659
2727
  *
@@ -2662,7 +2730,6 @@ angular.mock.$RootScopeDecorator = ['$delegate', function($delegate) {
2662
2730
  * @returns {number} Total number of child scopes.
2663
2731
  */
2664
2732
  function countChildScopes() {
2665
- // jshint validthis: true
2666
2733
  var count = 0; // exclude the current scope
2667
2734
  var pendingChildHeads = [this.$$childHead];
2668
2735
  var currentScope;
@@ -2684,6 +2751,7 @@ angular.mock.$RootScopeDecorator = ['$delegate', function($delegate) {
2684
2751
  /**
2685
2752
  * @ngdoc method
2686
2753
  * @name $rootScope.Scope#$countWatchers
2754
+ * @this $rootScope.Scope
2687
2755
  * @module ngMock
2688
2756
  * @description
2689
2757
  * Counts all the watchers of direct and indirect child scopes of the current scope.
@@ -2694,7 +2762,6 @@ angular.mock.$RootScopeDecorator = ['$delegate', function($delegate) {
2694
2762
  * @returns {number} Total number of watchers.
2695
2763
  */
2696
2764
  function countWatchers() {
2697
- // jshint validthis: true
2698
2765
  var count = this.$$watchers ? this.$$watchers.length : 0; // include the current scope
2699
2766
  var pendingChildHeads = [this.$$childHead];
2700
2767
  var currentScope;
@@ -2714,7 +2781,7 @@ angular.mock.$RootScopeDecorator = ['$delegate', function($delegate) {
2714
2781
  }];
2715
2782
 
2716
2783
 
2717
- !(function(jasmineOrMocha) {
2784
+ (function(jasmineOrMocha) {
2718
2785
 
2719
2786
  if (!jasmineOrMocha) {
2720
2787
  return;
@@ -2809,7 +2876,7 @@ angular.mock.$RootScopeDecorator = ['$delegate', function($delegate) {
2809
2876
  *
2810
2877
  * You cannot call `sharedInjector()` from within a context already using `sharedInjector()`.
2811
2878
  *
2812
- * ## Example
2879
+ * ## Example
2813
2880
  *
2814
2881
  * Typically beforeAll is used to make many assertions about a single operation. This can
2815
2882
  * cut down test run-time as the test setup doesn't need to be re-run, and enabling focussed
@@ -2847,14 +2914,14 @@ angular.mock.$RootScopeDecorator = ['$delegate', function($delegate) {
2847
2914
  */
2848
2915
  module.sharedInjector = function() {
2849
2916
  if (!(module.$$beforeAllHook && module.$$afterAllHook)) {
2850
- throw Error("sharedInjector() cannot be used unless your test runner defines beforeAll/afterAll");
2917
+ throw Error('sharedInjector() cannot be used unless your test runner defines beforeAll/afterAll');
2851
2918
  }
2852
2919
 
2853
2920
  var initialized = false;
2854
2921
 
2855
- module.$$beforeAllHook(function() {
2922
+ module.$$beforeAllHook(/** @this */ function() {
2856
2923
  if (injectorState.shared) {
2857
- injectorState.sharedError = Error("sharedInjector() cannot be called inside a context that has already called sharedInjector()");
2924
+ injectorState.sharedError = Error('sharedInjector() cannot be called inside a context that has already called sharedInjector()');
2858
2925
  throw injectorState.sharedError;
2859
2926
  }
2860
2927
  initialized = true;
@@ -2873,10 +2940,10 @@ angular.mock.$RootScopeDecorator = ['$delegate', function($delegate) {
2873
2940
  };
2874
2941
 
2875
2942
  module.$$beforeEach = function() {
2876
- if (injectorState.shared && currentSpec && currentSpec != this) {
2943
+ if (injectorState.shared && currentSpec && currentSpec !== this) {
2877
2944
  var state = currentSpec;
2878
2945
  currentSpec = this;
2879
- angular.forEach(["$injector","$modules","$providerInjector", "$injectorStrict"], function(k) {
2946
+ angular.forEach(['$injector','$modules','$providerInjector', '$injectorStrict'], function(k) {
2880
2947
  currentSpec[k] = state[k];
2881
2948
  state[k] = null;
2882
2949
  });
@@ -2967,7 +3034,7 @@ angular.mock.$RootScopeDecorator = ['$delegate', function($delegate) {
2967
3034
  * These are ignored by the injector when the reference name is resolved.
2968
3035
  *
2969
3036
  * For example, the parameter `_myService_` would be resolved as the reference `myService`.
2970
- * Since it is available in the function body as _myService_, we can then assign it to a variable
3037
+ * Since it is available in the function body as `_myService_`, we can then assign it to a variable
2971
3038
  * defined in an outer scope.
2972
3039
  *
2973
3040
  * ```
@@ -3031,7 +3098,7 @@ angular.mock.$RootScopeDecorator = ['$delegate', function($delegate) {
3031
3098
 
3032
3099
 
3033
3100
 
3034
- var ErrorAddingDeclarationLocationStack = function(e, errorForStack) {
3101
+ var ErrorAddingDeclarationLocationStack = function ErrorAddingDeclarationLocationStack(e, errorForStack) {
3035
3102
  this.message = e.message;
3036
3103
  this.name = e.name;
3037
3104
  if (e.line) this.line = e.line;
@@ -3049,11 +3116,11 @@ angular.mock.$RootScopeDecorator = ['$delegate', function($delegate) {
3049
3116
  if (!errorForStack.stack) {
3050
3117
  try {
3051
3118
  throw errorForStack;
3052
- } catch (e) {}
3119
+ } catch (e) { /* empty */ }
3053
3120
  }
3054
- return wasInjectorCreated() ? workFn.call(currentSpec) : workFn;
3121
+ return wasInjectorCreated() ? WorkFn.call(currentSpec) : WorkFn;
3055
3122
  /////////////////////
3056
- function workFn() {
3123
+ function WorkFn() {
3057
3124
  var modules = currentSpec.$modules || [];
3058
3125
  var strictDi = !!currentSpec.$injectorStrict;
3059
3126
  modules.unshift(['$injector', function($injector) {
@@ -3066,7 +3133,7 @@ angular.mock.$RootScopeDecorator = ['$delegate', function($delegate) {
3066
3133
  if (strictDi) {
3067
3134
  // If strictDi is enabled, annotate the providerInjector blocks
3068
3135
  angular.forEach(modules, function(moduleFn) {
3069
- if (typeof moduleFn === "function") {
3136
+ if (typeof moduleFn === 'function') {
3070
3137
  angular.injector.$$annotate(moduleFn);
3071
3138
  }
3072
3139
  });
@@ -3081,9 +3148,7 @@ angular.mock.$RootScopeDecorator = ['$delegate', function($delegate) {
3081
3148
  injector.annotate(blockFns[i]);
3082
3149
  }
3083
3150
  try {
3084
- /* jshint -W040 *//* Jasmine explicitly provides a `this` object when calling functions */
3085
3151
  injector.invoke(blockFns[i] || angular.noop, this);
3086
- /* jshint +W040 */
3087
3152
  } catch (e) {
3088
3153
  if (e.stack && errorForStack) {
3089
3154
  throw new ErrorAddingDeclarationLocationStack(e, errorForStack);
@@ -3122,5 +3187,218 @@ angular.mock.$RootScopeDecorator = ['$delegate', function($delegate) {
3122
3187
  }
3123
3188
  })(window.jasmine || window.mocha);
3124
3189
 
3190
+ 'use strict';
3191
+
3192
+ (function() {
3193
+ /**
3194
+ * Triggers a browser event. Attempts to choose the right event if one is
3195
+ * not specified.
3196
+ *
3197
+ * @param {Object} element Either a wrapped jQuery/jqLite node or a DOMElement
3198
+ * @param {string} eventType Optional event type
3199
+ * @param {Object=} eventData An optional object which contains additional event data (such as x,y
3200
+ * coordinates, keys, etc...) that are passed into the event when triggered
3201
+ */
3202
+ window.browserTrigger = function browserTrigger(element, eventType, eventData) {
3203
+ if (element && !element.nodeName) element = element[0];
3204
+ if (!element) return;
3205
+
3206
+ eventData = eventData || {};
3207
+ var relatedTarget = eventData.relatedTarget || element;
3208
+ var keys = eventData.keys;
3209
+ var x = eventData.x;
3210
+ var y = eventData.y;
3211
+
3212
+ var inputType = (element.type) ? element.type.toLowerCase() : null,
3213
+ nodeName = element.nodeName.toLowerCase();
3214
+ if (!eventType) {
3215
+ eventType = {
3216
+ 'text': 'change',
3217
+ 'textarea': 'change',
3218
+ 'hidden': 'change',
3219
+ 'password': 'change',
3220
+ 'button': 'click',
3221
+ 'submit': 'click',
3222
+ 'reset': 'click',
3223
+ 'image': 'click',
3224
+ 'checkbox': 'click',
3225
+ 'radio': 'click',
3226
+ 'select-one': 'change',
3227
+ 'select-multiple': 'change',
3228
+ '_default_': 'click'
3229
+ }[inputType || '_default_'];
3230
+ }
3231
+
3232
+ if (nodeName === 'option') {
3233
+ element.parentNode.value = element.value;
3234
+ element = element.parentNode;
3235
+ eventType = 'change';
3236
+ }
3237
+
3238
+ keys = keys || [];
3239
+ function pressed(key) {
3240
+ return keys.indexOf(key) !== -1;
3241
+ }
3242
+
3243
+ var evnt;
3244
+ if (/transitionend/.test(eventType)) {
3245
+ if (window.WebKitTransitionEvent) {
3246
+ evnt = new window.WebKitTransitionEvent(eventType, eventData);
3247
+ evnt.initEvent(eventType, false, true);
3248
+ } else {
3249
+ try {
3250
+ evnt = new window.TransitionEvent(eventType, eventData);
3251
+ } catch (e) {
3252
+ evnt = window.document.createEvent('TransitionEvent');
3253
+ evnt.initTransitionEvent(eventType, null, null, null, eventData.elapsedTime || 0);
3254
+ }
3255
+ }
3256
+ } else if (/animationend/.test(eventType)) {
3257
+ if (window.WebKitAnimationEvent) {
3258
+ evnt = new window.WebKitAnimationEvent(eventType, eventData);
3259
+ evnt.initEvent(eventType, false, true);
3260
+ } else {
3261
+ try {
3262
+ evnt = new window.AnimationEvent(eventType, eventData);
3263
+ } catch (e) {
3264
+ evnt = window.document.createEvent('AnimationEvent');
3265
+ evnt.initAnimationEvent(eventType, null, null, null, eventData.elapsedTime || 0);
3266
+ }
3267
+ }
3268
+ } else if (/touch/.test(eventType) && supportsTouchEvents()) {
3269
+ evnt = createTouchEvent(element, eventType, x, y);
3270
+ } else if (/key/.test(eventType)) {
3271
+ evnt = window.document.createEvent('Events');
3272
+ evnt.initEvent(eventType, eventData.bubbles, eventData.cancelable);
3273
+ evnt.view = window;
3274
+ evnt.ctrlKey = pressed('ctrl');
3275
+ evnt.altKey = pressed('alt');
3276
+ evnt.shiftKey = pressed('shift');
3277
+ evnt.metaKey = pressed('meta');
3278
+ evnt.keyCode = eventData.keyCode;
3279
+ evnt.charCode = eventData.charCode;
3280
+ evnt.which = eventData.which;
3281
+ } else {
3282
+ evnt = window.document.createEvent('MouseEvents');
3283
+ x = x || 0;
3284
+ y = y || 0;
3285
+ evnt.initMouseEvent(eventType, true, true, window, 0, x, y, x, y, pressed('ctrl'),
3286
+ pressed('alt'), pressed('shift'), pressed('meta'), 0, relatedTarget);
3287
+ }
3288
+
3289
+ /* we're unable to change the timeStamp value directly so this
3290
+ * is only here to allow for testing where the timeStamp value is
3291
+ * read */
3292
+ evnt.$manualTimeStamp = eventData.timeStamp;
3293
+
3294
+ if (!evnt) return;
3295
+
3296
+ var originalPreventDefault = evnt.preventDefault,
3297
+ appWindow = element.ownerDocument.defaultView,
3298
+ fakeProcessDefault = true,
3299
+ finalProcessDefault,
3300
+ angular = appWindow.angular || {};
3301
+
3302
+ // igor: temporary fix for https://bugzilla.mozilla.org/show_bug.cgi?id=684208
3303
+ angular['ff-684208-preventDefault'] = false;
3304
+ evnt.preventDefault = function() {
3305
+ fakeProcessDefault = false;
3306
+ return originalPreventDefault.apply(evnt, arguments);
3307
+ };
3308
+
3309
+ if (!eventData.bubbles || supportsEventBubblingInDetachedTree() || isAttachedToDocument(element)) {
3310
+ element.dispatchEvent(evnt);
3311
+ } else {
3312
+ triggerForPath(element, evnt);
3313
+ }
3314
+
3315
+ finalProcessDefault = !(angular['ff-684208-preventDefault'] || !fakeProcessDefault);
3316
+
3317
+ delete angular['ff-684208-preventDefault'];
3318
+
3319
+ return finalProcessDefault;
3320
+ };
3321
+
3322
+ function supportsTouchEvents() {
3323
+ if ('_cached' in supportsTouchEvents) {
3324
+ return supportsTouchEvents._cached;
3325
+ }
3326
+ if (!window.document.createTouch || !window.document.createTouchList) {
3327
+ supportsTouchEvents._cached = false;
3328
+ return false;
3329
+ }
3330
+ try {
3331
+ window.document.createEvent('TouchEvent');
3332
+ } catch (e) {
3333
+ supportsTouchEvents._cached = false;
3334
+ return false;
3335
+ }
3336
+ supportsTouchEvents._cached = true;
3337
+ return true;
3338
+ }
3339
+
3340
+ function createTouchEvent(element, eventType, x, y) {
3341
+ var evnt = new window.Event(eventType);
3342
+ x = x || 0;
3343
+ y = y || 0;
3344
+
3345
+ var touch = window.document.createTouch(window, element, Date.now(), x, y, x, y);
3346
+ var touches = window.document.createTouchList(touch);
3347
+
3348
+ evnt.touches = touches;
3349
+
3350
+ return evnt;
3351
+ }
3352
+
3353
+ function supportsEventBubblingInDetachedTree() {
3354
+ if ('_cached' in supportsEventBubblingInDetachedTree) {
3355
+ return supportsEventBubblingInDetachedTree._cached;
3356
+ }
3357
+ supportsEventBubblingInDetachedTree._cached = false;
3358
+ var doc = window.document;
3359
+ if (doc) {
3360
+ var parent = doc.createElement('div'),
3361
+ child = parent.cloneNode();
3362
+ parent.appendChild(child);
3363
+ parent.addEventListener('e', function() {
3364
+ supportsEventBubblingInDetachedTree._cached = true;
3365
+ });
3366
+ var evnt = window.document.createEvent('Events');
3367
+ evnt.initEvent('e', true, true);
3368
+ child.dispatchEvent(evnt);
3369
+ }
3370
+ return supportsEventBubblingInDetachedTree._cached;
3371
+ }
3372
+
3373
+ function triggerForPath(element, evnt) {
3374
+ var stop = false;
3375
+
3376
+ var _stopPropagation = evnt.stopPropagation;
3377
+ evnt.stopPropagation = function() {
3378
+ stop = true;
3379
+ _stopPropagation.apply(evnt, arguments);
3380
+ };
3381
+ patchEventTargetForBubbling(evnt, element);
3382
+ do {
3383
+ element.dispatchEvent(evnt);
3384
+ // eslint-disable-next-line no-unmodified-loop-condition
3385
+ } while (!stop && (element = element.parentNode));
3386
+ }
3387
+
3388
+ function patchEventTargetForBubbling(event, target) {
3389
+ event._target = target;
3390
+ Object.defineProperty(event, 'target', {get: function() { return this._target;}});
3391
+ }
3392
+
3393
+ function isAttachedToDocument(element) {
3394
+ while ((element = element.parentNode)) {
3395
+ if (element === window) {
3396
+ return true;
3397
+ }
3398
+ }
3399
+ return false;
3400
+ }
3401
+ })();
3402
+
3125
3403
 
3126
3404
  })(window, window.angular);