teabag 0.7.1 → 0.7.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (148) hide show
  1. data/app/assets/javascripts/teabag-mocha.js +154 -123
  2. data/app/assets/javascripts/teabag-qunit.js +401 -195
  3. data/app/assets/javascripts/teabag-teabag.js +3 -4
  4. data/app/assets/javascripts/teabag/mocha.coffee +1 -1
  5. data/app/assets/javascripts/teabag/mocha/reporters/html.coffee +1 -1
  6. data/app/assets/javascripts/teabag/qunit.coffee +1 -1
  7. data/app/assets/javascripts/teabag/qunit/reporters/html.coffee +1 -1
  8. data/app/assets/javascripts/teabag/teabag.coffee +1 -0
  9. data/lib/teabag/version.rb +1 -1
  10. data/spec/dummy/log/development.log +18711 -0
  11. data/spec/dummy/log/test.log +632 -0
  12. data/spec/dummy/tmp/cache/assets/C35/A30/sprockets%2F29906bf540f7d2e081088494b2554989 +0 -0
  13. data/spec/dummy/tmp/cache/assets/C4E/9B0/sprockets%2Fa807397434c9262c3d62da3e91152184 +0 -0
  14. data/spec/dummy/tmp/cache/assets/C5B/D00/sprockets%2F01f43815683089878e371a5d078d3e2c +0 -0
  15. data/spec/dummy/tmp/cache/assets/C72/150/sprockets%2F4194031b4b51b6422c14ac697e3455e5 +0 -0
  16. data/spec/dummy/tmp/cache/assets/C75/D50/sprockets%2F5302968a40e08d2c011aa38666d273f6 +0 -0
  17. data/spec/dummy/tmp/cache/assets/C78/F80/sprockets%2F9161622ddd251097a4ab816b8220984c +0 -0
  18. data/spec/dummy/tmp/cache/assets/C7C/AC0/sprockets%2F29124be1160817c61bb4878894b2ba55 +0 -0
  19. data/spec/dummy/tmp/cache/assets/C7D/8F0/sprockets%2Ff13d01b85f2449a4f0638ff260425906 +0 -0
  20. data/spec/dummy/tmp/cache/assets/C7E/E80/sprockets%2F38544f84f61bb3942d24104e39e108c4 +0 -0
  21. data/spec/dummy/tmp/cache/assets/C85/6E0/sprockets%2F9e583044ba9762ac39f15431ed504495 +0 -0
  22. data/spec/dummy/tmp/cache/assets/C8A/460/sprockets%2F77bffd9959420103906722b404ae8d59 +0 -0
  23. data/spec/dummy/tmp/cache/assets/C91/FA0/sprockets%2F2eb81283f5789ae91a69344552db3856 +0 -0
  24. data/spec/dummy/tmp/cache/assets/C97/430/sprockets%2Fc049582fd1c9178ff983323f75326f64 +0 -0
  25. data/spec/dummy/tmp/cache/assets/C9D/E90/sprockets%2F3045c9533f179d3e1c805d163ed002a0 +0 -0
  26. data/spec/dummy/tmp/cache/assets/CA3/C80/sprockets%2F00916393d1e2e947ddafa91701411a73 +0 -0
  27. data/spec/dummy/tmp/cache/assets/CA6/DF0/sprockets%2F7da83747ce56e49393b6b8726587f846 +0 -0
  28. data/spec/dummy/tmp/cache/assets/CA9/C40/sprockets%2F932b7e2cd1e067289ab51190800814df +0 -0
  29. data/spec/dummy/tmp/cache/assets/CAD/410/sprockets%2F651414e5c7e86f05c5108dc71626b25c +0 -0
  30. data/spec/dummy/tmp/cache/assets/CAF/0F0/sprockets%2F6000e67cf3f2377f860c24da7c819701 +0 -0
  31. data/spec/dummy/tmp/cache/assets/CB0/700/sprockets%2F006af6bf0f6b55777b03c4615c853881 +0 -0
  32. data/spec/dummy/tmp/cache/assets/CB1/B50/sprockets%2F44b5b96ee7652d66a217a1756431c4a8 +0 -0
  33. data/spec/dummy/tmp/cache/assets/CB6/120/sprockets%2F2df706e820de0f82332a613c49f47867 +0 -0
  34. data/spec/dummy/tmp/cache/assets/CBB/FA0/sprockets%2F74922109263bdc965b2e9567eec6d154 +0 -0
  35. data/spec/dummy/tmp/cache/assets/CBD/AF0/sprockets%2Fd687ec33822256e9444e8cd04f1b4873 +0 -0
  36. data/spec/dummy/tmp/cache/assets/CBF/630/sprockets%2F707d2db81468088470d476abff35388d +0 -0
  37. data/spec/dummy/tmp/cache/assets/CC2/EC0/sprockets%2F76bf80cb571ca530357f78db78167866 +0 -0
  38. data/spec/dummy/tmp/cache/assets/CCB/3B0/sprockets%2F9535146026add9cffa012ee220204a66 +0 -0
  39. data/spec/dummy/tmp/cache/assets/CCC/DB0/sprockets%2F3998958d61cda73452466f5652ed81ef +0 -0
  40. data/spec/dummy/tmp/cache/assets/CCE/C50/sprockets%2Fe12774c2fea852112414bb379a71f31a +0 -0
  41. data/spec/dummy/tmp/cache/assets/CD3/460/sprockets%2F7f3f6802b0b309ed142d0b671c9640c4 +0 -0
  42. data/spec/dummy/tmp/cache/assets/CD6/DD0/sprockets%2F301bd3b0e19eb866905681d03a891be3 +0 -0
  43. data/spec/dummy/tmp/cache/assets/CE0/090/sprockets%2F48d5d35ae87d0723318b8bc257fa2237 +0 -0
  44. data/spec/dummy/tmp/cache/assets/CE3/1F0/sprockets%2Fe69a515d3a9d14c669be8871012a7d07 +0 -0
  45. data/spec/dummy/tmp/cache/assets/CE4/190/sprockets%2F36c9ee4181433e33e07eb9748d218ae2 +0 -0
  46. data/spec/dummy/tmp/cache/assets/CE6/270/sprockets%2F2c98152560d18470fec8cf4c6829b4d0 +0 -0
  47. data/spec/dummy/tmp/cache/assets/CE6/7C0/sprockets%2Fa03a2c86ce6724be8542295e1cf24798 +0 -0
  48. data/spec/dummy/tmp/cache/assets/CE7/A60/sprockets%2Ff58eee249aa167d23f8220087bb46684 +0 -0
  49. data/spec/dummy/tmp/cache/assets/CE9/9E0/sprockets%2F135480d497ed7e4884462dc0ef0b80d7 +0 -0
  50. data/spec/dummy/tmp/cache/assets/CEB/680/sprockets%2F67f0794ef8c0576d5c7da34f4437305a +0 -0
  51. data/spec/dummy/tmp/cache/assets/CEB/B40/sprockets%2F1150bf8d912aa100a132251eefaf6045 +0 -0
  52. data/spec/dummy/tmp/cache/assets/CEC/360/sprockets%2F264b79dde726b36d63fee272a0609469 +0 -0
  53. data/spec/dummy/tmp/cache/assets/CEE/930/sprockets%2Fe196521e15fd8d33e3261d5538fe8f92 +0 -0
  54. data/spec/dummy/tmp/cache/assets/CEF/650/sprockets%2Fe859309c630f7637a53d381b327df8fd +0 -0
  55. data/spec/dummy/tmp/cache/assets/CEF/840/sprockets%2F16c7d195fa548e8343c6a4d2256ed778 +0 -0
  56. data/spec/dummy/tmp/cache/assets/CF1/C50/sprockets%2F57bd9ac92067ea01882feef075582758 +0 -0
  57. data/spec/dummy/tmp/cache/assets/CF3/3A0/sprockets%2F6571249b82eb52e7c7e035c692df9b69 +0 -0
  58. data/spec/dummy/tmp/cache/assets/CF3/C50/sprockets%2F892b968b622f37b988a1de81e09bf631 +0 -0
  59. data/spec/dummy/tmp/cache/assets/CF8/780/sprockets%2F8845b81ff27cdb57c835836c9f91a265 +0 -0
  60. data/spec/dummy/tmp/cache/assets/CFA/D20/sprockets%2Fb26796b39b3c5d6ed70be7989637a493 +0 -0
  61. data/spec/dummy/tmp/cache/assets/CFB/210/sprockets%2F9104695bfbf9a9d4b94382e6e90487a9 +0 -0
  62. data/spec/dummy/tmp/cache/assets/CFC/380/sprockets%2Fa7443cbd671446a589867dd5f4a4f989 +0 -0
  63. data/spec/dummy/tmp/cache/assets/D00/110/sprockets%2F6a6353b7723a8b21708e0fbfe04bd422 +0 -0
  64. data/spec/dummy/tmp/cache/assets/D00/F60/sprockets%2F42e279b52511c47d26c0adb125fd04e8 +0 -0
  65. data/spec/dummy/tmp/cache/assets/D02/570/sprockets%2F51fa8dc514e6256ae0836d5eb24e0312 +0 -0
  66. data/spec/dummy/tmp/cache/assets/D03/630/sprockets%2F5d8da32dba6a7be70426a1d554773701 +0 -0
  67. data/spec/dummy/tmp/cache/assets/D04/170/sprockets%2F76ab1dc02e6c7618852708a1e05a2df3 +0 -0
  68. data/spec/dummy/tmp/cache/assets/D04/480/sprockets%2F8bd8f10500b21d2f9d94e4cd1401c936 +0 -0
  69. data/spec/dummy/tmp/cache/assets/D05/8D0/sprockets%2F319f8f235f452343f1ebf03cb262d23d +0 -0
  70. data/spec/dummy/tmp/cache/assets/D09/BF0/sprockets%2F9e6bca5d26f50d9484385d51ba04312c +0 -0
  71. data/spec/dummy/tmp/cache/assets/D0B/210/sprockets%2Fb95ce127097fba0e4019f633e91b730d +0 -0
  72. data/spec/dummy/tmp/cache/assets/D0E/570/sprockets%2F90fe371bf8091e88a712124d9cdae260 +0 -0
  73. data/spec/dummy/tmp/cache/assets/D11/080/sprockets%2Fe202468befa786e2a3e7c6d5980b2333 +0 -0
  74. data/spec/dummy/tmp/cache/assets/D15/750/sprockets%2F8effdd3e668a4036260a3e370f3b6657 +0 -0
  75. data/spec/dummy/tmp/cache/assets/D17/710/sprockets%2Ffa49fb6823d466e79a195e0cd71340c5 +0 -0
  76. data/spec/dummy/tmp/cache/assets/D1D/560/sprockets%2F1ca784ee7ba1922465147e7f8963eae5 +0 -0
  77. data/spec/dummy/tmp/cache/assets/D1E/AA0/sprockets%2F5c8741a556bc955cd36e61c88582b6dc +0 -0
  78. data/spec/dummy/tmp/cache/assets/D22/4D0/sprockets%2Fe94f07f16b94d5cf185c48023f98f1b7 +0 -0
  79. data/spec/dummy/tmp/cache/assets/D2D/060/sprockets%2F545ec7a363badb5e7106e5112b53b26d +0 -0
  80. data/spec/dummy/tmp/cache/assets/D30/740/sprockets%2F4ac342b2e0244e90d08bac61f54f4f82 +0 -0
  81. data/spec/dummy/tmp/cache/assets/D31/9C0/sprockets%2Fbd102a4f5a4985c3519dd6ab0295a1c6 +0 -0
  82. data/spec/dummy/tmp/cache/assets/D35/7C0/sprockets%2Ff536a2606eaf7d542c0985104cb62baf +0 -0
  83. data/spec/dummy/tmp/cache/assets/D37/FF0/sprockets%2F96841ca4cfae32c515077f3f5fc303b2 +0 -0
  84. data/spec/dummy/tmp/cache/assets/D3C/840/sprockets%2Fc6202ec91d567a85bd3d46dc43ea9108 +0 -0
  85. data/spec/dummy/tmp/cache/assets/D44/0F0/sprockets%2Fc4d293b967c2e290deed3f3bd2271828 +0 -0
  86. data/spec/dummy/tmp/cache/assets/D44/E90/sprockets%2F05cfc0bf7c9938963d1d1c63248db80d +0 -0
  87. data/spec/dummy/tmp/cache/assets/D45/C30/sprockets%2Fcc744877558178a3adb77c441cadce70 +0 -0
  88. data/spec/dummy/tmp/cache/assets/D48/BA0/sprockets%2F30a5bfc94bac88df67501fc509b84694 +0 -0
  89. data/spec/dummy/tmp/cache/assets/D49/A10/sprockets%2Fc4656bd995a6f297c26d19b13aadb963 +0 -0
  90. data/spec/dummy/tmp/cache/assets/D4A/580/sprockets%2F19b8d8a9a57850de79b6c099fb2d010e +0 -0
  91. data/spec/dummy/tmp/cache/assets/D50/D70/sprockets%2Fe2a3e6c95b11e0801a4eebae3a026026 +0 -0
  92. data/spec/dummy/tmp/cache/assets/D51/400/sprockets%2Ff5e433d8a31e80985b75ce598de236be +0 -0
  93. data/spec/dummy/tmp/cache/assets/D54/D80/sprockets%2F631327e25ec20edc723046cdec3bb1c0 +0 -0
  94. data/spec/dummy/tmp/cache/assets/D5C/710/sprockets%2F9427d05cee2caa721241a25a9af1d08f +0 -0
  95. data/spec/dummy/tmp/cache/assets/D5C/CC0/sprockets%2Faa8bf6de211f2765b0a26f112b971f0c +0 -0
  96. data/spec/dummy/tmp/cache/assets/D61/1F0/sprockets%2F0c7a6176d2fc4db00bb9a74d36380fe1 +0 -0
  97. data/spec/dummy/tmp/cache/assets/D63/050/sprockets%2Fae26cd0ae2c0da97e49f6043b91008d5 +0 -0
  98. data/spec/dummy/tmp/cache/assets/D67/BC0/sprockets%2F35d2c2b45981ade5a2db2a9c7f37a615 +0 -0
  99. data/spec/dummy/tmp/cache/assets/D67/C20/sprockets%2F0d30bf27e5f74bbd85f313cb8d3c4623 +0 -0
  100. data/spec/dummy/tmp/cache/assets/D69/F90/sprockets%2F6a0795b7b38bd7e6142cd1b88211dade +0 -0
  101. data/spec/dummy/tmp/cache/assets/D6D/530/sprockets%2F8d52dee91bff01a8a2306d8a7c9152a9 +0 -0
  102. data/spec/dummy/tmp/cache/assets/D6D/DA0/sprockets%2Fac936bf40b42227a2bf9d474ae9ec149 +0 -0
  103. data/spec/dummy/tmp/cache/assets/D77/B30/sprockets%2F946cf2f17c7eb41037f9ee08ad67ec40 +0 -0
  104. data/spec/dummy/tmp/cache/assets/D78/2F0/sprockets%2F3c61f8915b8f717b1de788e6ecad122c +0 -0
  105. data/spec/dummy/tmp/cache/assets/D80/390/sprockets%2Fe44158f578d9ffade083a07f54eab729 +0 -0
  106. data/spec/dummy/tmp/cache/assets/D8C/520/sprockets%2F221cd58a042baac534d27e4cfedc1188 +0 -0
  107. data/spec/dummy/tmp/cache/assets/D93/BD0/sprockets%2Ff5e1b60201e08e3ddf8d3de5211f3d5e +0 -0
  108. data/spec/dummy/tmp/cache/assets/D9B/C20/sprockets%2F0e01606ddd95e451bc7d39ce0eeb664d +0 -0
  109. data/spec/dummy/tmp/cache/assets/DA0/330/sprockets%2Fcbbb4de706387d50f48a72ee6c9c1b80 +0 -0
  110. data/spec/dummy/tmp/cache/assets/DA5/0A0/sprockets%2F7a4b5928cec69ab65afff309a04d6b47 +0 -0
  111. data/spec/dummy/tmp/cache/assets/DAE/6C0/sprockets%2F77c7a8676aeefa73156c55dfcf51cc46 +0 -0
  112. data/spec/dummy/tmp/cache/assets/DAF/7C0/sprockets%2F8942514d59e7bffbfb33cde6fa9735c2 +0 -0
  113. data/spec/dummy/tmp/cache/assets/DB3/5D0/sprockets%2Fce1d4d75832c9bdeafd869f6f7b61725 +0 -0
  114. data/spec/dummy/tmp/cache/assets/DB3/D70/sprockets%2Fcc2f5e1f6eeb99c33881848cb1cde758 +0 -0
  115. data/spec/dummy/tmp/cache/assets/DB5/040/sprockets%2F9a9da5df88713663b9fbc945facca891 +0 -0
  116. data/spec/dummy/tmp/cache/assets/DC3/230/sprockets%2Fdf52e72eb73be91eccc60182191aed0b +0 -0
  117. data/spec/dummy/tmp/cache/assets/DC7/A10/sprockets%2F84a8af0fcbf401864e1ae5bf092cba94 +0 -0
  118. data/spec/dummy/tmp/cache/assets/DCD/EB0/sprockets%2F4f77f509126ecbced7ea2a5ab290c8d4 +0 -0
  119. data/spec/dummy/tmp/cache/assets/DD8/C10/sprockets%2Ffb91282efc9f16ebaf7e98e312ce0b73 +0 -0
  120. data/spec/dummy/tmp/cache/assets/DDB/EF0/sprockets%2Fe790bb18b64df8aa0a9fe94642a9edd8 +0 -0
  121. data/spec/dummy/tmp/cache/assets/DDD/A60/sprockets%2Fff948b6ffe44a3cc3d2d109a39f548fd +0 -0
  122. data/spec/dummy/tmp/cache/assets/DEB/110/sprockets%2F2dbdab0ce5babca645cdb5780004f875 +0 -0
  123. data/spec/dummy/tmp/cache/assets/DF6/0E0/sprockets%2F85b10db6e1afe643aba6d396abdd77f0 +0 -0
  124. data/spec/dummy/tmp/cache/assets/DF7/E10/sprockets%2F25e4253aba9a9adcefb72552fb1ff0c8 +0 -0
  125. data/spec/dummy/tmp/cache/assets/DF9/AD0/sprockets%2Fc700afd7cee3fe9d7ff8352b213b2c4a +0 -0
  126. data/spec/dummy/tmp/cache/assets/DFC/C20/sprockets%2Fd9178ad7e3b401c9fceafd64ea2b50d6 +0 -0
  127. data/spec/dummy/tmp/cache/assets/DFC/C30/sprockets%2Fb50a07cb30b0bd0eec8e98e5de79d65d +0 -0
  128. data/spec/dummy/tmp/cache/assets/E02/6E0/sprockets%2F63d6a5cdb8cefa64ef76b5c6e0fd3720 +0 -0
  129. data/spec/dummy/tmp/cache/assets/E08/BB0/sprockets%2Fefac99af1af28543aef6fb607faa4973 +0 -0
  130. data/spec/dummy/tmp/cache/assets/E0D/070/sprockets%2F0e7ef9a5978dcc6b1abce678ef836c0a +0 -0
  131. data/spec/dummy/tmp/cache/assets/E17/EF0/sprockets%2Fa291ad64a26afd055dfadabbdf03f154 +0 -0
  132. data/spec/dummy/tmp/cache/assets/E2F/790/sprockets%2F7fac280deaa7ef20a77d5c9b5b9cfc34 +0 -0
  133. data/spec/dummy/tmp/cache/assets/E37/9B0/sprockets%2F4defba98cf7befff81450e2b24e90b6d +0 -0
  134. data/spec/dummy/tmp/cache/assets/E41/250/sprockets%2F97cf8fe3d7ffaff076f655aefb36da03 +0 -0
  135. data/spec/dummy/tmp/cache/assets/E58/840/sprockets%2Fab7a15f76acfee8c320dd3cfc2a8c6d5 +0 -0
  136. data/spec/dummy/tmp/cache/assets/E64/1E0/sprockets%2F81ab4c863fbbdec8dd66afc97ebf034d +0 -0
  137. data/spec/dummy/tmp/cache/assets/E6E/260/sprockets%2Fd9f8ab8b91ef582cc6c99a3ba0dedfe6 +0 -0
  138. data/spec/dummy/tmp/cache/assets/E89/4C0/sprockets%2F68b2eedb3cde6fc01d50fead7caf8a18 +0 -0
  139. data/spec/dummy/tmp/cache/assets/F79/360/sprockets%2F0ce035fefee5ebdabc8efabfbdbd6ee4 +0 -0
  140. data/spec/javascripts/teabag/mocha/reporters/html_mspec.coffee +1 -1
  141. data/vendor/assets/javascripts/{mocha-1.8.1.MIT.LICENSE → mocha-1.9.1.MIT.LICENSE} +0 -0
  142. data/vendor/assets/javascripts/{mocha-1.8.1.js → mocha-1.9.1.js} +79 -81
  143. data/vendor/assets/javascripts/{qunit-1.10.0.MIT.LICENSE → qunit-1.11.0.MIT.LICENSE} +0 -0
  144. data/vendor/assets/javascripts/{qunit-1.10.0.js → qunit-1.11.0.js} +319 -144
  145. data/vendor/assets/javascripts/support/chai.js +721 -279
  146. data/vendor/assets/javascripts/support/jasmine-jquery.js +28 -2
  147. data/vendor/assets/javascripts/support/sinon.js +581 -435
  148. metadata +26 -8
@@ -1,5 +1,5 @@
1
1
  /**
2
- * QUnit v1.10.0 - A JavaScript Unit Testing Framework
2
+ * QUnit v1.11.0 - A JavaScript Unit Testing Framework
3
3
  *
4
4
  * http://qunitjs.com
5
5
  *
@@ -11,6 +11,7 @@
11
11
  (function( window ) {
12
12
 
13
13
  var QUnit,
14
+ assert,
14
15
  config,
15
16
  onErrorFnPrev,
16
17
  testId = 0,
@@ -31,6 +32,55 @@
31
32
  return false;
32
33
  }
33
34
  }())
35
+ },
36
+ /**
37
+ * Provides a normalized error string, correcting an issue
38
+ * with IE 7 (and prior) where Error.prototype.toString is
39
+ * not properly implemented
40
+ *
41
+ * Based on http://es5.github.com/#x15.11.4.4
42
+ *
43
+ * @param {String|Error} error
44
+ * @return {String} error message
45
+ */
46
+ errorString = function( error ) {
47
+ var name, message,
48
+ errorString = error.toString();
49
+ if ( errorString.substring( 0, 7 ) === "[object" ) {
50
+ name = error.name ? error.name.toString() : "Error";
51
+ message = error.message ? error.message.toString() : "";
52
+ if ( name && message ) {
53
+ return name + ": " + message;
54
+ } else if ( name ) {
55
+ return name;
56
+ } else if ( message ) {
57
+ return message;
58
+ } else {
59
+ return "Error";
60
+ }
61
+ } else {
62
+ return errorString;
63
+ }
64
+ },
65
+ /**
66
+ * Makes a clone of an object using only Array or Object as base,
67
+ * and copies over the own enumerable properties.
68
+ *
69
+ * @param {Object} obj
70
+ * @return {Object} New object with only the own properties (recursively).
71
+ */
72
+ objectValues = function( obj ) {
73
+ // Grunt 0.3.x uses an older version of jshint that still has jshint/jshint#392.
74
+ /*jshint newcap: false */
75
+ var key, val,
76
+ vals = QUnit.is( "array", obj ) ? [] : {};
77
+ for ( key in obj ) {
78
+ if ( hasOwn.call( obj, key ) ) {
79
+ val = obj[key];
80
+ vals[key] = val === Object(val) ? objectValues(val) : val;
81
+ }
82
+ }
83
+ return vals;
34
84
  };
35
85
 
36
86
  function Test( settings ) {
@@ -48,7 +98,7 @@
48
98
 
49
99
  if ( tests ) {
50
100
  b = document.createElement( "strong" );
51
- b.innerHTML = this.name;
101
+ b.innerHTML = this.nameHtml;
52
102
 
53
103
  // `a` initialized at top of scope
54
104
  a = document.createElement( "a" );
@@ -92,6 +142,7 @@
92
142
  teardown: function() {}
93
143
  }, this.moduleTestEnvironment );
94
144
 
145
+ this.started = +new Date();
95
146
  runLoggingCallbacks( "testStart", QUnit, {
96
147
  name: this.testName,
97
148
  module: this.module
@@ -111,7 +162,7 @@
111
162
  try {
112
163
  this.testEnvironment.setup.call( this.testEnvironment );
113
164
  } catch( e ) {
114
- QUnit.pushFailure( "Setup failed on " + this.testName + ": " + e.message, extractStacktrace( e, 1 ) );
165
+ QUnit.pushFailure( "Setup failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
115
166
  }
116
167
  },
117
168
  run: function() {
@@ -120,22 +171,28 @@
120
171
  var running = id( "qunit-testresult" );
121
172
 
122
173
  if ( running ) {
123
- running.innerHTML = "Running: <br/>" + this.name;
174
+ running.innerHTML = "Running: <br/>" + this.nameHtml;
124
175
  }
125
176
 
126
177
  if ( this.async ) {
127
178
  QUnit.stop();
128
179
  }
129
180
 
181
+ this.callbackStarted = +new Date();
182
+
130
183
  if ( config.notrycatch ) {
131
184
  this.callback.call( this.testEnvironment, QUnit.assert );
185
+ this.callbackRuntime = +new Date() - this.callbackStarted;
132
186
  return;
133
187
  }
134
188
 
135
189
  try {
136
190
  this.callback.call( this.testEnvironment, QUnit.assert );
191
+ this.callbackRuntime = +new Date() - this.callbackStarted;
137
192
  } catch( e ) {
138
- QUnit.pushFailure( "Died on test #" + (this.assertions.length + 1) + " " + this.stack + ": " + e.message, extractStacktrace( e, 0 ) );
193
+ this.callbackRuntime = +new Date() - this.callbackStarted;
194
+
195
+ QUnit.pushFailure( "Died on test #" + (this.assertions.length + 1) + " " + this.stack + ": " + ( e.message || e ), extractStacktrace( e, 0 ) );
139
196
  // else next test will carry the responsibility
140
197
  saveGlobal();
141
198
 
@@ -148,38 +205,43 @@
148
205
  teardown: function() {
149
206
  config.current = this;
150
207
  if ( config.notrycatch ) {
208
+ if ( typeof this.callbackRuntime === "undefined" ) {
209
+ this.callbackRuntime = +new Date() - this.callbackStarted;
210
+ }
151
211
  this.testEnvironment.teardown.call( this.testEnvironment );
152
212
  return;
153
213
  } else {
154
214
  try {
155
215
  this.testEnvironment.teardown.call( this.testEnvironment );
156
216
  } catch( e ) {
157
- QUnit.pushFailure( "Teardown failed on " + this.testName + ": " + e.message, extractStacktrace( e, 1 ) );
217
+ QUnit.pushFailure( "Teardown failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
158
218
  }
159
219
  }
160
220
  checkPollution();
161
221
  },
162
222
  finish: function() {
163
223
  config.current = this;
164
- if ( config.requireExpects && this.expected == null ) {
224
+ if ( config.requireExpects && this.expected === null ) {
165
225
  QUnit.pushFailure( "Expected number of assertions to be defined, but expect() was not called.", this.stack );
166
- } else if ( this.expected != null && this.expected != this.assertions.length ) {
226
+ } else if ( this.expected !== null && this.expected !== this.assertions.length ) {
167
227
  QUnit.pushFailure( "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run", this.stack );
168
- } else if ( this.expected == null && !this.assertions.length ) {
228
+ } else if ( this.expected === null && !this.assertions.length ) {
169
229
  QUnit.pushFailure( "Expected at least one assertion, but none were run - call expect(0) to accept zero assertions.", this.stack );
170
230
  }
171
231
 
172
- var assertion, a, b, i, li, ol,
232
+ var i, assertion, a, b, time, li, ol,
173
233
  test = this,
174
234
  good = 0,
175
235
  bad = 0,
176
236
  tests = id( "qunit-tests" );
177
237
 
238
+ this.runtime = +new Date() - this.started;
178
239
  config.stats.all += this.assertions.length;
179
240
  config.moduleStats.all += this.assertions.length;
180
241
 
181
242
  if ( tests ) {
182
243
  ol = document.createElement( "ol" );
244
+ ol.className = "qunit-assert-list";
183
245
 
184
246
  for ( i = 0; i < this.assertions.length; i++ ) {
185
247
  assertion = this.assertions[i];
@@ -208,22 +270,22 @@
208
270
  }
209
271
 
210
272
  if ( bad === 0 ) {
211
- ol.style.display = "none";
273
+ addClass( ol, "qunit-collapsed" );
212
274
  }
213
275
 
214
276
  // `b` initialized at top of scope
215
277
  b = document.createElement( "strong" );
216
- b.innerHTML = this.name + " <b class='counts'>(<b class='failed'>" + bad + "</b>, <b class='passed'>" + good + "</b>, " + this.assertions.length + ")</b>";
278
+ b.innerHTML = this.nameHtml + " <b class='counts'>(<b class='failed'>" + bad + "</b>, <b class='passed'>" + good + "</b>, " + this.assertions.length + ")</b>";
217
279
 
218
280
  addEvent(b, "click", function() {
219
- var next = b.nextSibling.nextSibling,
220
- display = next.style.display;
221
- next.style.display = display === "none" ? "block" : "none";
281
+ var next = b.parentNode.lastChild,
282
+ collapsed = hasClass( next, "qunit-collapsed" );
283
+ ( collapsed ? removeClass : addClass )( next, "qunit-collapsed" );
222
284
  });
223
285
 
224
286
  addEvent(b, "dblclick", function( e ) {
225
287
  var target = e && e.target ? e.target : window.event.srcElement;
226
- if ( target.nodeName.toLowerCase() == "span" || target.nodeName.toLowerCase() == "b" ) {
288
+ if ( target.nodeName.toLowerCase() === "span" || target.nodeName.toLowerCase() === "b" ) {
227
289
  target = target.parentNode;
228
290
  }
229
291
  if ( window.location && target.nodeName.toLowerCase() === "strong" ) {
@@ -231,13 +293,19 @@
231
293
  }
232
294
  });
233
295
 
296
+ // `time` initialized at top of scope
297
+ time = document.createElement( "span" );
298
+ time.className = "runtime";
299
+ time.innerHTML = this.runtime + " ms";
300
+
234
301
  // `li` initialized at top of scope
235
302
  li = id( this.id );
236
303
  li.className = bad ? "fail" : "pass";
237
304
  li.removeChild( li.firstChild );
238
305
  a = li.firstChild;
239
306
  li.appendChild( b );
240
- li.appendChild ( a );
307
+ li.appendChild( a );
308
+ li.appendChild( time );
241
309
  li.appendChild( ol );
242
310
 
243
311
  } else {
@@ -255,7 +323,8 @@
255
323
  module: this.module,
256
324
  failed: bad,
257
325
  passed: this.assertions.length - bad,
258
- total: this.assertions.length
326
+ total: this.assertions.length,
327
+ duration: this.runtime
259
328
  });
260
329
 
261
330
  QUnit.reset();
@@ -321,7 +390,7 @@
321
390
 
322
391
  test: function( testName, expected, callback, async ) {
323
392
  var test,
324
- name = "<span class='test-name'>" + escapeInnerText( testName ) + "</span>";
393
+ nameHtml = "<span class='test-name'>" + escapeText( testName ) + "</span>";
325
394
 
326
395
  if ( arguments.length === 2 ) {
327
396
  callback = expected;
@@ -329,11 +398,11 @@
329
398
  }
330
399
 
331
400
  if ( config.currentModule ) {
332
- name = "<span class='module-name'>" + config.currentModule + "</span>: " + name;
401
+ nameHtml = "<span class='module-name'>" + escapeText( config.currentModule ) + "</span>: " + nameHtml;
333
402
  }
334
403
 
335
404
  test = new Test({
336
- name: name,
405
+ nameHtml: nameHtml,
337
406
  testName: testName,
338
407
  expected: expected,
339
408
  async: async,
@@ -360,6 +429,18 @@
360
429
  },
361
430
 
362
431
  start: function( count ) {
432
+ // QUnit hasn't been initialized yet.
433
+ // Note: RequireJS (et al) may delay onLoad
434
+ if ( config.semaphore === undefined ) {
435
+ QUnit.begin(function() {
436
+ // This is triggered at the top of QUnit.load, push start() to the event loop, to allow QUnit.load to finish first
437
+ setTimeout(function() {
438
+ QUnit.start( count );
439
+ });
440
+ });
441
+ return;
442
+ }
443
+
363
444
  config.semaphore -= count || 1;
364
445
  // don't start until equal number of stop-calls
365
446
  if ( config.semaphore > 0 ) {
@@ -368,6 +449,8 @@
368
449
  // ignore if start is called more often then stop
369
450
  if ( config.semaphore < 0 ) {
370
451
  config.semaphore = 0;
452
+ QUnit.pushFailure( "Called start() while already started (QUnit.config.semaphore was 0 already)", null, sourceFromStacktrace(2) );
453
+ return;
371
454
  }
372
455
  // A slight delay, to avoid any current callbacks
373
456
  if ( defined.setTimeout ) {
@@ -403,11 +486,14 @@
403
486
  }
404
487
  };
405
488
 
489
+ // `assert` initialized at top of scope
406
490
  // Asssert helpers
407
- // All of these must call either QUnit.push() or manually do:
491
+ // All of these must either call QUnit.push() or manually do:
408
492
  // - runLoggingCallbacks( "log", .. );
409
493
  // - config.current.assertions.push({ .. });
410
- QUnit.assert = {
494
+ // We attach it to the QUnit object *after* we expose the public API,
495
+ // otherwise `assert` will become a global variable in browsers (#341).
496
+ assert = {
411
497
  /**
412
498
  * Asserts rough true-ish result.
413
499
  * @name ok
@@ -428,14 +514,14 @@
428
514
  message: msg
429
515
  };
430
516
 
431
- msg = escapeInnerText( msg || (result ? "okay" : "failed" ) );
517
+ msg = escapeText( msg || (result ? "okay" : "failed" ) );
432
518
  msg = "<span class='test-message'>" + msg + "</span>";
433
519
 
434
520
  if ( !result ) {
435
521
  source = sourceFromStacktrace( 2 );
436
522
  if ( source ) {
437
523
  details.source = source;
438
- msg += "<table><tr class='test-source'><th>Source: </th><td><pre>" + escapeInnerText( source ) + "</pre></td></tr></table>";
524
+ msg += "<table><tr class='test-source'><th>Source: </th><td><pre>" + escapeText( source ) + "</pre></td></tr></table>";
439
525
  }
440
526
  }
441
527
  runLoggingCallbacks( "log", QUnit, details );
@@ -453,6 +539,7 @@
453
539
  * @example equal( format( "Received {0} bytes.", 2), "Received 2 bytes.", "format() replaces {0} with next argument" );
454
540
  */
455
541
  equal: function( actual, expected, message ) {
542
+ /*jshint eqeqeq:false */
456
543
  QUnit.push( expected == actual, actual, expected, message );
457
544
  },
458
545
 
@@ -461,9 +548,30 @@
461
548
  * @function
462
549
  */
463
550
  notEqual: function( actual, expected, message ) {
551
+ /*jshint eqeqeq:false */
464
552
  QUnit.push( expected != actual, actual, expected, message );
465
553
  },
466
554
 
555
+ /**
556
+ * @name propEqual
557
+ * @function
558
+ */
559
+ propEqual: function( actual, expected, message ) {
560
+ actual = objectValues(actual);
561
+ expected = objectValues(expected);
562
+ QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
563
+ },
564
+
565
+ /**
566
+ * @name notPropEqual
567
+ * @function
568
+ */
569
+ notPropEqual: function( actual, expected, message ) {
570
+ actual = objectValues(actual);
571
+ expected = objectValues(expected);
572
+ QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
573
+ },
574
+
467
575
  /**
468
576
  * @name deepEqual
469
577
  * @function
@@ -496,8 +604,9 @@
496
604
  QUnit.push( expected !== actual, actual, expected, message );
497
605
  },
498
606
 
499
- throws: function( block, expected, message ) {
607
+ "throws": function( block, expected, message ) {
500
608
  var actual,
609
+ expectedOutput = expected,
501
610
  ok = false;
502
611
 
503
612
  // 'expected' is optional
@@ -518,18 +627,20 @@
518
627
  // we don't want to validate thrown error
519
628
  if ( !expected ) {
520
629
  ok = true;
630
+ expectedOutput = null;
521
631
  // expected is a regexp
522
632
  } else if ( QUnit.objectType( expected ) === "regexp" ) {
523
- ok = expected.test( actual );
633
+ ok = expected.test( errorString( actual ) );
524
634
  // expected is a constructor
525
635
  } else if ( actual instanceof expected ) {
526
636
  ok = true;
527
637
  // expected is a validation function which returns true is validation passed
528
638
  } else if ( expected.call( {}, actual ) === true ) {
639
+ expectedOutput = null;
529
640
  ok = true;
530
641
  }
531
642
 
532
- QUnit.push( ok, actual, null, message );
643
+ QUnit.push( ok, actual, expectedOutput, message );
533
644
  } else {
534
645
  QUnit.pushFailure( message, null, 'No exception was thrown.' );
535
646
  }
@@ -538,15 +649,16 @@
538
649
 
539
650
  /**
540
651
  * @deprecate since 1.8.0
541
- * Kept assertion helpers in root for backwards compatibility
652
+ * Kept assertion helpers in root for backwards compatibility.
542
653
  */
543
- extend( QUnit, QUnit.assert );
654
+ extend( QUnit, assert );
544
655
 
545
656
  /**
546
657
  * @deprecated since 1.9.0
547
- * Kept global "raises()" for backwards compatibility
658
+ * Kept root "raises()" for backwards compatibility.
659
+ * (Note that we don't introduce assert.raises).
548
660
  */
549
- QUnit.raises = QUnit.assert.throws;
661
+ QUnit.raises = assert[ "throws" ];
550
662
 
551
663
  /**
552
664
  * @deprecated since 1.0.0, replaced with error pushes since 1.3.0
@@ -622,6 +734,15 @@
622
734
  moduleDone: []
623
735
  };
624
736
 
737
+ // Export global variables, unless an 'exports' object exists,
738
+ // in that case we assume we're in CommonJS (dealt with on the bottom of the script)
739
+ if ( typeof exports === "undefined" ) {
740
+ extend( window, QUnit );
741
+
742
+ // Expose QUnit object
743
+ window.QUnit = QUnit;
744
+ }
745
+
625
746
  // Initialize more QUnit.config and QUnit.urlParams
626
747
  (function() {
627
748
  var i,
@@ -655,18 +776,11 @@
655
776
  QUnit.isLocal = location.protocol === "file:";
656
777
  }());
657
778
 
658
- // Export global variables, unless an 'exports' object exists,
659
- // in that case we assume we're in CommonJS (dealt with on the bottom of the script)
660
- if ( typeof exports === "undefined" ) {
661
- extend( window, QUnit );
662
-
663
- // Expose QUnit object
664
- window.QUnit = QUnit;
665
- }
666
-
667
779
  // Extend QUnit object,
668
780
  // these after set here because they should not be exposed as global functions
669
781
  extend( QUnit, {
782
+ assert: assert,
783
+
670
784
  config: config,
671
785
 
672
786
  // Initialize the configuration options
@@ -681,7 +795,7 @@
681
795
  autorun: false,
682
796
  filter: "",
683
797
  queue: [],
684
- semaphore: 0
798
+ semaphore: 1
685
799
  });
686
800
 
687
801
  var tests, banner, result,
@@ -689,7 +803,7 @@
689
803
 
690
804
  if ( qunit ) {
691
805
  qunit.innerHTML =
692
- "<h1 id='qunit-header'>" + escapeInnerText( document.title ) + "</h1>" +
806
+ "<h1 id='qunit-header'>" + escapeText( document.title ) + "</h1>" +
693
807
  "<h2 id='qunit-banner'></h2>" +
694
808
  "<div id='qunit-testrunner-toolbar'></div>" +
695
809
  "<h2 id='qunit-userAgent'></h2>" +
@@ -745,7 +859,7 @@
745
859
 
746
860
  // Safe object type checking
747
861
  is: function( type, obj ) {
748
- return QUnit.objectType( obj ) == type;
862
+ return QUnit.objectType( obj ) === type;
749
863
  },
750
864
 
751
865
  objectType: function( obj ) {
@@ -757,7 +871,8 @@
757
871
  return "null";
758
872
  }
759
873
 
760
- var type = toString.call( obj ).match(/^\[object\s(.*)\]$/)[1] || "";
874
+ var match = toString.call( obj ).match(/^\[object\s(.*)\]$/),
875
+ type = match && match[1] || "";
761
876
 
762
877
  switch ( type ) {
763
878
  case "Number":
@@ -794,16 +909,16 @@
794
909
  expected: expected
795
910
  };
796
911
 
797
- message = escapeInnerText( message ) || ( result ? "okay" : "failed" );
912
+ message = escapeText( message ) || ( result ? "okay" : "failed" );
798
913
  message = "<span class='test-message'>" + message + "</span>";
799
914
  output = message;
800
915
 
801
916
  if ( !result ) {
802
- expected = escapeInnerText( QUnit.jsDump.parse(expected) );
803
- actual = escapeInnerText( QUnit.jsDump.parse(actual) );
917
+ expected = escapeText( QUnit.jsDump.parse(expected) );
918
+ actual = escapeText( QUnit.jsDump.parse(actual) );
804
919
  output += "<table><tr class='test-expected'><th>Expected: </th><td><pre>" + expected + "</pre></td></tr>";
805
920
 
806
- if ( actual != expected ) {
921
+ if ( actual !== expected ) {
807
922
  output += "<tr class='test-actual'><th>Result: </th><td><pre>" + actual + "</pre></td></tr>";
808
923
  output += "<tr class='test-diff'><th>Diff: </th><td><pre>" + QUnit.diff( expected, actual ) + "</pre></td></tr>";
809
924
  }
@@ -812,7 +927,7 @@
812
927
 
813
928
  if ( source ) {
814
929
  details.source = source;
815
- output += "<tr class='test-source'><th>Source: </th><td><pre>" + escapeInnerText( source ) + "</pre></td></tr>";
930
+ output += "<tr class='test-source'><th>Source: </th><td><pre>" + escapeText( source ) + "</pre></td></tr>";
816
931
  }
817
932
 
818
933
  output += "</table>";
@@ -839,19 +954,19 @@
839
954
  message: message
840
955
  };
841
956
 
842
- message = escapeInnerText( message ) || "error";
957
+ message = escapeText( message ) || "error";
843
958
  message = "<span class='test-message'>" + message + "</span>";
844
959
  output = message;
845
960
 
846
961
  output += "<table>";
847
962
 
848
963
  if ( actual ) {
849
- output += "<tr class='test-actual'><th>Result: </th><td><pre>" + escapeInnerText( actual ) + "</pre></td></tr>";
964
+ output += "<tr class='test-actual'><th>Result: </th><td><pre>" + escapeText( actual ) + "</pre></td></tr>";
850
965
  }
851
966
 
852
967
  if ( source ) {
853
968
  details.source = source;
854
- output += "<tr class='test-source'><th>Source: </th><td><pre>" + escapeInnerText( source ) + "</pre></td></tr>";
969
+ output += "<tr class='test-source'><th>Source: </th><td><pre>" + escapeText( source ) + "</pre></td></tr>";
855
970
  }
856
971
 
857
972
  output += "</table>";
@@ -876,7 +991,8 @@
876
991
  querystring += encodeURIComponent( key ) + "=" +
877
992
  encodeURIComponent( params[ key ] ) + "&";
878
993
  }
879
- return window.location.pathname + querystring.slice( 0, -1 );
994
+ return window.location.protocol + "//" + window.location.host +
995
+ window.location.pathname + querystring.slice( 0, -1 );
880
996
  },
881
997
 
882
998
  extend: extend,
@@ -907,7 +1023,7 @@
907
1023
  // testStart: { name }
908
1024
  testStart: registerLoggingCallback( "testStart" ),
909
1025
 
910
- // testDone: { name, failed, passed, total }
1026
+ // testDone: { name, failed, passed, total, duration }
911
1027
  testDone: registerLoggingCallback( "testDone" ),
912
1028
 
913
1029
  // moduleStart: { name }
@@ -925,7 +1041,8 @@
925
1041
  runLoggingCallbacks( "begin", QUnit, {} );
926
1042
 
927
1043
  // Initialize the config, saving the execution queue
928
- var banner, filter, i, label, len, main, ol, toolbar, userAgent, val, urlConfigCheckboxes, moduleFilter,
1044
+ var banner, filter, i, label, len, main, ol, toolbar, userAgent, val,
1045
+ urlConfigCheckboxesContainer, urlConfigCheckboxes, moduleFilter,
929
1046
  numModules = 0,
930
1047
  moduleFilterHtml = "",
931
1048
  urlConfigHtml = "",
@@ -948,14 +1065,24 @@
948
1065
  };
949
1066
  }
950
1067
  config[ val.id ] = QUnit.urlParams[ val.id ];
951
- urlConfigHtml += "<input id='qunit-urlconfig-" + val.id + "' name='" + val.id + "' type='checkbox'" + ( config[ val.id ] ? " checked='checked'" : "" ) + " title='" + val.tooltip + "'><label for='qunit-urlconfig-" + val.id + "' title='" + val.tooltip + "'>" + val.label + "</label>";
1068
+ urlConfigHtml += "<input id='qunit-urlconfig-" + escapeText( val.id ) +
1069
+ "' name='" + escapeText( val.id ) +
1070
+ "' type='checkbox'" + ( config[ val.id ] ? " checked='checked'" : "" ) +
1071
+ " title='" + escapeText( val.tooltip ) +
1072
+ "'><label for='qunit-urlconfig-" + escapeText( val.id ) +
1073
+ "' title='" + escapeText( val.tooltip ) + "'>" + val.label + "</label>";
952
1074
  }
953
1075
 
954
- moduleFilterHtml += "<label for='qunit-modulefilter'>Module: </label><select id='qunit-modulefilter' name='modulefilter'><option value='' " + ( config.module === undefined ? "selected" : "" ) + ">< All Modules ></option>";
1076
+ moduleFilterHtml += "<label for='qunit-modulefilter'>Module: </label><select id='qunit-modulefilter' name='modulefilter'><option value='' " +
1077
+ ( config.module === undefined ? "selected='selected'" : "" ) +
1078
+ ">< All Modules ></option>";
1079
+
955
1080
  for ( i in config.modules ) {
956
1081
  if ( config.modules.hasOwnProperty( i ) ) {
957
1082
  numModules += 1;
958
- moduleFilterHtml += "<option value='" + encodeURIComponent(i) + "' " + ( config.module === i ? "selected" : "" ) + ">" + i + "</option>";
1083
+ moduleFilterHtml += "<option value='" + escapeText( encodeURIComponent(i) ) + "' " +
1084
+ ( config.module === i ? "selected='selected'" : "" ) +
1085
+ ">" + escapeText(i) + "</option>";
959
1086
  }
960
1087
  }
961
1088
  moduleFilterHtml += "</select>";
@@ -1014,20 +1141,26 @@
1014
1141
  label.innerHTML = "Hide passed tests";
1015
1142
  toolbar.appendChild( label );
1016
1143
 
1017
- urlConfigCheckboxes = document.createElement( 'span' );
1018
- urlConfigCheckboxes.innerHTML = urlConfigHtml;
1019
- addEvent( urlConfigCheckboxes, "change", function( event ) {
1020
- var params = {};
1021
- params[ event.target.name ] = event.target.checked ? true : undefined;
1144
+ urlConfigCheckboxesContainer = document.createElement("span");
1145
+ urlConfigCheckboxesContainer.innerHTML = urlConfigHtml;
1146
+ urlConfigCheckboxes = urlConfigCheckboxesContainer.getElementsByTagName("input");
1147
+ // For oldIE support:
1148
+ // * Add handlers to the individual elements instead of the container
1149
+ // * Use "click" instead of "change"
1150
+ // * Fallback from event.target to event.srcElement
1151
+ addEvents( urlConfigCheckboxes, "click", function( event ) {
1152
+ var params = {},
1153
+ target = event.target || event.srcElement;
1154
+ params[ target.name ] = target.checked ? true : undefined;
1022
1155
  window.location = QUnit.url( params );
1023
1156
  });
1024
- toolbar.appendChild( urlConfigCheckboxes );
1157
+ toolbar.appendChild( urlConfigCheckboxesContainer );
1025
1158
 
1026
1159
  if (numModules > 1) {
1027
1160
  moduleFilter = document.createElement( 'span' );
1028
1161
  moduleFilter.setAttribute( 'id', 'qunit-modulefilter-container' );
1029
1162
  moduleFilter.innerHTML = moduleFilterHtml;
1030
- addEvent( moduleFilter, "change", function() {
1163
+ addEvent( moduleFilter.lastChild, "change", function() {
1031
1164
  var selectBox = moduleFilter.getElementsByTagName("select")[0],
1032
1165
  selectedModule = decodeURIComponent(selectBox.options[selectBox.selectedIndex].value);
1033
1166
 
@@ -1106,7 +1239,7 @@
1106
1239
  " milliseconds.<br/>",
1107
1240
  "<span class='passed'>",
1108
1241
  passed,
1109
- "</span> tests of <span class='total'>",
1242
+ "</span> assertions of <span class='total'>",
1110
1243
  config.stats.all,
1111
1244
  "</span> passed, <span class='failed'>",
1112
1245
  config.stats.bad,
@@ -1199,7 +1332,7 @@
1199
1332
  function extractStacktrace( e, offset ) {
1200
1333
  offset = offset === undefined ? 3 : offset;
1201
1334
 
1202
- var stack, include, i, regex;
1335
+ var stack, include, i;
1203
1336
 
1204
1337
  if ( e.stacktrace ) {
1205
1338
  // Opera
@@ -1213,7 +1346,7 @@
1213
1346
  if ( fileName ) {
1214
1347
  include = [];
1215
1348
  for ( i = offset; i < stack.length; i++ ) {
1216
- if ( stack[ i ].indexOf( fileName ) != -1 ) {
1349
+ if ( stack[ i ].indexOf( fileName ) !== -1 ) {
1217
1350
  break;
1218
1351
  }
1219
1352
  include.push( stack[ i ] );
@@ -1242,17 +1375,27 @@
1242
1375
  }
1243
1376
  }
1244
1377
 
1245
- function escapeInnerText( s ) {
1378
+ /**
1379
+ * Escape text for attribute or text content.
1380
+ */
1381
+ function escapeText( s ) {
1246
1382
  if ( !s ) {
1247
1383
  return "";
1248
1384
  }
1249
1385
  s = s + "";
1250
- return s.replace( /[\&<>]/g, function( s ) {
1386
+ // Both single quotes and double quotes (for attributes)
1387
+ return s.replace( /['"<>&]/g, function( s ) {
1251
1388
  switch( s ) {
1252
- case "&": return "&amp;";
1253
- case "<": return "&lt;";
1254
- case ">": return "&gt;";
1255
- default: return s;
1389
+ case '\'':
1390
+ return '&#039;';
1391
+ case '"':
1392
+ return '&quot;';
1393
+ case '<':
1394
+ return '&lt;';
1395
+ case '>':
1396
+ return '&gt;';
1397
+ case '&':
1398
+ return '&amp;';
1256
1399
  }
1257
1400
  });
1258
1401
  }
@@ -1300,7 +1443,7 @@
1300
1443
  }
1301
1444
  }
1302
1445
 
1303
- function checkPollution( name ) {
1446
+ function checkPollution() {
1304
1447
  var newGlobals,
1305
1448
  deletedGlobals,
1306
1449
  old = config.pollution;
@@ -1349,16 +1492,53 @@
1349
1492
  return a;
1350
1493
  }
1351
1494
 
1495
+ /**
1496
+ * @param {HTMLElement} elem
1497
+ * @param {string} type
1498
+ * @param {Function} fn
1499
+ */
1352
1500
  function addEvent( elem, type, fn ) {
1501
+ // Standards-based browsers
1353
1502
  if ( elem.addEventListener ) {
1354
1503
  elem.addEventListener( type, fn, false );
1355
- } else if ( elem.attachEvent ) {
1356
- elem.attachEvent( "on" + type, fn );
1504
+ // IE
1357
1505
  } else {
1358
- fn();
1506
+ elem.attachEvent( "on" + type, fn );
1359
1507
  }
1360
1508
  }
1361
1509
 
1510
+ /**
1511
+ * @param {Array|NodeList} elems
1512
+ * @param {string} type
1513
+ * @param {Function} fn
1514
+ */
1515
+ function addEvents( elems, type, fn ) {
1516
+ var i = elems.length;
1517
+ while ( i-- ) {
1518
+ addEvent( elems[i], type, fn );
1519
+ }
1520
+ }
1521
+
1522
+ function hasClass( elem, name ) {
1523
+ return (" " + elem.className + " ").indexOf(" " + name + " ") > -1;
1524
+ }
1525
+
1526
+ function addClass( elem, name ) {
1527
+ if ( !hasClass( elem, name ) ) {
1528
+ elem.className += (elem.className ? " " : "") + name;
1529
+ }
1530
+ }
1531
+
1532
+ function removeClass( elem, name ) {
1533
+ var set = " " + elem.className + " ";
1534
+ // Class name may appear multiple times
1535
+ while ( set.indexOf(" " + name + " ") > -1 ) {
1536
+ set = set.replace(" " + name + " " , " ");
1537
+ }
1538
+ // If possible, trim it for prettiness, but not neccecarily
1539
+ elem.className = window.jQuery ? jQuery.trim( set ) : ( set.trim ? set.trim() : set );
1540
+ }
1541
+
1362
1542
  function id( name ) {
1363
1543
  return !!( typeof document !== "undefined" && document && document.getElementById ) &&
1364
1544
  document.getElementById( name );
@@ -1372,7 +1552,6 @@
1372
1552
 
1373
1553
  // Supports deprecated method of completely overwriting logging callbacks
1374
1554
  function runLoggingCallbacks( key, scope, args ) {
1375
- //debugger;
1376
1555
  var i, callbacks;
1377
1556
  if ( QUnit.hasOwnProperty( key ) ) {
1378
1557
  QUnit[ key ].call(scope, args );
@@ -1414,6 +1593,7 @@
1414
1593
 
1415
1594
  // for string, boolean, number and null
1416
1595
  function useStrictEquality( b, a ) {
1596
+ /*jshint eqeqeq:false */
1417
1597
  if ( b instanceof a.constructor || a instanceof b.constructor ) {
1418
1598
  // to catch short annotaion VS 'new' annotation of a
1419
1599
  // declaration
@@ -1610,7 +1790,8 @@
1610
1790
 
1611
1791
  var reName = /^function (\w+)/,
1612
1792
  jsDump = {
1613
- parse: function( obj, type, stack ) { //type is used mostly internally, you can fix a (custom)type in advance
1793
+ // type is used mostly internally, you can fix a (custom)type in advance
1794
+ parse: function( obj, type, stack ) {
1614
1795
  stack = stack || [ ];
1615
1796
  var inStack, res,
1616
1797
  parser = this.parsers[ type || this.typeOf(obj) ];
@@ -1618,18 +1799,16 @@
1618
1799
  type = typeof parser;
1619
1800
  inStack = inArray( obj, stack );
1620
1801
 
1621
- if ( inStack != -1 ) {
1802
+ if ( inStack !== -1 ) {
1622
1803
  return "recursion(" + (inStack - stack.length) + ")";
1623
1804
  }
1624
- //else
1625
- if ( type == "function" ) {
1805
+ if ( type === "function" ) {
1626
1806
  stack.push( obj );
1627
1807
  res = parser.call( this, obj, stack );
1628
1808
  stack.pop();
1629
1809
  return res;
1630
1810
  }
1631
- // else
1632
- return ( type == "string" ) ? parser : this.parsers.error;
1811
+ return ( type === "string" ) ? parser : this.parsers.error;
1633
1812
  },
1634
1813
  typeOf: function( obj ) {
1635
1814
  var type;
@@ -1656,6 +1835,8 @@
1656
1835
  ( typeof obj.length === "number" && typeof obj.item !== "undefined" && ( obj.length ? obj.item(0) === obj[0] : ( obj.item( 0 ) === null && typeof obj[0] === "undefined" ) ) )
1657
1836
  ) {
1658
1837
  type = "array";
1838
+ } else if ( obj.constructor === Error.prototype.constructor ) {
1839
+ type = "error";
1659
1840
  } else {
1660
1841
  type = typeof obj;
1661
1842
  }
@@ -1664,7 +1845,8 @@
1664
1845
  separator: function() {
1665
1846
  return this.multiline ? this.HTML ? "<br />" : "\n" : this.HTML ? "&nbsp;" : " ";
1666
1847
  },
1667
- indent: function( extra ) {// extra can be a number, shortcut for increasing-calling-decreasing
1848
+ // extra can be a number, shortcut for increasing-calling-decreasing
1849
+ indent: function( extra ) {
1668
1850
  if ( !this.multiline ) {
1669
1851
  return "";
1670
1852
  }
@@ -1693,13 +1875,16 @@
1693
1875
  parsers: {
1694
1876
  window: "[Window]",
1695
1877
  document: "[Document]",
1696
- error: "[ERROR]", //when no parser is found, shouldn"t happen
1878
+ error: function(error) {
1879
+ return "Error(\"" + error.message + "\")";
1880
+ },
1697
1881
  unknown: "[Unknown]",
1698
1882
  "null": "null",
1699
1883
  "undefined": "undefined",
1700
1884
  "function": function( fn ) {
1701
1885
  var ret = "function",
1702
- name = "name" in fn ? fn.name : (reName.exec(fn) || [])[1];//functions never have name in IE
1886
+ // functions never have name in IE
1887
+ name = "name" in fn ? fn.name : (reName.exec(fn) || [])[1];
1703
1888
 
1704
1889
  if ( name ) {
1705
1890
  ret += " " + name;
@@ -1715,13 +1900,9 @@
1715
1900
  object: function( map, stack ) {
1716
1901
  var ret = [ ], keys, key, val, i;
1717
1902
  QUnit.jsDump.up();
1718
- if ( Object.keys ) {
1719
- keys = Object.keys( map );
1720
- } else {
1721
- keys = [];
1722
- for ( key in map ) {
1723
- keys.push( key );
1724
- }
1903
+ keys = [];
1904
+ for ( key in map ) {
1905
+ keys.push( key );
1725
1906
  }
1726
1907
  keys.sort();
1727
1908
  for ( i = 0; i < keys.length; i++ ) {
@@ -1733,21 +1914,34 @@
1733
1914
  return join( "{", ret, "}" );
1734
1915
  },
1735
1916
  node: function( node ) {
1736
- var a, val,
1917
+ var len, i, val,
1737
1918
  open = QUnit.jsDump.HTML ? "&lt;" : "<",
1738
1919
  close = QUnit.jsDump.HTML ? "&gt;" : ">",
1739
1920
  tag = node.nodeName.toLowerCase(),
1740
- ret = open + tag;
1741
-
1742
- for ( a in QUnit.jsDump.DOMAttrs ) {
1743
- val = node[ QUnit.jsDump.DOMAttrs[a] ];
1744
- if ( val ) {
1745
- ret += " " + a + "=" + QUnit.jsDump.parse( val, "attribute" );
1921
+ ret = open + tag,
1922
+ attrs = node.attributes;
1923
+
1924
+ if ( attrs ) {
1925
+ for ( i = 0, len = attrs.length; i < len; i++ ) {
1926
+ val = attrs[i].nodeValue;
1927
+ // IE6 includes all attributes in .attributes, even ones not explicitly set.
1928
+ // Those have values like undefined, null, 0, false, "" or "inherit".
1929
+ if ( val && val !== "inherit" ) {
1930
+ ret += " " + attrs[i].nodeName + "=" + QUnit.jsDump.parse( val, "attribute" );
1931
+ }
1746
1932
  }
1747
1933
  }
1748
- return ret + close + open + "/" + tag + close;
1934
+ ret += close;
1935
+
1936
+ // Show content of TextNode or CDATASection
1937
+ if ( node.nodeType === 3 || node.nodeType === 4 ) {
1938
+ ret += node.nodeValue;
1939
+ }
1940
+
1941
+ return ret + open + "/" + tag + close;
1749
1942
  },
1750
- functionArgs: function( fn ) {//function calls it internally, it's the arguments part of the function
1943
+ // function calls it internally, it's the arguments part of the function
1944
+ functionArgs: function( fn ) {
1751
1945
  var args,
1752
1946
  l = fn.length;
1753
1947
 
@@ -1757,54 +1951,34 @@
1757
1951
 
1758
1952
  args = new Array(l);
1759
1953
  while ( l-- ) {
1760
- args[l] = String.fromCharCode(97+l);//97 is 'a'
1954
+ // 97 is 'a'
1955
+ args[l] = String.fromCharCode(97+l);
1761
1956
  }
1762
1957
  return " " + args.join( ", " ) + " ";
1763
1958
  },
1764
- key: quote, //object calls it internally, the key part of an item in a map
1765
- functionCode: "[code]", //function calls it internally, it's the content of the function
1766
- attribute: quote, //node calls it internally, it's an html attribute value
1959
+ // object calls it internally, the key part of an item in a map
1960
+ key: quote,
1961
+ // function calls it internally, it's the content of the function
1962
+ functionCode: "[code]",
1963
+ // node calls it internally, it's an html attribute value
1964
+ attribute: quote,
1767
1965
  string: quote,
1768
1966
  date: quote,
1769
- regexp: literal, //regex
1967
+ regexp: literal,
1770
1968
  number: literal,
1771
1969
  "boolean": literal
1772
1970
  },
1773
- DOMAttrs: {
1774
- //attributes to dump from nodes, name=>realName
1775
- id: "id",
1776
- name: "name",
1777
- "class": "className"
1778
- },
1779
- HTML: false,//if true, entities are escaped ( <, >, \t, space and \n )
1780
- indentChar: " ",//indentation unit
1781
- multiline: true //if true, items in a collection, are separated by a \n, else just a space.
1971
+ // if true, entities are escaped ( <, >, \t, space and \n )
1972
+ HTML: false,
1973
+ // indentation unit
1974
+ indentChar: " ",
1975
+ // if true, items in a collection, are separated by a \n, else just a space.
1976
+ multiline: true
1782
1977
  };
1783
1978
 
1784
1979
  return jsDump;
1785
1980
  }());
1786
1981
 
1787
- // from Sizzle.js
1788
- function getText( elems ) {
1789
- var i, elem,
1790
- ret = "";
1791
-
1792
- for ( i = 0; elems[i]; i++ ) {
1793
- elem = elems[i];
1794
-
1795
- // Get the text from text nodes and CDATA nodes
1796
- if ( elem.nodeType === 3 || elem.nodeType === 4 ) {
1797
- ret += elem.nodeValue;
1798
-
1799
- // Traverse everything else, except comment nodes
1800
- } else if ( elem.nodeType !== 8 ) {
1801
- ret += getText( elem.childNodes );
1802
- }
1803
- }
1804
-
1805
- return ret;
1806
- }
1807
-
1808
1982
  // from jquery.js
1809
1983
  function inArray( elem, array ) {
1810
1984
  if ( array.indexOf ) {
@@ -1835,13 +2009,14 @@
1835
2009
  * QUnit.diff( "the quick brown fox jumped over", "the quick fox jumps over" ) == "the quick <del>brown </del> fox <del>jumped </del><ins>jumps </ins> over"
1836
2010
  */
1837
2011
  QUnit.diff = (function() {
2012
+ /*jshint eqeqeq:false, eqnull:true */
1838
2013
  function diff( o, n ) {
1839
2014
  var i,
1840
2015
  ns = {},
1841
2016
  os = {};
1842
2017
 
1843
2018
  for ( i = 0; i < n.length; i++ ) {
1844
- if ( ns[ n[i] ] == null ) {
2019
+ if ( !hasOwn.call( ns, n[i] ) ) {
1845
2020
  ns[ n[i] ] = {
1846
2021
  rows: [],
1847
2022
  o: null
@@ -1851,7 +2026,7 @@
1851
2026
  }
1852
2027
 
1853
2028
  for ( i = 0; i < o.length; i++ ) {
1854
- if ( os[ o[i] ] == null ) {
2029
+ if ( !hasOwn.call( os, o[i] ) ) {
1855
2030
  os[ o[i] ] = {
1856
2031
  rows: [],
1857
2032
  n: null
@@ -1864,7 +2039,7 @@
1864
2039
  if ( !hasOwn.call( ns, i ) ) {
1865
2040
  continue;
1866
2041
  }
1867
- if ( ns[i].rows.length == 1 && typeof os[i] != "undefined" && os[i].rows.length == 1 ) {
2042
+ if ( ns[i].rows.length === 1 && hasOwn.call( os, i ) && os[i].rows.length === 1 ) {
1868
2043
  n[ ns[i].rows[0] ] = {
1869
2044
  text: n[ ns[i].rows[0] ],
1870
2045
  row: os[i].rows[0]
@@ -1970,7 +2145,7 @@
1970
2145
 
1971
2146
  // for CommonJS enviroments, export everything
1972
2147
  if ( typeof exports !== "undefined" ) {
1973
- extend(exports, QUnit);
2148
+ extend( exports, QUnit );
1974
2149
  }
1975
2150
 
1976
2151
  // get at whatever the global object is, like window in browsers