netzke-testing 0.12.3 → 1.0.0.0.pre

Sign up to get free protection for your applications and to get access to all the features.
Files changed (106) hide show
  1. data/CHANGELOG.md +1 -0
  2. data/Gemfile +2 -3
  3. data/LICENSE.txt +2 -21
  4. data/README.md +8 -7
  5. data/app/assets/javascripts/netzke/testing/helpers/actions.js.coffee +3 -0
  6. data/app/assets/javascripts/netzke/testing/helpers/grid.js.coffee +16 -10
  7. data/app/assets/javascripts/netzke/testing/helpers/queries.js.coffee +16 -10
  8. data/app/assets/javascripts/netzke/testing/mocha/mocha.js +1948 -723
  9. data/app/assets/stylesheets/netzke/testing/mocha/mocha.css +53 -14
  10. data/lib/netzke/testing/version.rb +1 -1
  11. data/spec/rails_app/app/assets/javascripts/application.js +0 -3
  12. data/spec/rails_app/log/test.log +1699 -0
  13. data/spec/rails_app/tmp/cache/assets/test/sprockets/v3.0/-o-YaVl0T7eDJ9OrOV9RGwqVsIWZFHy_ANOiYAzd5xs.cache +2 -0
  14. data/spec/rails_app/tmp/cache/assets/test/sprockets/v3.0/0ytTgUbUdaNC4f2HwTF9KPoNfEPoelbdxEEonmXcFY8.cache +1 -0
  15. data/spec/rails_app/tmp/cache/assets/test/sprockets/v3.0/2N-wUxBH2S0I0Vdtr2WyUGI2-QP0sx654c316Tle0Y8.cache +1 -0
  16. data/spec/rails_app/tmp/cache/assets/test/sprockets/v3.0/2zr8-0Qy8xKJVKL6YDLMlxXVM3UR6y6LsSiMHIzTzZk.cache +108 -0
  17. data/spec/rails_app/tmp/cache/assets/test/sprockets/v3.0/4iunyDf9YIjBbUNGIWAUzBvRnjmDZHzub-ySK64tNiM.cache +1 -0
  18. data/spec/rails_app/tmp/cache/assets/test/sprockets/v3.0/5TvecBl1M5rB_WmUw9C6hq0IQscGnYdoEo54Nu7v-ro.cache +2 -0
  19. data/spec/rails_app/tmp/cache/assets/test/sprockets/v3.0/5hZUq2VTJHMVrffS80-YXBfIY0KRFcqIczHYxwEq1O4.cache +1 -0
  20. data/spec/rails_app/tmp/cache/assets/test/sprockets/v3.0/65vMYBj8h-G6ncIkZb0XGK0AkccVIg3nRZ49oVQD5pk.cache +1 -0
  21. data/spec/rails_app/tmp/cache/assets/test/sprockets/v3.0/6QkXlYVD0H86cOJuY4YsQwTsh9R-Xuei5H9g4AI6qLc.cache +0 -0
  22. data/spec/rails_app/tmp/cache/assets/test/sprockets/v3.0/6oNBMh4vlr3nAg_zScBsRwoNfCUCwuMfxEsMExGEZ58.cache +1 -0
  23. data/spec/rails_app/tmp/cache/assets/test/sprockets/v3.0/7AdXoQpyUKCU1NajQOdwfICU7NNx66_CjHVZaEPMie8.cache +0 -0
  24. data/spec/rails_app/tmp/cache/assets/test/sprockets/v3.0/7SehKiu3k-7sWqyekPGAAlRRuG6zi4zImkGSsFZY5Hg.cache +1 -0
  25. data/spec/rails_app/tmp/cache/assets/test/sprockets/v3.0/8hCQLzcxr1YiyVw4yQnLRkyjUeJPrBL68jaO0PBTVlc.cache +1 -0
  26. data/spec/rails_app/tmp/cache/assets/test/sprockets/v3.0/8jJcLw-iylJTyRci7ICaZfve0wKGZehtTiFdrRGRSWY.cache +1 -0
  27. data/spec/rails_app/tmp/cache/assets/test/sprockets/v3.0/9tmtKoc6UHxqorCSuhwhFQiEoEH8cz4oCJxJRhz6pyg.cache +0 -0
  28. data/spec/rails_app/tmp/cache/assets/test/sprockets/v3.0/BOuRxAKchk00bl_QQch7_NnI7jvFEq1o3uicHp8nTlA.cache +0 -0
  29. data/spec/rails_app/tmp/cache/assets/test/sprockets/v3.0/BT0NlH5e-SMXSFoONZqKAfPuxkCaZq9t03GG-tbqf2A.cache +1 -0
  30. data/spec/rails_app/tmp/cache/assets/test/sprockets/v3.0/C3sjqQ7IyyEmT_fAJspAqXDgyZTcglD-YbgpfYb0zb0.cache +0 -0
  31. data/spec/rails_app/tmp/cache/assets/test/sprockets/v3.0/CD3FvmKB9PfopODzH8rXDZqEJfXsuXpcIezK4WAZaBE.cache +3 -0
  32. data/spec/rails_app/tmp/cache/assets/test/sprockets/v3.0/CeuWmVqZWhwboK9KGiK-VGwtZYLrqCRI93rvJQIBTXs.cache +2 -0
  33. data/spec/rails_app/tmp/cache/assets/test/sprockets/v3.0/DBSkqZmCLWpPoAEFi-Reo4ICD1LTRmbh9XIbohHM47A.cache +1 -0
  34. data/spec/rails_app/tmp/cache/assets/test/sprockets/v3.0/DYPq9tb1XNCaTXOoFjisXo-wigP-JudWtJeUfiqW0m8.cache +0 -0
  35. data/spec/rails_app/tmp/cache/assets/test/sprockets/v3.0/EvRmssKzs-UegvrZuPi_Lk3cjNfMNSpr9xx0EshSNJo.cache +1 -0
  36. data/spec/rails_app/tmp/cache/assets/test/sprockets/v3.0/GGgLpQ8oW-77EMBuKwruBXwHesf4NZu1Y3HiI1WMWDI.cache +1 -0
  37. data/spec/rails_app/tmp/cache/assets/test/sprockets/v3.0/Gg7p64pI2umKw5BpAglJ9RimpnYcL34FWDWFaKOz62A.cache +106 -0
  38. data/spec/rails_app/tmp/cache/assets/test/sprockets/v3.0/Hdq71Baun4hNkGv_d0fbdq2p26likuSnCMUFkyDCFws.cache +0 -0
  39. data/spec/rails_app/tmp/cache/assets/test/sprockets/v3.0/HsEibo-dY2kOc-nAvEmkUrm5PWK9cU-uNKra6itU_zw.cache +1 -0
  40. data/spec/rails_app/tmp/cache/assets/test/sprockets/v3.0/I-Yu0SmONUDD_GaeBx_r3qR4yHoQ3aqFWAFmyHRL-zg.cache +3 -0
  41. data/spec/rails_app/tmp/cache/assets/test/sprockets/v3.0/JCrLlkFPuQLUZyQYKL6_MMNgNGfz2-E323acSOSrt5k.cache +0 -0
  42. data/spec/rails_app/tmp/cache/assets/test/sprockets/v3.0/JVTgVQi9d98c1SokUVnZ3aomHqJQbXZioi7g3ahm5Qc.cache +1 -0
  43. data/spec/rails_app/tmp/cache/assets/test/sprockets/v3.0/Jeh27aEr_ZWMJZqyCSIczaLGHt_DhIWwdukzqrGWa9w.cache +1 -0
  44. data/spec/rails_app/tmp/cache/assets/test/sprockets/v3.0/Jl60NqnWqOdABtuYSE5ZzrcmVseJlSZF2HNFS59FpY0.cache +0 -0
  45. data/spec/rails_app/tmp/cache/assets/test/sprockets/v3.0/LRGtOZMxHuSVunCvJ63sVbxqDeAajlRaa6KCmyrAIqA.cache +1 -0
  46. data/spec/rails_app/tmp/cache/assets/test/sprockets/v3.0/MBeoy0q5Gyw0x-mJzpHAPysisACug1l0TL2vMkIyrOw.cache +2 -0
  47. data/spec/rails_app/tmp/cache/assets/test/sprockets/v3.0/NOfTwd49eb86ANBlpdBndMO4ImhsuP1GRpxDAgwAfx4.cache +3 -0
  48. data/spec/rails_app/tmp/cache/assets/test/sprockets/v3.0/N_20zEdBHyIIxuOVGv8q7BS0FFrNQ39k3CPwpMrSSYo.cache +1 -0
  49. data/spec/rails_app/tmp/cache/assets/test/sprockets/v3.0/NvWH8wh5mUg78k87c85rP3NlI7nTtwzUxyYJOS5qiQI.cache +3 -0
  50. data/spec/rails_app/tmp/cache/assets/test/sprockets/v3.0/OUo2VS0xOErRnbS1XuvOarZVKs-rq2NnztsajD5Fj10.cache +1 -0
  51. data/spec/rails_app/tmp/cache/assets/test/sprockets/v3.0/OcWPwVd4Kv47Guuuu80JnFKoHk_okLZ7iRvgwzoZUHA.cache +0 -0
  52. data/spec/rails_app/tmp/cache/assets/test/sprockets/v3.0/Oyz8XfIMJQ3g6O0KjipLd4Kuem3B6xG5oyaHeeGmt-M.cache +1 -0
  53. data/spec/rails_app/tmp/cache/assets/test/sprockets/v3.0/P8_qz5Ye3lrk5y6ujvXaW6SDLuGDLb262IusJX4dIVE.cache +0 -0
  54. data/spec/rails_app/tmp/cache/assets/test/sprockets/v3.0/QW--4tkWOk_XF1gyoYZDRCyDehMpmnuVayrZKMVqZ7M.cache +2 -0
  55. data/spec/rails_app/tmp/cache/assets/test/sprockets/v3.0/RLcVI-Rt6DzaGkFHDbXe0tx4wEBGaCRvnY_EycIsnuU.cache +0 -0
  56. data/spec/rails_app/tmp/cache/assets/test/sprockets/v3.0/Sw3U88tBBMOJoXaXESCBCsrzso8r9YSJvEKU8JZ0BNo.cache +2 -0
  57. data/spec/rails_app/tmp/cache/assets/test/sprockets/v3.0/TITv6kKDIwWXMb3nMX-OmOM1MM1mmsPg1LcooNVGG9Y.cache +0 -0
  58. data/spec/rails_app/tmp/cache/assets/test/sprockets/v3.0/U4FMxMcT2pVuJgZ0D8A0QRXYk9HkjcVtq5UUkSZo4T8.cache +3 -0
  59. data/spec/rails_app/tmp/cache/assets/test/sprockets/v3.0/Ue75Stcow3jQUURIsInN3UD7RoV7zwQ9QJPNgjMhbxA.cache +1 -0
  60. data/spec/rails_app/tmp/cache/assets/test/sprockets/v3.0/VQZge3nKTLKNH6_2qlFSj9_U6tszzMCCb3Dt8zlJLEs.cache +3 -0
  61. data/spec/rails_app/tmp/cache/assets/test/sprockets/v3.0/WobYryqMWrJJ1FO5WUyND9wkonpQ-k0TFRSdlnJxQpA.cache +2 -0
  62. data/spec/rails_app/tmp/cache/assets/test/sprockets/v3.0/WukfMkB8j3K5Frrr4G-QucfwskKB-pt4ZVVOF9ctkWc.cache +1 -0
  63. data/spec/rails_app/tmp/cache/assets/test/sprockets/v3.0/Xf7wDNUuYgkKRSiNrAXnd202ySmPUYH7Bz1uh7NkQ3E.cache +1 -0
  64. data/spec/rails_app/tmp/cache/assets/test/sprockets/v3.0/Z-Roe_JsgiZpkKE_8qoVGx3TMCSMOoPhPovT2mkAz80.cache +1 -0
  65. data/spec/rails_app/tmp/cache/assets/test/sprockets/v3.0/ZdXCd9BmMKvjHoZpHQB-YyFuGeaVXUMrcAu2LxlrUD8.cache +1 -0
  66. data/spec/rails_app/tmp/cache/assets/test/sprockets/v3.0/ZyKlKxGLZqtOZ1B5xqNJAy5I17yM_tX3zg_pk0fthZI.cache +1 -0
  67. data/spec/rails_app/tmp/cache/assets/test/sprockets/v3.0/_DDbKzjQQKg6BAaLR73pixBhcBdqyJWKjrqiRBqz2eg.cache +2 -0
  68. data/spec/rails_app/tmp/cache/assets/test/sprockets/v3.0/aEe8dZBMoJN_L7dQ9O90etuJwhYBZaxRLXPLkI4lwXU.cache +3 -0
  69. data/spec/rails_app/tmp/cache/assets/test/sprockets/v3.0/apG5zQKUGPau7gI490daUVsPkALVV2jmMhHowsEv_uc.cache +0 -0
  70. data/spec/rails_app/tmp/cache/assets/test/sprockets/v3.0/bigAjWfxtrTpxpryFTjOzuZDpQN1TQn2LgyC2UX608A.cache +3 -0
  71. data/spec/rails_app/tmp/cache/assets/test/sprockets/v3.0/cC4aVV6WxpZQ1JV9tiqJ7c1SHial-X4fXVKIL_0cSNk.cache +1 -0
  72. data/spec/rails_app/tmp/cache/assets/test/sprockets/v3.0/eCXlP45Wc2ERhH-FkBXtTDoS_WnSRhTr0gswBg-RRfY.cache +0 -0
  73. data/spec/rails_app/tmp/cache/assets/test/sprockets/v3.0/eHpCOzyMXB_heVVMB3p9CZ1SETj9OoVhd_4vmYxVjKs.cache +1 -0
  74. data/spec/rails_app/tmp/cache/assets/test/sprockets/v3.0/ez37HtozJjtuxDJ7zpMQKEA8mmmXbeo_53mQclPL4aw.cache +0 -0
  75. data/spec/rails_app/tmp/cache/assets/test/sprockets/v3.0/hAQjVJYrPwre3Y-BQAhTqMEnxoGw0-4b7qhLyD52dAg.cache +0 -0
  76. data/spec/rails_app/tmp/cache/assets/test/sprockets/v3.0/hhhcBN5dBU2-wGGwdUrlOVzAEf9gVcyGUcbFgHPMDpw.cache +1 -0
  77. data/spec/rails_app/tmp/cache/assets/test/sprockets/v3.0/j0GxKFTTXVLhgLP0leVrUzi9J5Vk0iv5I3Etnvf1hKo.cache +3 -0
  78. data/spec/rails_app/tmp/cache/assets/test/sprockets/v3.0/jJtmBEK1VRWyzZxlArUpOZ_eLVOhOnVYeZqq0bIsyEc.cache +0 -0
  79. data/spec/rails_app/tmp/cache/assets/test/sprockets/v3.0/jOCRCYDoaF271HXVDnj1U6FBFjKDD49spXEobwxFHoY.cache +1 -0
  80. data/spec/rails_app/tmp/cache/assets/test/sprockets/v3.0/jUcv_4GPi-D5jFNvcEkNKl60eXmJV3voiuFymwpMEZc.cache +2 -0
  81. data/spec/rails_app/tmp/cache/assets/test/sprockets/v3.0/jbxonAySrT1xyOeSqtRWBQz1vraED9_QfuVtGgPSPgw.cache +0 -0
  82. data/spec/rails_app/tmp/cache/assets/test/sprockets/v3.0/kAGXQElMVnAPNM2Gp_-yrWrZ53cEVOJg4rSrqelTa74.cache +1 -0
  83. data/spec/rails_app/tmp/cache/assets/test/sprockets/v3.0/kAtTT8eQbqVAPn3r0CLbsK1K84vbYpAJO-cDeriRN_4.cache +1 -0
  84. data/spec/rails_app/tmp/cache/assets/test/sprockets/v3.0/ll8jtsHipPGjByuvi5Cfqa4nz7g5si6q5arg9iK3hB8.cache +1 -0
  85. data/spec/rails_app/tmp/cache/assets/test/sprockets/v3.0/m7qNudRV2a_8us3h_WQ0MenSTjES5wu_R4CiBsCFbIQ.cache +1 -0
  86. data/spec/rails_app/tmp/cache/assets/test/sprockets/v3.0/nONU3x7H75eQ2Xaw3GMC0pKEWPyMtRxMJ9Y-l0Ayq6M.cache +33 -0
  87. data/spec/rails_app/tmp/cache/assets/test/sprockets/v3.0/nY3J4dkHhQje-2nXPqoqWH-9rzW2pK2HwaMfQbsfoIM.cache +1 -0
  88. data/spec/rails_app/tmp/cache/assets/test/sprockets/v3.0/oKqCIaSUcvj99uxAW-9dg1RT6kfhkaQXnWbKgR05uXs.cache +1 -0
  89. data/spec/rails_app/tmp/cache/assets/test/sprockets/v3.0/pOy3DFQaPfNEszqVjOsUM2d4fMorRrlDjUZCBLXfdWY.cache +1 -0
  90. data/spec/rails_app/tmp/cache/assets/test/sprockets/v3.0/qA9aqXy3Z7iNVnH_S00EnHsObKjU4gBjfAi0LsK31ec.cache +1 -0
  91. data/spec/rails_app/tmp/cache/assets/test/sprockets/v3.0/qoifXlMbps0buakSToSMKGUzijDll20f2phfUWvTveI.cache +0 -0
  92. data/spec/rails_app/tmp/cache/assets/test/sprockets/v3.0/qp_LekwrmrrQbsDBfH1bncgh22iq3wpSny6qolOBxrg.cache +1 -0
  93. data/spec/rails_app/tmp/cache/assets/test/sprockets/v3.0/rAhxfb71OMNOOASBBxbuJxVZWEHebArv3N7bzdiPqmk.cache +0 -0
  94. data/spec/rails_app/tmp/cache/assets/test/sprockets/v3.0/rED6iTVwl15Rj1k2LO38e0eCQitK-lMbvwpdz3G4mkU.cache +0 -0
  95. data/spec/rails_app/tmp/cache/assets/test/sprockets/v3.0/rqAXfU5_qJvYOuvQFsv4-Bsr993COgaOPKutmISI9Ac.cache +3 -0
  96. data/spec/rails_app/tmp/cache/assets/test/sprockets/v3.0/sbkgYxjKRuP8wk525y6VBNm00JCRW3rELt3mRvcfhUo.cache +13 -0
  97. data/spec/rails_app/tmp/cache/assets/test/sprockets/v3.0/srA1w0iCmsgYQvL_8ETHApAWdkqP7mRv3yRsts_8oks.cache +3 -0
  98. data/spec/rails_app/tmp/cache/assets/test/sprockets/v3.0/t3yuTQREe-_jlUIsoNfmFjrCncCUapXxX196qXhdtHM.cache +0 -0
  99. data/spec/rails_app/tmp/cache/assets/test/sprockets/v3.0/uytA8PznWSrTlIdRDkZ0cbhA72VDTsEeaj1MEK3XS18.cache +2 -0
  100. data/spec/rails_app/tmp/cache/assets/test/sprockets/v3.0/vWTf1CyFrHGKFakqn3HWhHKawzFnpTRXP0NaqPKXZj8.cache +2 -0
  101. data/spec/rails_app/tmp/cache/assets/test/sprockets/v3.0/vhuMIsvEbEL-zaLp1RZEIWd3sZDg4gCw6Am1tFfZEhY.cache +0 -0
  102. data/spec/rails_app/tmp/cache/assets/test/sprockets/v3.0/ynpdaUV6dj37pI5aP5Ki9BLQf9UEcqkc_yL9fCeoOU0.cache +0 -0
  103. data/spec/rails_app/tmp/cache/assets/test/sprockets/v3.0/yr5lGfFwzSXWHCuM8LahKsYDRGqJt4eMSPcc7WU1gkE.cache +0 -0
  104. metadata +213 -28
  105. checksums.yaml +0 -7
  106. data/netzke-testing.gemspec +0 -21
data/CHANGELOG.md ADDED
@@ -0,0 +1 @@
1
+ * Fix `wait` hanging at server exception
data/Gemfile CHANGED
@@ -2,7 +2,7 @@ source 'https://rubygems.org'
2
2
 
3
3
  gemspec
4
4
 
5
- gem 'rails', '4.2.0'
5
+ gem 'rails', '~>4.2.0'
6
6
  gem 'sqlite3'
7
7
  gem 'yard'
8
8
  gem 'rake'
@@ -15,8 +15,7 @@ group :test do
15
15
  end
16
16
 
17
17
  group :development, :test do
18
- gem 'byebug'
19
18
  gem 'web-console', '~> 2.0'
20
19
  gem 'pry-rails'
21
- gem 'netzke-core', github: 'netzke/netzke-core'
20
+ gem 'netzke-core', github: 'netzke/netzke-core', branch: 'master'
22
21
  end
data/LICENSE.txt CHANGED
@@ -1,22 +1,3 @@
1
- Copyright (c) 2015 Max Gorin
1
+ Copyright (c) 2009-2015 Good Bit Labs Limited
2
2
 
3
- MIT License
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining
6
- a copy of this software and associated documentation files (the
7
- "Software"), to deal in the Software without restriction, including
8
- without limitation the rights to use, copy, modify, merge, publish,
9
- distribute, sublicense, and/or sell copies of the Software, and to
10
- permit persons to whom the Software is furnished to do so, subject to
11
- the following conditions:
12
-
13
- The above copyright notice and this permission notice shall be
14
- included in all copies or substantial portions of the Software.
15
-
16
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
- LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
- OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
3
+ GPLv3 License: http://www.gnu.org/licenses/gpl-3.0.en.html
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # Netzke Testing [![Gem Version](https://fury-badge.herokuapp.com/rb/netzke-testing.png)](http://badge.fury.io/rb/netzke-testing)
1
+ # Netzke Testing [![Build Status](https://travis-ci.org/netzke/netzke-testing.png?branch=master)](https://travis-ci.org/netzke/netzke-testing) [![Gem Version](https://fury-badge.herokuapp.com/rb/netzke-testing.png)](http://badge.fury.io/rb/netzke-testing)
2
2
 
3
3
  This gem helps with development and testing of Netzke components. In parcticular, it helps you with:
4
4
 
@@ -7,7 +7,7 @@ This gem helps with development and testing of Netzke components. In parcticular
7
7
 
8
8
  Usage:
9
9
 
10
- gem 'netzke_testing'
10
+ gem 'netzke-testing'
11
11
 
12
12
  ## Isolated component development
13
13
 
@@ -157,14 +157,15 @@ Asynchronous helpers like `wait` can either call the provided callback function,
157
157
  .then
158
158
  doSomeMore()
159
159
 
160
+ ## Note on headless browser testing
161
+
162
+ No headless browsers like PhantomJS or WebKit were used for testing because our tests rely heavily on HTMLElement's `click` event, which is only properly implemented in "real" browsers like Firefox (which is what we use).
163
+
160
164
  ## Requirements
161
165
 
162
- * Ruby >= 2.0.0
166
+ * Ruby >= 1.9.3
163
167
  * Rails ~> 4.2.0
164
168
  * Ext JS = 5.1.0
165
169
 
166
170
  ---
167
- © 2015 [Max Gorin](https://twitter.com/mxgrn), released under the MIT license (see LICENSE).
168
-
169
- **Note** that Ext JS is licensed [differently](http://www.sencha.com/products/extjs/license/), and you may need to
170
- purchase a commercial license in order to use it in your projects!
171
+ Copyright (c) 2009-2015 [Good Bit Labs Limited](http://goodbitlabs.com/), released under the GPLv3 license
@@ -5,6 +5,9 @@ Ext.Ajax.on 'beforerequest', ->
5
5
  Ext.Ajax.on 'requestcomplete', ->
6
6
  Netzke.ajaxCount -= 1
7
7
 
8
+ Ext.Ajax.on 'requestexception', ->
9
+ Netzke.ajaxCount -= 1
10
+
8
11
  Ext.apply window,
9
12
  # Waits for all AJAX activity to stop, then calls the optional callback. If no callback was specified, returns a
10
13
  # promise. The first argument can be a number of milliseconds to wait before starting to listen to the AJAX activity
@@ -57,12 +57,7 @@ Ext.apply window,
57
57
 
58
58
  valuesInColumn: (name, params = {}) ->
59
59
  grid = params.in || @grid()
60
- out = []
61
- i = 0
62
- grid.getStore().each (r) ->
63
- out.push valueInCell(name, i++, params)
64
-
65
- out
60
+ valueInCell(name, i, params) for i in [0..grid.getStore().getCount()-1]
66
61
 
67
62
  # Example:
68
63
  # valueInCell 'author__name', 2
@@ -78,7 +73,7 @@ Ext.apply window,
78
73
  selectAllRows: (params) ->
79
74
  params ?= {}
80
75
  grid = params.in || @grid()
81
- grid.getSelectionModel().selectAll()
76
+ grid.getSelectionModel().selectRange(0, grid.getStore().getCount() - 1)
82
77
 
83
78
  # rowDisplayValues in: grid('Books'), of: grid('Books').getStore().last()
84
79
  # Without parameters, assumes the first found grid and the selected row
@@ -94,7 +89,7 @@ Ext.apply window,
94
89
  i = -1
95
90
  return Ext.Array.map(Ext.DomQuery.select('table[data-recordid="'+record.internalId+'"] tbody tr td div'), (cell) ->
96
91
  i++
97
- if visibleColumns[i].attrType == 'boolean'
92
+ if visibleColumns[i].type == 'boolean'
98
93
  record.get(visibleColumns[i].name)
99
94
  else
100
95
  cell.innerHTML
@@ -106,7 +101,7 @@ Ext.apply window,
106
101
  selectLastRow: (params) ->
107
102
  params ?= {}
108
103
  grid = params.in || @grid()
109
- grid.getSelectionModel().select(grid.getStore().last())
104
+ grid.getSelectionModel().select(grid.getStore().getCount() - 1)
110
105
 
111
106
  # Examples:
112
107
  # selectFirstRow()
@@ -114,7 +109,7 @@ Ext.apply window,
114
109
  selectFirstRow: (params) ->
115
110
  params ?= {}
116
111
  grid = params.in || @grid()
117
- grid.getSelectionModel().select(grid.getStore().first())
112
+ grid.getSelectionModel().select(0)
118
113
 
119
114
  # Examples:
120
115
  # selectRow 5
@@ -138,3 +133,14 @@ Ext.apply window,
138
133
  g = g || @grid()
139
134
  e = g.getPlugin('celleditor')
140
135
  e.completeEdit()
136
+
137
+ # Double clicks currently selected row
138
+ dblclickRow: (params = {}) ->
139
+ grid = params.in || @grid()
140
+ record = grid.getSelectionModel().getSelection()[0]
141
+ rowEl = Ext.DomQuery.select('table[data-recordid="'+record.internalId+'"] tbody tr td div')[0]
142
+ event = new MouseEvent 'dblclick',
143
+ view: window
144
+ bubbles: true
145
+ cancelable: true
146
+ rowEl.dispatchEvent(event)
@@ -10,11 +10,16 @@ Ext.apply window,
10
10
  panelWithContent: (text) ->
11
11
  Ext.DomQuery.select("div.x-panel-body:contains(" + text + ")")[0] || 'panel with content ' + text
12
12
 
13
- button: (text) ->
14
- button = Ext.ComponentQuery.query("button{isVisible(true)}[text='"+text+"']")[0]
15
- button ||= Ext.ComponentQuery.query("button{isVisible(true)}[tooltip='"+text+"']")[0]
13
+ button: (text, params = {}) ->
14
+ context = params.within || Ext.ComponentQuery
15
+
16
+ button = context.query("button{isVisible(true)}[text='"+text+"']")[0]
17
+ button ||= context.query("button{isVisible(true)}[tooltip='"+text+"']")[0]
16
18
  button || "button " + text
17
19
 
20
+ panel: (name) ->
21
+ Ext.getCmp(name)
22
+
18
23
  tool: (type) ->
19
24
  Ext.ComponentQuery.query("tool{isVisible(true)}[type='"+type+"']")[0] || 'tool ' + type
20
25
 
@@ -32,26 +37,26 @@ Ext.apply window,
32
37
 
33
38
  combobox: (name) ->
34
39
  Ext.ComponentQuery.query("combo{isVisible(true)}[name='"+name+"']")[0] ||
35
- 'combobox ' + name
40
+ "combobox '#{name}'"
36
41
 
37
42
  icon: (tooltip) ->
38
43
  Ext.DomQuery.select('img[data-qtip="'+tooltip+'"]')[0] || 'icon ' + tooltip
39
44
 
40
45
  textfield: (name) ->
41
46
  Ext.ComponentQuery.query("textfield{isVisible(true)}[name='"+name+"']")[0] ||
42
- 'textfield ' + name
47
+ "textfield '#{name}'"
43
48
 
44
49
  numberfield: (name) ->
45
50
  Ext.ComponentQuery.query("numberfield{isVisible(true)}[name='"+name+"']")[0] ||
46
- 'numberfield ' + name
51
+ "numberfield '#{name}'"
47
52
 
48
53
  datefield: (name) ->
49
54
  Ext.ComponentQuery.query("datefield{isVisible(true)}[name='"+name+"']")[0] ||
50
- 'datefield ' + name
55
+ "datefield '#{name}'"
51
56
 
52
57
  xdatetime: (name) ->
53
58
  Ext.ComponentQuery.query("xdatetime{isVisible(true)}[name='"+name+"']")[0] ||
54
- 'xdatetime ' + name
59
+ "xdatetime '#{name}'"
55
60
 
56
61
  textFieldWith: (text) ->
57
62
  _componentLike "textfield", "value", text
@@ -69,7 +74,7 @@ Ext.apply window,
69
74
  Ext.WindowMgr.getActive()
70
75
 
71
76
  dateTimeFieldWith: (value) ->
72
- res = 'xdatetime with value ' + value
77
+ res = "xdatetime with value '#{value}'"
73
78
  Ext.each Ext.ComponentQuery.query('xdatetime'), (item) ->
74
79
  if item.getValue().toString() == (new Date(value)).toString()
75
80
  res = item
@@ -77,7 +82,7 @@ Ext.apply window,
77
82
  res
78
83
 
79
84
  dateFieldWith: (value) ->
80
- res = 'datefield with value ' + value
85
+ res = "datefield with value '#{value}'"
81
86
  Ext.each Ext.ComponentQuery.query('datefield'), (item) ->
82
87
  if item.getValue().toString() == (new Date(value)).toString()
83
88
  res = item
@@ -98,5 +103,6 @@ Ext.apply window,
98
103
 
99
104
  _componentLike:(type,attr,value)->
100
105
  Ext.ComponentQuery.query(type+'['+attr+'='+value+']')[0] || type + " with " + attr + " '" + value + "'"
106
+
101
107
  # alias
102
108
  window.anywhere = window.somewhere
@@ -1,6 +1,5 @@
1
1
  ;(function(){
2
2
 
3
-
4
3
  // CommonJS require()
5
4
 
6
5
  function require(p){
@@ -49,16 +48,15 @@ require.relative = function (parent) {
49
48
 
50
49
 
51
50
  require.register("browser/debug.js", function(module, exports, require){
52
-
53
51
  module.exports = function(type){
54
52
  return function(){
55
-
56
53
  }
57
54
  };
55
+
58
56
  }); // module: browser/debug.js
59
57
 
60
58
  require.register("browser/diff.js", function(module, exports, require){
61
- /* See license.txt for terms of usage */
59
+ /* See LICENSE file for terms of use */
62
60
 
63
61
  /*
64
62
  * Text diff implementation.
@@ -75,6 +73,7 @@ require.register("browser/diff.js", function(module, exports, require){
75
73
  * http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.4.6927
76
74
  */
77
75
  var JsDiff = (function() {
76
+ /*jshint maxparams: 5*/
78
77
  function clonePath(path) {
79
78
  return { newPos: path.newPos, components: path.components.slice(0) };
80
79
  }
@@ -89,22 +88,21 @@ var JsDiff = (function() {
89
88
  }
90
89
  function escapeHTML(s) {
91
90
  var n = s;
92
- n = n.replace(/&/g, "&");
93
- n = n.replace(/</g, "&lt;");
94
- n = n.replace(/>/g, "&gt;");
95
- n = n.replace(/"/g, "&quot;");
91
+ n = n.replace(/&/g, '&amp;');
92
+ n = n.replace(/</g, '&lt;');
93
+ n = n.replace(/>/g, '&gt;');
94
+ n = n.replace(/"/g, '&quot;');
96
95
 
97
96
  return n;
98
97
  }
99
98
 
100
-
101
- var fbDiff = function(ignoreWhitespace) {
99
+ var Diff = function(ignoreWhitespace) {
102
100
  this.ignoreWhitespace = ignoreWhitespace;
103
101
  };
104
- fbDiff.prototype = {
102
+ Diff.prototype = {
105
103
  diff: function(oldString, newString) {
106
104
  // Handle the identity case (this is due to unrolling editLength == 0
107
- if (newString == oldString) {
105
+ if (newString === oldString) {
108
106
  return [{ value: newString }];
109
107
  }
110
108
  if (!newString) {
@@ -199,7 +197,7 @@ var JsDiff = (function() {
199
197
  if (this.ignoreWhitespace && !reWhitespace.test(left) && !reWhitespace.test(right)) {
200
198
  return true;
201
199
  } else {
202
- return left == right;
200
+ return left === right;
203
201
  }
204
202
  },
205
203
  join: function(left, right) {
@@ -210,26 +208,45 @@ var JsDiff = (function() {
210
208
  }
211
209
  };
212
210
 
213
- var CharDiff = new fbDiff();
211
+ var CharDiff = new Diff();
214
212
 
215
- var WordDiff = new fbDiff(true);
216
- WordDiff.tokenize = function(value) {
213
+ var WordDiff = new Diff(true);
214
+ var WordWithSpaceDiff = new Diff();
215
+ WordDiff.tokenize = WordWithSpaceDiff.tokenize = function(value) {
217
216
  return removeEmpty(value.split(/(\s+|\b)/));
218
217
  };
219
218
 
220
- var CssDiff = new fbDiff(true);
219
+ var CssDiff = new Diff(true);
221
220
  CssDiff.tokenize = function(value) {
222
221
  return removeEmpty(value.split(/([{}:;,]|\s+)/));
223
222
  };
224
223
 
225
- var LineDiff = new fbDiff();
224
+ var LineDiff = new Diff();
226
225
  LineDiff.tokenize = function(value) {
227
- return value.split(/^/m);
226
+ var retLines = [],
227
+ lines = value.split(/^/m);
228
+
229
+ for(var i = 0; i < lines.length; i++) {
230
+ var line = lines[i],
231
+ lastLine = lines[i - 1];
232
+
233
+ // Merge lines that may contain windows new lines
234
+ if (line == '\n' && lastLine && lastLine[lastLine.length - 1] === '\r') {
235
+ retLines[retLines.length - 1] += '\n';
236
+ } else if (line) {
237
+ retLines.push(line);
238
+ }
239
+ }
240
+
241
+ return retLines;
228
242
  };
229
243
 
230
244
  return {
245
+ Diff: Diff,
246
+
231
247
  diffChars: function(oldStr, newStr) { return CharDiff.diff(oldStr, newStr); },
232
248
  diffWords: function(oldStr, newStr) { return WordDiff.diff(oldStr, newStr); },
249
+ diffWordsWithSpace: function(oldStr, newStr) { return WordWithSpaceDiff.diff(oldStr, newStr); },
233
250
  diffLines: function(oldStr, newStr) { return LineDiff.diff(oldStr, newStr); },
234
251
 
235
252
  diffCss: function(oldStr, newStr) { return CssDiff.diff(oldStr, newStr); },
@@ -237,16 +254,16 @@ var JsDiff = (function() {
237
254
  createPatch: function(fileName, oldStr, newStr, oldHeader, newHeader) {
238
255
  var ret = [];
239
256
 
240
- ret.push("Index: " + fileName);
241
- ret.push("===================================================================");
242
- ret.push("--- " + fileName + (typeof oldHeader === "undefined" ? "" : "\t" + oldHeader));
243
- ret.push("+++ " + fileName + (typeof newHeader === "undefined" ? "" : "\t" + newHeader));
257
+ ret.push('Index: ' + fileName);
258
+ ret.push('===================================================================');
259
+ ret.push('--- ' + fileName + (typeof oldHeader === 'undefined' ? '' : '\t' + oldHeader));
260
+ ret.push('+++ ' + fileName + (typeof newHeader === 'undefined' ? '' : '\t' + newHeader));
244
261
 
245
262
  var diff = LineDiff.diff(oldStr, newStr);
246
263
  if (!diff[diff.length-1].value) {
247
264
  diff.pop(); // Remove trailing newline add
248
265
  }
249
- diff.push({value: "", lines: []}); // Append an empty value to make cleanup easier
266
+ diff.push({value: '', lines: []}); // Append an empty value to make cleanup easier
250
267
 
251
268
  function contextLines(lines) {
252
269
  return lines.map(function(entry) { return ' ' + entry; });
@@ -254,7 +271,7 @@ var JsDiff = (function() {
254
271
  function eofNL(curRange, i, current) {
255
272
  var last = diff[diff.length-2],
256
273
  isLast = i === diff.length-2,
257
- isLastOfType = i === diff.length-3 && (current.added === !last.added || current.removed === !last.removed);
274
+ isLastOfType = i === diff.length-3 && (current.added !== last.added || current.removed !== last.removed);
258
275
 
259
276
  // Figure out if this is the last line for the given file and missing NL
260
277
  if (!/\n$/.test(current.value) && (isLast || isLastOfType)) {
@@ -266,7 +283,7 @@ var JsDiff = (function() {
266
283
  oldLine = 1, newLine = 1;
267
284
  for (var i = 0; i < diff.length; i++) {
268
285
  var current = diff[i],
269
- lines = current.lines || current.value.replace(/\n$/, "").split("\n");
286
+ lines = current.lines || current.value.replace(/\n$/, '').split('\n');
270
287
  current.lines = lines;
271
288
 
272
289
  if (current.added || current.removed) {
@@ -281,7 +298,7 @@ var JsDiff = (function() {
281
298
  newRangeStart -= curRange.length;
282
299
  }
283
300
  }
284
- curRange.push.apply(curRange, lines.map(function(entry) { return (current.added?"+":"-") + entry; }));
301
+ curRange.push.apply(curRange, lines.map(function(entry) { return (current.added?'+':'-') + entry; }));
285
302
  eofNL(curRange, i, current);
286
303
 
287
304
  if (current.added) {
@@ -299,9 +316,9 @@ var JsDiff = (function() {
299
316
  // end the range and output
300
317
  var contextSize = Math.min(lines.length, 4);
301
318
  ret.push(
302
- "@@ -" + oldRangeStart + "," + (oldLine-oldRangeStart+contextSize)
303
- + " +" + newRangeStart + "," + (newLine-newRangeStart+contextSize)
304
- + " @@");
319
+ '@@ -' + oldRangeStart + ',' + (oldLine-oldRangeStart+contextSize)
320
+ + ' +' + newRangeStart + ',' + (newLine-newRangeStart+contextSize)
321
+ + ' @@');
305
322
  ret.push.apply(ret, curRange);
306
323
  ret.push.apply(ret, contextLines(lines.slice(0, contextSize)));
307
324
  if (lines.length <= 4) {
@@ -319,37 +336,114 @@ var JsDiff = (function() {
319
336
  return ret.join('\n') + '\n';
320
337
  },
321
338
 
339
+ applyPatch: function(oldStr, uniDiff) {
340
+ var diffstr = uniDiff.split('\n');
341
+ var diff = [];
342
+ var remEOFNL = false,
343
+ addEOFNL = false;
344
+
345
+ for (var i = (diffstr[0][0]==='I'?4:0); i < diffstr.length; i++) {
346
+ if(diffstr[i][0] === '@') {
347
+ var meh = diffstr[i].split(/@@ -(\d+),(\d+) \+(\d+),(\d+) @@/);
348
+ diff.unshift({
349
+ start:meh[3],
350
+ oldlength:meh[2],
351
+ oldlines:[],
352
+ newlength:meh[4],
353
+ newlines:[]
354
+ });
355
+ } else if(diffstr[i][0] === '+') {
356
+ diff[0].newlines.push(diffstr[i].substr(1));
357
+ } else if(diffstr[i][0] === '-') {
358
+ diff[0].oldlines.push(diffstr[i].substr(1));
359
+ } else if(diffstr[i][0] === ' ') {
360
+ diff[0].newlines.push(diffstr[i].substr(1));
361
+ diff[0].oldlines.push(diffstr[i].substr(1));
362
+ } else if(diffstr[i][0] === '\\') {
363
+ if (diffstr[i-1][0] === '+') {
364
+ remEOFNL = true;
365
+ } else if(diffstr[i-1][0] === '-') {
366
+ addEOFNL = true;
367
+ }
368
+ }
369
+ }
370
+
371
+ var str = oldStr.split('\n');
372
+ for (var i = diff.length - 1; i >= 0; i--) {
373
+ var d = diff[i];
374
+ for (var j = 0; j < d.oldlength; j++) {
375
+ if(str[d.start-1+j] !== d.oldlines[j]) {
376
+ return false;
377
+ }
378
+ }
379
+ Array.prototype.splice.apply(str,[d.start-1,+d.oldlength].concat(d.newlines));
380
+ }
381
+
382
+ if (remEOFNL) {
383
+ while (!str[str.length-1]) {
384
+ str.pop();
385
+ }
386
+ } else if (addEOFNL) {
387
+ str.push('');
388
+ }
389
+ return str.join('\n');
390
+ },
391
+
322
392
  convertChangesToXML: function(changes){
323
393
  var ret = [];
324
394
  for ( var i = 0; i < changes.length; i++) {
325
395
  var change = changes[i];
326
396
  if (change.added) {
327
- ret.push("<ins>");
397
+ ret.push('<ins>');
328
398
  } else if (change.removed) {
329
- ret.push("<del>");
399
+ ret.push('<del>');
330
400
  }
331
401
 
332
402
  ret.push(escapeHTML(change.value));
333
403
 
334
404
  if (change.added) {
335
- ret.push("</ins>");
405
+ ret.push('</ins>');
336
406
  } else if (change.removed) {
337
- ret.push("</del>");
407
+ ret.push('</del>');
338
408
  }
339
409
  }
340
- return ret.join("");
410
+ return ret.join('');
411
+ },
412
+
413
+ // See: http://code.google.com/p/google-diff-match-patch/wiki/API
414
+ convertChangesToDMP: function(changes){
415
+ var ret = [], change;
416
+ for ( var i = 0; i < changes.length; i++) {
417
+ change = changes[i];
418
+ ret.push([(change.added ? 1 : change.removed ? -1 : 0), change.value]);
419
+ }
420
+ return ret;
341
421
  }
342
422
  };
343
423
  })();
344
424
 
345
- if (typeof module !== "undefined") {
425
+ if (typeof module !== 'undefined') {
346
426
  module.exports = JsDiff;
347
427
  }
348
428
 
349
429
  }); // module: browser/diff.js
350
430
 
351
- require.register("browser/events.js", function(module, exports, require){
431
+ require.register("browser/escape-string-regexp.js", function(module, exports, require){
432
+ 'use strict';
433
+
434
+ var matchOperatorsRe = /[|\\{}()[\]^$+*?.]/g;
435
+
436
+ module.exports = function (str) {
437
+ if (typeof str !== 'string') {
438
+ throw new TypeError('Expected a string');
439
+ }
440
+
441
+ return str.replace(matchOperatorsRe, '\\$&');
442
+ };
443
+
444
+ }); // module: browser/escape-string-regexp.js
352
445
 
446
+ require.register("browser/events.js", function(module, exports, require){
353
447
  /**
354
448
  * Module exports.
355
449
  */
@@ -527,18 +621,22 @@ EventEmitter.prototype.emit = function (name) {
527
621
 
528
622
  return true;
529
623
  };
624
+
530
625
  }); // module: browser/events.js
531
626
 
532
627
  require.register("browser/fs.js", function(module, exports, require){
533
628
 
534
629
  }); // module: browser/fs.js
535
630
 
631
+ require.register("browser/glob.js", function(module, exports, require){
632
+
633
+ }); // module: browser/glob.js
634
+
536
635
  require.register("browser/path.js", function(module, exports, require){
537
636
 
538
637
  }); // module: browser/path.js
539
638
 
540
639
  require.register("browser/progress.js", function(module, exports, require){
541
-
542
640
  /**
543
641
  * Expose `Progress`.
544
642
  */
@@ -627,58 +725,63 @@ Progress.prototype.update = function(n){
627
725
  */
628
726
 
629
727
  Progress.prototype.draw = function(ctx){
630
- var percent = Math.min(this.percent, 100)
631
- , size = this._size
632
- , half = size / 2
633
- , x = half
634
- , y = half
635
- , rad = half - 1
636
- , fontSize = this._fontSize;
637
-
638
- ctx.font = fontSize + 'px ' + this._font;
639
-
640
- var angle = Math.PI * 2 * (percent / 100);
641
- ctx.clearRect(0, 0, size, size);
642
-
643
- // outer circle
644
- ctx.strokeStyle = '#9f9f9f';
645
- ctx.beginPath();
646
- ctx.arc(x, y, rad, 0, angle, false);
647
- ctx.stroke();
648
-
649
- // inner circle
650
- ctx.strokeStyle = '#eee';
651
- ctx.beginPath();
652
- ctx.arc(x, y, rad - 1, 0, angle, true);
653
- ctx.stroke();
654
-
655
- // text
656
- var text = this._text || (percent | 0) + '%'
657
- , w = ctx.measureText(text).width;
658
-
659
- ctx.fillText(
660
- text
661
- , x - w / 2 + 1
662
- , y + fontSize / 2 - 1);
663
-
728
+ try {
729
+ var percent = Math.min(this.percent, 100)
730
+ , size = this._size
731
+ , half = size / 2
732
+ , x = half
733
+ , y = half
734
+ , rad = half - 1
735
+ , fontSize = this._fontSize;
736
+
737
+ ctx.font = fontSize + 'px ' + this._font;
738
+
739
+ var angle = Math.PI * 2 * (percent / 100);
740
+ ctx.clearRect(0, 0, size, size);
741
+
742
+ // outer circle
743
+ ctx.strokeStyle = '#9f9f9f';
744
+ ctx.beginPath();
745
+ ctx.arc(x, y, rad, 0, angle, false);
746
+ ctx.stroke();
747
+
748
+ // inner circle
749
+ ctx.strokeStyle = '#eee';
750
+ ctx.beginPath();
751
+ ctx.arc(x, y, rad - 1, 0, angle, true);
752
+ ctx.stroke();
753
+
754
+ // text
755
+ var text = this._text || (percent | 0) + '%'
756
+ , w = ctx.measureText(text).width;
757
+
758
+ ctx.fillText(
759
+ text
760
+ , x - w / 2 + 1
761
+ , y + fontSize / 2 - 1);
762
+ } catch (ex) {} //don't fail if we can't render progress
664
763
  return this;
665
764
  };
666
765
 
667
766
  }); // module: browser/progress.js
668
767
 
669
768
  require.register("browser/tty.js", function(module, exports, require){
670
-
671
769
  exports.isatty = function(){
672
770
  return true;
673
771
  };
674
772
 
675
773
  exports.getWindowSize = function(){
676
- return [window.innerHeight, window.innerWidth];
774
+ if ('innerHeight' in global) {
775
+ return [global.innerHeight, global.innerWidth];
776
+ } else {
777
+ // In a Web Worker, the DOM Window is not available.
778
+ return [640, 480];
779
+ }
677
780
  };
781
+
678
782
  }); // module: browser/tty.js
679
783
 
680
784
  require.register("context.js", function(module, exports, require){
681
-
682
785
  /**
683
786
  * Expose `Context`.
684
787
  */
@@ -716,10 +819,25 @@ Context.prototype.runnable = function(runnable){
716
819
  */
717
820
 
718
821
  Context.prototype.timeout = function(ms){
822
+ if (arguments.length === 0) return this.runnable().timeout();
719
823
  this.runnable().timeout(ms);
720
824
  return this;
721
825
  };
722
826
 
827
+ /**
828
+ * Set test timeout `enabled`.
829
+ *
830
+ * @param {Boolean} enabled
831
+ * @return {Context} self
832
+ * @api private
833
+ */
834
+
835
+ Context.prototype.enableTimeouts = function (enabled) {
836
+ this.runnable().enableTimeouts(enabled);
837
+ return this;
838
+ };
839
+
840
+
723
841
  /**
724
842
  * Set test slowness threshold `ms`.
725
843
  *
@@ -733,6 +851,18 @@ Context.prototype.slow = function(ms){
733
851
  return this;
734
852
  };
735
853
 
854
+ /**
855
+ * Mark a test as skipped.
856
+ *
857
+ * @return {Context} self
858
+ * @api private
859
+ */
860
+
861
+ Context.prototype.skip = function(){
862
+ this.runnable().skip();
863
+ return this;
864
+ };
865
+
736
866
  /**
737
867
  * Inspect the context void of `._runnable`.
738
868
  *
@@ -751,7 +881,6 @@ Context.prototype.inspect = function(){
751
881
  }); // module: context.js
752
882
 
753
883
  require.register("hook.js", function(module, exports, require){
754
-
755
884
  /**
756
885
  * Module dependencies.
757
886
  */
@@ -805,17 +934,17 @@ Hook.prototype.error = function(err){
805
934
  this._error = err;
806
935
  };
807
936
 
808
-
809
937
  }); // module: hook.js
810
938
 
811
939
  require.register("interfaces/bdd.js", function(module, exports, require){
812
-
813
940
  /**
814
941
  * Module dependencies.
815
942
  */
816
943
 
817
944
  var Suite = require('../suite')
818
- , Test = require('../test');
945
+ , Test = require('../test')
946
+ , utils = require('../utils')
947
+ , escapeRe = require('browser/escape-string-regexp');
819
948
 
820
949
  /**
821
950
  * BDD-style interface:
@@ -839,38 +968,13 @@ module.exports = function(suite){
839
968
 
840
969
  suite.on('pre-require', function(context, file, mocha){
841
970
 
842
- /**
843
- * Execute before running tests.
844
- */
845
-
846
- context.before = function(fn){
847
- suites[0].beforeAll(fn);
848
- };
849
-
850
- /**
851
- * Execute after running tests.
852
- */
853
-
854
- context.after = function(fn){
855
- suites[0].afterAll(fn);
856
- };
857
-
858
- /**
859
- * Execute before each test case.
860
- */
861
-
862
- context.beforeEach = function(fn){
863
- suites[0].beforeEach(fn);
864
- };
865
-
866
- /**
867
- * Execute after each test case.
868
- */
869
-
870
- context.afterEach = function(fn){
871
- suites[0].afterEach(fn);
872
- };
971
+ var common = require('./common')(suites, context);
873
972
 
973
+ context.before = common.before;
974
+ context.after = common.after;
975
+ context.beforeEach = common.beforeEach;
976
+ context.afterEach = common.afterEach;
977
+ context.run = mocha.options.delay && common.runWithSuite(suite);
874
978
  /**
875
979
  * Describe a "suite" with the given `title`
876
980
  * and callback `fn` containing nested suites
@@ -879,6 +983,7 @@ module.exports = function(suite){
879
983
 
880
984
  context.describe = context.context = function(title, fn){
881
985
  var suite = Suite.create(suites[0], title);
986
+ suite.file = file;
882
987
  suites.unshift(suite);
883
988
  fn.call(suite);
884
989
  suites.shift();
@@ -906,6 +1011,7 @@ module.exports = function(suite){
906
1011
  context.describe.only = function(title, fn){
907
1012
  var suite = context.describe(title, fn);
908
1013
  mocha.grep(suite.fullTitle());
1014
+ return suite;
909
1015
  };
910
1016
 
911
1017
  /**
@@ -916,8 +1022,9 @@ module.exports = function(suite){
916
1022
 
917
1023
  context.it = context.specify = function(title, fn){
918
1024
  var suite = suites[0];
919
- if (suite.pending) var fn = null;
1025
+ if (suite.pending) fn = null;
920
1026
  var test = new Test(title, fn);
1027
+ test.file = file;
921
1028
  suite.addTest(test);
922
1029
  return test;
923
1030
  };
@@ -928,7 +1035,9 @@ module.exports = function(suite){
928
1035
 
929
1036
  context.it.only = function(title, fn){
930
1037
  var test = context.it(title, fn);
931
- mocha.grep(test.fullTitle());
1038
+ var reString = '^' + escapeRe(test.fullTitle()) + '$';
1039
+ mocha.grep(new RegExp(reString));
1040
+ return test;
932
1041
  };
933
1042
 
934
1043
  /**
@@ -940,13 +1049,75 @@ module.exports = function(suite){
940
1049
  context.it.skip = function(title){
941
1050
  context.it(title);
942
1051
  };
1052
+
943
1053
  });
944
1054
  };
945
1055
 
946
1056
  }); // module: interfaces/bdd.js
947
1057
 
948
- require.register("interfaces/exports.js", function(module, exports, require){
1058
+ require.register("interfaces/common.js", function(module, exports, require){
1059
+ /**
1060
+ * Functions common to more than one interface
1061
+ * @module lib/interfaces/common
1062
+ */
1063
+
1064
+ 'use strict';
1065
+
1066
+ module.exports = function (suites, context) {
1067
+
1068
+ return {
1069
+ /**
1070
+ * This is only present if flag --delay is passed into Mocha. It triggers
1071
+ * root suite execution. Returns a function which runs the root suite.
1072
+ */
1073
+ runWithSuite: function runWithSuite(suite) {
1074
+ return function run() {
1075
+ suite.run();
1076
+ };
1077
+ },
1078
+
1079
+ /**
1080
+ * Execute before running tests.
1081
+ */
1082
+ before: function (name, fn) {
1083
+ suites[0].beforeAll(name, fn);
1084
+ },
1085
+
1086
+ /**
1087
+ * Execute after running tests.
1088
+ */
1089
+ after: function (name, fn) {
1090
+ suites[0].afterAll(name, fn);
1091
+ },
1092
+
1093
+ /**
1094
+ * Execute before each test case.
1095
+ */
1096
+ beforeEach: function (name, fn) {
1097
+ suites[0].beforeEach(name, fn);
1098
+ },
1099
+
1100
+ /**
1101
+ * Execute after each test case.
1102
+ */
1103
+ afterEach: function (name, fn) {
1104
+ suites[0].afterEach(name, fn);
1105
+ },
1106
+
1107
+ test: {
1108
+ /**
1109
+ * Pending test case.
1110
+ */
1111
+ skip: function (title) {
1112
+ context.test(title);
1113
+ }
1114
+ }
1115
+ }
1116
+ };
1117
+
1118
+ }); // module: interfaces/common.js
949
1119
 
1120
+ require.register("interfaces/exports.js", function(module, exports, require){
950
1121
  /**
951
1122
  * Module dependencies.
952
1123
  */
@@ -976,7 +1147,7 @@ module.exports = function(suite){
976
1147
 
977
1148
  suite.on('require', visit);
978
1149
 
979
- function visit(obj) {
1150
+ function visit(obj, file) {
980
1151
  var suite;
981
1152
  for (var key in obj) {
982
1153
  if ('function' == typeof obj[key]) {
@@ -995,10 +1166,12 @@ module.exports = function(suite){
995
1166
  suites[0].afterEach(fn);
996
1167
  break;
997
1168
  default:
998
- suites[0].addTest(new Test(key, fn));
1169
+ var test = new Test(key, fn);
1170
+ test.file = file;
1171
+ suites[0].addTest(test);
999
1172
  }
1000
1173
  } else {
1001
- var suite = Suite.create(suites[0], key);
1174
+ suite = Suite.create(suites[0], key);
1002
1175
  suites.unshift(suite);
1003
1176
  visit(obj[key]);
1004
1177
  suites.shift();
@@ -1006,10 +1179,10 @@ module.exports = function(suite){
1006
1179
  }
1007
1180
  }
1008
1181
  };
1182
+
1009
1183
  }); // module: interfaces/exports.js
1010
1184
 
1011
1185
  require.register("interfaces/index.js", function(module, exports, require){
1012
-
1013
1186
  exports.bdd = require('./bdd');
1014
1187
  exports.tdd = require('./tdd');
1015
1188
  exports.qunit = require('./qunit');
@@ -1018,13 +1191,14 @@ exports.exports = require('./exports');
1018
1191
  }); // module: interfaces/index.js
1019
1192
 
1020
1193
  require.register("interfaces/qunit.js", function(module, exports, require){
1021
-
1022
1194
  /**
1023
1195
  * Module dependencies.
1024
1196
  */
1025
1197
 
1026
1198
  var Suite = require('../suite')
1027
- , Test = require('../test');
1199
+ , Test = require('../test')
1200
+ , escapeRe = require('browser/escape-string-regexp')
1201
+ , utils = require('../utils');
1028
1202
 
1029
1203
  /**
1030
1204
  * QUnit-style interface:
@@ -1054,72 +1228,75 @@ var Suite = require('../suite')
1054
1228
  module.exports = function(suite){
1055
1229
  var suites = [suite];
1056
1230
 
1057
- suite.on('pre-require', function(context){
1058
-
1059
- /**
1060
- * Execute before running tests.
1061
- */
1231
+ suite.on('pre-require', function(context, file, mocha){
1062
1232
 
1063
- context.before = function(fn){
1064
- suites[0].beforeAll(fn);
1065
- };
1233
+ var common = require('./common')(suites, context);
1066
1234
 
1235
+ context.before = common.before;
1236
+ context.after = common.after;
1237
+ context.beforeEach = common.beforeEach;
1238
+ context.afterEach = common.afterEach;
1239
+ context.run = mocha.options.delay && common.runWithSuite(suite);
1067
1240
  /**
1068
- * Execute after running tests.
1241
+ * Describe a "suite" with the given `title`.
1069
1242
  */
1070
1243
 
1071
- context.after = function(fn){
1072
- suites[0].afterAll(fn);
1244
+ context.suite = function(title){
1245
+ if (suites.length > 1) suites.shift();
1246
+ var suite = Suite.create(suites[0], title);
1247
+ suite.file = file;
1248
+ suites.unshift(suite);
1249
+ return suite;
1073
1250
  };
1074
1251
 
1075
1252
  /**
1076
- * Execute before each test case.
1253
+ * Exclusive test-case.
1077
1254
  */
1078
1255
 
1079
- context.beforeEach = function(fn){
1080
- suites[0].beforeEach(fn);
1256
+ context.suite.only = function(title, fn){
1257
+ var suite = context.suite(title, fn);
1258
+ mocha.grep(suite.fullTitle());
1081
1259
  };
1082
1260
 
1083
1261
  /**
1084
- * Execute after each test case.
1262
+ * Describe a specification or test-case
1263
+ * with the given `title` and callback `fn`
1264
+ * acting as a thunk.
1085
1265
  */
1086
1266
 
1087
- context.afterEach = function(fn){
1088
- suites[0].afterEach(fn);
1267
+ context.test = function(title, fn){
1268
+ var test = new Test(title, fn);
1269
+ test.file = file;
1270
+ suites[0].addTest(test);
1271
+ return test;
1089
1272
  };
1090
1273
 
1091
1274
  /**
1092
- * Describe a "suite" with the given `title`.
1275
+ * Exclusive test-case.
1093
1276
  */
1094
1277
 
1095
- context.suite = function(title){
1096
- if (suites.length > 1) suites.shift();
1097
- var suite = Suite.create(suites[0], title);
1098
- suites.unshift(suite);
1278
+ context.test.only = function(title, fn){
1279
+ var test = context.test(title, fn);
1280
+ var reString = '^' + escapeRe(test.fullTitle()) + '$';
1281
+ mocha.grep(new RegExp(reString));
1099
1282
  };
1100
1283
 
1101
- /**
1102
- * Describe a specification or test-case
1103
- * with the given `title` and callback `fn`
1104
- * acting as a thunk.
1105
- */
1284
+ context.test.skip = common.test.skip;
1106
1285
 
1107
- context.test = function(title, fn){
1108
- suites[0].addTest(new Test(title, fn));
1109
- };
1110
1286
  });
1111
1287
  };
1112
1288
 
1113
1289
  }); // module: interfaces/qunit.js
1114
1290
 
1115
1291
  require.register("interfaces/tdd.js", function(module, exports, require){
1116
-
1117
1292
  /**
1118
1293
  * Module dependencies.
1119
1294
  */
1120
1295
 
1121
1296
  var Suite = require('../suite')
1122
- , Test = require('../test');
1297
+ , Test = require('../test')
1298
+ , escapeRe = require('browser/escape-string-regexp')
1299
+ , utils = require('../utils');
1123
1300
 
1124
1301
  /**
1125
1302
  * TDD-style interface:
@@ -1151,38 +1328,13 @@ module.exports = function(suite){
1151
1328
 
1152
1329
  suite.on('pre-require', function(context, file, mocha){
1153
1330
 
1154
- /**
1155
- * Execute before each test case.
1156
- */
1157
-
1158
- context.setup = function(fn){
1159
- suites[0].beforeEach(fn);
1160
- };
1161
-
1162
- /**
1163
- * Execute after each test case.
1164
- */
1165
-
1166
- context.teardown = function(fn){
1167
- suites[0].afterEach(fn);
1168
- };
1169
-
1170
- /**
1171
- * Execute before the suite.
1172
- */
1173
-
1174
- context.suiteSetup = function(fn){
1175
- suites[0].beforeAll(fn);
1176
- };
1177
-
1178
- /**
1179
- * Execute after the suite.
1180
- */
1181
-
1182
- context.suiteTeardown = function(fn){
1183
- suites[0].afterAll(fn);
1184
- };
1331
+ var common = require('./common')(suites, context);
1185
1332
 
1333
+ context.setup = common.beforeEach;
1334
+ context.teardown = common.afterEach;
1335
+ context.suiteSetup = common.before;
1336
+ context.suiteTeardown = common.after;
1337
+ context.run = mocha.options.delay && common.runWithSuite(suite);
1186
1338
  /**
1187
1339
  * Describe a "suite" with the given `title`
1188
1340
  * and callback `fn` containing nested suites
@@ -1191,12 +1343,24 @@ module.exports = function(suite){
1191
1343
 
1192
1344
  context.suite = function(title, fn){
1193
1345
  var suite = Suite.create(suites[0], title);
1346
+ suite.file = file;
1194
1347
  suites.unshift(suite);
1195
1348
  fn.call(suite);
1196
1349
  suites.shift();
1197
1350
  return suite;
1198
1351
  };
1199
1352
 
1353
+ /**
1354
+ * Pending suite.
1355
+ */
1356
+ context.suite.skip = function(title, fn) {
1357
+ var suite = Suite.create(suites[0], title);
1358
+ suite.pending = true;
1359
+ suites.unshift(suite);
1360
+ fn.call(suite);
1361
+ suites.shift();
1362
+ };
1363
+
1200
1364
  /**
1201
1365
  * Exclusive test-case.
1202
1366
  */
@@ -1213,8 +1377,11 @@ module.exports = function(suite){
1213
1377
  */
1214
1378
 
1215
1379
  context.test = function(title, fn){
1380
+ var suite = suites[0];
1381
+ if (suite.pending) fn = null;
1216
1382
  var test = new Test(title, fn);
1217
- suites[0].addTest(test);
1383
+ test.file = file;
1384
+ suite.addTest(test);
1218
1385
  return test;
1219
1386
  };
1220
1387
 
@@ -1224,16 +1391,11 @@ module.exports = function(suite){
1224
1391
 
1225
1392
  context.test.only = function(title, fn){
1226
1393
  var test = context.test(title, fn);
1227
- mocha.grep(test.fullTitle());
1394
+ var reString = '^' + escapeRe(test.fullTitle()) + '$';
1395
+ mocha.grep(new RegExp(reString));
1228
1396
  };
1229
1397
 
1230
- /**
1231
- * Pending test case.
1232
- */
1233
-
1234
- context.test.skip = function(title){
1235
- context.test(title);
1236
- };
1398
+ context.test.skip = common.test.skip;
1237
1399
  });
1238
1400
  };
1239
1401
 
@@ -1251,6 +1413,7 @@ require.register("mocha.js", function(module, exports, require){
1251
1413
  */
1252
1414
 
1253
1415
  var path = require('browser/path')
1416
+ , escapeRe = require('browser/escape-string-regexp')
1254
1417
  , utils = require('./utils');
1255
1418
 
1256
1419
  /**
@@ -1259,6 +1422,16 @@ var path = require('browser/path')
1259
1422
 
1260
1423
  exports = module.exports = Mocha;
1261
1424
 
1425
+ /**
1426
+ * To require local UIs and reporters when running in node.
1427
+ */
1428
+
1429
+ if (typeof process !== 'undefined' && typeof process.cwd === 'function') {
1430
+ var join = path.join
1431
+ , cwd = process.cwd();
1432
+ module.paths.push(cwd, join(cwd, 'node_modules'));
1433
+ }
1434
+
1262
1435
  /**
1263
1436
  * Expose internals.
1264
1437
  */
@@ -1291,12 +1464,13 @@ function image(name) {
1291
1464
  * Options:
1292
1465
  *
1293
1466
  * - `ui` name "bdd", "tdd", "exports" etc
1294
- * - `reporter` reporter instance, defaults to `mocha.reporters.Dot`
1467
+ * - `reporter` reporter instance, defaults to `mocha.reporters.spec`
1295
1468
  * - `globals` array of accepted globals
1296
1469
  * - `timeout` timeout in milliseconds
1297
1470
  * - `bail` bail on the first test failure
1298
1471
  * - `slow` milliseconds to wait before considering a test slow
1299
1472
  * - `ignoreLeaks` ignore global leaks
1473
+ * - `fullTrace` display the full stack-trace on failing
1300
1474
  * - `grep` string or regexp to filter tests with
1301
1475
  *
1302
1476
  * @param {Object} options
@@ -1307,13 +1481,32 @@ function Mocha(options) {
1307
1481
  options = options || {};
1308
1482
  this.files = [];
1309
1483
  this.options = options;
1310
- this.grep(options.grep);
1484
+ if (options.grep) this.grep(new RegExp(options.grep));
1485
+ if (options.fgrep) this.grep(options.fgrep);
1311
1486
  this.suite = new exports.Suite('', new exports.Context);
1312
1487
  this.ui(options.ui);
1313
1488
  this.bail(options.bail);
1314
- this.reporter(options.reporter);
1315
- if (options.timeout) this.timeout(options.timeout);
1489
+ this.reporter(options.reporter, options.reporterOptions);
1490
+ if (null != options.timeout) this.timeout(options.timeout);
1491
+ this.useColors(options.useColors);
1492
+ if (options.enableTimeouts !== null) this.enableTimeouts(options.enableTimeouts);
1316
1493
  if (options.slow) this.slow(options.slow);
1494
+
1495
+ this.suite.on('pre-require', function (context) {
1496
+ exports.afterEach = context.afterEach || context.teardown;
1497
+ exports.after = context.after || context.suiteTeardown;
1498
+ exports.beforeEach = context.beforeEach || context.setup;
1499
+ exports.before = context.before || context.suiteSetup;
1500
+ exports.describe = context.describe || context.suite;
1501
+ exports.it = context.it || context.test;
1502
+ exports.setup = context.setup || context.beforeEach;
1503
+ exports.suiteSetup = context.suiteSetup || context.before;
1504
+ exports.suiteTeardown = context.suiteTeardown || context.after;
1505
+ exports.suite = context.suite || context.describe;
1506
+ exports.teardown = context.teardown || context.afterEach;
1507
+ exports.test = context.test || context.it;
1508
+ exports.run = context.run;
1509
+ });
1317
1510
  }
1318
1511
 
1319
1512
  /**
@@ -1342,24 +1535,32 @@ Mocha.prototype.addFile = function(file){
1342
1535
  };
1343
1536
 
1344
1537
  /**
1345
- * Set reporter to `reporter`, defaults to "dot".
1538
+ * Set reporter to `reporter`, defaults to "spec".
1346
1539
  *
1347
1540
  * @param {String|Function} reporter name or constructor
1541
+ * @param {Object} reporterOptions optional options
1348
1542
  * @api public
1349
1543
  */
1350
-
1351
- Mocha.prototype.reporter = function(reporter){
1544
+ Mocha.prototype.reporter = function(reporter, reporterOptions){
1352
1545
  if ('function' == typeof reporter) {
1353
1546
  this._reporter = reporter;
1354
1547
  } else {
1355
- reporter = reporter || 'dot';
1356
- try {
1357
- this._reporter = require('./reporters/' + reporter);
1358
- } catch (err) {
1359
- this._reporter = require(reporter);
1548
+ reporter = reporter || 'spec';
1549
+ var _reporter;
1550
+ try { _reporter = require('./reporters/' + reporter); } catch (err) {}
1551
+ if (!_reporter) try { _reporter = require(reporter); } catch (err) {
1552
+ err.message.indexOf('Cannot find module') !== -1
1553
+ ? console.warn('"' + reporter + '" reporter not found')
1554
+ : console.warn('"' + reporter + '" reporter blew up with error:\n' + err.stack);
1360
1555
  }
1361
- if (!this._reporter) throw new Error('invalid reporter "' + reporter + '"');
1556
+ if (!_reporter && reporter === 'teamcity')
1557
+ console.warn('The Teamcity reporter was moved to a package named ' +
1558
+ 'mocha-teamcity-reporter ' +
1559
+ '(https://npmjs.org/package/mocha-teamcity-reporter).');
1560
+ if (!_reporter) throw new Error('invalid reporter "' + reporter + '"');
1561
+ this._reporter = _reporter;
1362
1562
  }
1563
+ this.options.reporterOptions = reporterOptions;
1363
1564
  return this;
1364
1565
  };
1365
1566
 
@@ -1373,6 +1574,7 @@ Mocha.prototype.reporter = function(reporter){
1373
1574
  Mocha.prototype.ui = function(name){
1374
1575
  name = name || 'bdd';
1375
1576
  this._ui = exports.interfaces[name];
1577
+ if (!this._ui) try { this._ui = require(name); } catch (err) {}
1376
1578
  if (!this._ui) throw new Error('invalid interface "' + name + '"');
1377
1579
  this._ui = this._ui(this.suite);
1378
1580
  return this;
@@ -1431,7 +1633,7 @@ Mocha.prototype._growl = function(runner, reporter) {
1431
1633
 
1432
1634
  Mocha.prototype.grep = function(re){
1433
1635
  this.options.grep = 'string' == typeof re
1434
- ? new RegExp(utils.escapeRegexp(re))
1636
+ ? new RegExp(escapeRe(re))
1435
1637
  : re;
1436
1638
  return this;
1437
1639
  };
@@ -1451,12 +1653,13 @@ Mocha.prototype.invert = function(){
1451
1653
  /**
1452
1654
  * Ignore global leaks.
1453
1655
  *
1656
+ * @param {Boolean} ignore
1454
1657
  * @return {Mocha}
1455
1658
  * @api public
1456
1659
  */
1457
1660
 
1458
- Mocha.prototype.ignoreLeaks = function(){
1459
- this.options.ignoreLeaks = true;
1661
+ Mocha.prototype.ignoreLeaks = function(ignore){
1662
+ this.options.ignoreLeaks = !!ignore;
1460
1663
  return this;
1461
1664
  };
1462
1665
 
@@ -1472,6 +1675,18 @@ Mocha.prototype.checkLeaks = function(){
1472
1675
  return this;
1473
1676
  };
1474
1677
 
1678
+ /**
1679
+ * Display long stack-trace on failing
1680
+ *
1681
+ * @return {Mocha}
1682
+ * @api public
1683
+ */
1684
+
1685
+ Mocha.prototype.fullTrace = function() {
1686
+ this.options.fullStackTrace = true;
1687
+ return this;
1688
+ };
1689
+
1475
1690
  /**
1476
1691
  * Enable growl support.
1477
1692
  *
@@ -1498,69 +1713,145 @@ Mocha.prototype.globals = function(globals){
1498
1713
  };
1499
1714
 
1500
1715
  /**
1501
- * Set the timeout in milliseconds.
1716
+ * Emit color output.
1502
1717
  *
1503
- * @param {Number} timeout
1718
+ * @param {Boolean} colors
1504
1719
  * @return {Mocha}
1505
1720
  * @api public
1506
1721
  */
1507
1722
 
1508
- Mocha.prototype.timeout = function(timeout){
1509
- this.suite.timeout(timeout);
1723
+ Mocha.prototype.useColors = function(colors){
1724
+ if (colors !== undefined) {
1725
+ this.options.useColors = colors;
1726
+ }
1510
1727
  return this;
1511
1728
  };
1512
1729
 
1513
1730
  /**
1514
- * Set slowness threshold in milliseconds.
1731
+ * Use inline diffs rather than +/-.
1515
1732
  *
1516
- * @param {Number} slow
1733
+ * @param {Boolean} inlineDiffs
1517
1734
  * @return {Mocha}
1518
1735
  * @api public
1519
1736
  */
1520
1737
 
1521
- Mocha.prototype.slow = function(slow){
1522
- this.suite.slow(slow);
1738
+ Mocha.prototype.useInlineDiffs = function(inlineDiffs) {
1739
+ this.options.useInlineDiffs = arguments.length && inlineDiffs != undefined
1740
+ ? inlineDiffs
1741
+ : false;
1523
1742
  return this;
1524
1743
  };
1525
1744
 
1526
1745
  /**
1527
- * Makes all tests async (accepting a callback)
1746
+ * Set the timeout in milliseconds.
1528
1747
  *
1748
+ * @param {Number} timeout
1529
1749
  * @return {Mocha}
1530
1750
  * @api public
1531
1751
  */
1532
1752
 
1533
- Mocha.prototype.asyncOnly = function(){
1534
- this.options.asyncOnly = true;
1753
+ Mocha.prototype.timeout = function(timeout){
1754
+ this.suite.timeout(timeout);
1535
1755
  return this;
1536
1756
  };
1537
1757
 
1538
1758
  /**
1539
- * Run tests and invoke `fn()` when complete.
1759
+ * Set slowness threshold in milliseconds.
1540
1760
  *
1541
- * @param {Function} fn
1542
- * @return {Runner}
1761
+ * @param {Number} slow
1762
+ * @return {Mocha}
1763
+ * @api public
1764
+ */
1765
+
1766
+ Mocha.prototype.slow = function(slow){
1767
+ this.suite.slow(slow);
1768
+ return this;
1769
+ };
1770
+
1771
+ /**
1772
+ * Enable timeouts.
1773
+ *
1774
+ * @param {Boolean} enabled
1775
+ * @return {Mocha}
1776
+ * @api public
1777
+ */
1778
+
1779
+ Mocha.prototype.enableTimeouts = function(enabled) {
1780
+ this.suite.enableTimeouts(arguments.length && enabled !== undefined
1781
+ ? enabled
1782
+ : true);
1783
+ return this
1784
+ };
1785
+
1786
+ /**
1787
+ * Makes all tests async (accepting a callback)
1788
+ *
1789
+ * @return {Mocha}
1790
+ * @api public
1791
+ */
1792
+
1793
+ Mocha.prototype.asyncOnly = function(){
1794
+ this.options.asyncOnly = true;
1795
+ return this;
1796
+ };
1797
+
1798
+ /**
1799
+ * Disable syntax highlighting (in browser).
1800
+ * @returns {Mocha}
1543
1801
  * @api public
1544
1802
  */
1803
+ Mocha.prototype.noHighlighting = function() {
1804
+ this.options.noHighlighting = true;
1805
+ return this;
1806
+ };
1807
+
1808
+ /**
1809
+ * Delay root suite execution.
1810
+ * @returns {Mocha}
1811
+ * @api public
1812
+ */
1813
+ Mocha.prototype.delay = function delay() {
1814
+ this.options.delay = true;
1815
+ return this;
1816
+ };
1545
1817
 
1818
+ /**
1819
+ * Run tests and invoke `fn()` when complete.
1820
+ *
1821
+ * @param {Function} fn
1822
+ * @return {Runner}
1823
+ * @api public
1824
+ */
1546
1825
  Mocha.prototype.run = function(fn){
1547
1826
  if (this.files.length) this.loadFiles();
1548
1827
  var suite = this.suite;
1549
1828
  var options = this.options;
1550
- var runner = new exports.Runner(suite);
1551
- var reporter = new this._reporter(runner);
1552
- runner.ignoreLeaks = options.ignoreLeaks;
1829
+ options.files = this.files;
1830
+ var runner = new exports.Runner(suite, options.delay);
1831
+ var reporter = new this._reporter(runner, options);
1832
+ runner.ignoreLeaks = false !== options.ignoreLeaks;
1833
+ runner.fullStackTrace = options.fullStackTrace;
1553
1834
  runner.asyncOnly = options.asyncOnly;
1554
1835
  if (options.grep) runner.grep(options.grep, options.invert);
1555
1836
  if (options.globals) runner.globals(options.globals);
1556
1837
  if (options.growl) this._growl(runner, reporter);
1557
- return runner.run(fn);
1838
+ if (options.useColors !== undefined) {
1839
+ exports.reporters.Base.useColors = options.useColors;
1840
+ }
1841
+ exports.reporters.Base.inlineDiffs = options.useInlineDiffs;
1842
+
1843
+ function done(failures) {
1844
+ if (reporter.done) {
1845
+ reporter.done(failures, fn);
1846
+ } else fn && fn(failures);
1847
+ }
1848
+
1849
+ return runner.run(done);
1558
1850
  };
1559
1851
 
1560
1852
  }); // module: mocha.js
1561
1853
 
1562
1854
  require.register("ms.js", function(module, exports, require){
1563
-
1564
1855
  /**
1565
1856
  * Helpers.
1566
1857
  */
@@ -1569,19 +1860,26 @@ var s = 1000;
1569
1860
  var m = s * 60;
1570
1861
  var h = m * 60;
1571
1862
  var d = h * 24;
1863
+ var y = d * 365.25;
1572
1864
 
1573
1865
  /**
1574
1866
  * Parse or format the given `val`.
1575
1867
  *
1868
+ * Options:
1869
+ *
1870
+ * - `long` verbose formatting [false]
1871
+ *
1576
1872
  * @param {String|Number} val
1873
+ * @param {Object} options
1577
1874
  * @return {String|Number}
1578
1875
  * @api public
1579
1876
  */
1580
1877
 
1581
- module.exports = function(val){
1878
+ module.exports = function(val, options){
1879
+ options = options || {};
1582
1880
  if ('string' == typeof val) return parse(val);
1583
- return format(val);
1584
- }
1881
+ return options['long'] ? longFormat(val) : shortFormat(val);
1882
+ };
1585
1883
 
1586
1884
  /**
1587
1885
  * Parse the given `str` and return milliseconds.
@@ -1592,66 +1890,110 @@ module.exports = function(val){
1592
1890
  */
1593
1891
 
1594
1892
  function parse(str) {
1595
- var m = /^((?:\d+)?\.?\d+) *(ms|seconds?|s|minutes?|m|hours?|h|days?|d|years?|y)?$/i.exec(str);
1596
- if (!m) return;
1597
- var n = parseFloat(m[1]);
1598
- var type = (m[2] || 'ms').toLowerCase();
1893
+ var match = /^((?:\d+)?\.?\d+) *(ms|seconds?|s|minutes?|m|hours?|h|days?|d|years?|y)?$/i.exec(str);
1894
+ if (!match) return;
1895
+ var n = parseFloat(match[1]);
1896
+ var type = (match[2] || 'ms').toLowerCase();
1599
1897
  switch (type) {
1600
1898
  case 'years':
1601
1899
  case 'year':
1602
1900
  case 'y':
1603
- return n * 31557600000;
1901
+ return n * y;
1604
1902
  case 'days':
1605
1903
  case 'day':
1606
1904
  case 'd':
1607
- return n * 86400000;
1905
+ return n * d;
1608
1906
  case 'hours':
1609
1907
  case 'hour':
1610
1908
  case 'h':
1611
- return n * 3600000;
1909
+ return n * h;
1612
1910
  case 'minutes':
1613
1911
  case 'minute':
1614
1912
  case 'm':
1615
- return n * 60000;
1913
+ return n * m;
1616
1914
  case 'seconds':
1617
1915
  case 'second':
1618
1916
  case 's':
1619
- return n * 1000;
1917
+ return n * s;
1620
1918
  case 'ms':
1621
1919
  return n;
1622
1920
  }
1623
1921
  }
1624
1922
 
1625
1923
  /**
1626
- * Format the given `ms`.
1924
+ * Short format for `ms`.
1627
1925
  *
1628
1926
  * @param {Number} ms
1629
1927
  * @return {String}
1630
- * @api public
1928
+ * @api private
1929
+ */
1930
+
1931
+ function shortFormat(ms) {
1932
+ if (ms >= d) return Math.round(ms / d) + 'd';
1933
+ if (ms >= h) return Math.round(ms / h) + 'h';
1934
+ if (ms >= m) return Math.round(ms / m) + 'm';
1935
+ if (ms >= s) return Math.round(ms / s) + 's';
1936
+ return ms + 'ms';
1937
+ }
1938
+
1939
+ /**
1940
+ * Long format for `ms`.
1941
+ *
1942
+ * @param {Number} ms
1943
+ * @return {String}
1944
+ * @api private
1945
+ */
1946
+
1947
+ function longFormat(ms) {
1948
+ return plural(ms, d, 'day')
1949
+ || plural(ms, h, 'hour')
1950
+ || plural(ms, m, 'minute')
1951
+ || plural(ms, s, 'second')
1952
+ || ms + ' ms';
1953
+ }
1954
+
1955
+ /**
1956
+ * Pluralization helper.
1631
1957
  */
1632
1958
 
1633
- function format(ms) {
1634
- if (ms == d) return Math.round(ms / d) + ' day';
1635
- if (ms > d) return Math.round(ms / d) + ' days';
1636
- if (ms == h) return Math.round(ms / h) + ' hour';
1637
- if (ms > h) return Math.round(ms / h) + ' hours';
1638
- if (ms == m) return Math.round(ms / m) + ' minute';
1639
- if (ms > m) return Math.round(ms / m) + ' minutes';
1640
- if (ms == s) return Math.round(ms / s) + ' second';
1641
- if (ms > s) return Math.round(ms / s) + ' seconds';
1642
- return ms + ' ms';
1959
+ function plural(ms, n, name) {
1960
+ if (ms < n) return;
1961
+ if (ms < n * 1.5) return Math.floor(ms / n) + ' ' + name;
1962
+ return Math.ceil(ms / n) + ' ' + name + 's';
1643
1963
  }
1964
+
1644
1965
  }); // module: ms.js
1645
1966
 
1646
- require.register("reporters/base.js", function(module, exports, require){
1967
+ require.register("pending.js", function(module, exports, require){
1968
+
1969
+ /**
1970
+ * Expose `Pending`.
1971
+ */
1647
1972
 
1973
+ module.exports = Pending;
1974
+
1975
+ /**
1976
+ * Initialize a new `Pending` error with the given message.
1977
+ *
1978
+ * @param {String} message
1979
+ */
1980
+
1981
+ function Pending(message) {
1982
+ this.message = message;
1983
+ }
1984
+
1985
+ }); // module: pending.js
1986
+
1987
+ require.register("reporters/base.js", function(module, exports, require){
1648
1988
  /**
1649
1989
  * Module dependencies.
1650
1990
  */
1651
1991
 
1652
1992
  var tty = require('browser/tty')
1653
1993
  , diff = require('browser/diff')
1654
- , ms = require('../ms');
1994
+ , ms = require('../ms')
1995
+ , utils = require('../utils')
1996
+ , supportsColor = process.env ? require('supports-color') : null;
1655
1997
 
1656
1998
  /**
1657
1999
  * Save timer references to avoid Sinon interfering (see GH-237).
@@ -1676,10 +2018,18 @@ var isatty = tty.isatty(1) && tty.isatty(2);
1676
2018
  exports = module.exports = Base;
1677
2019
 
1678
2020
  /**
1679
- * Enable coloring by default.
2021
+ * Enable coloring by default, except in the browser interface.
2022
+ */
2023
+
2024
+ exports.useColors = process.env
2025
+ ? (supportsColor || (process.env.MOCHA_COLORS !== undefined))
2026
+ : false;
2027
+
2028
+ /**
2029
+ * Inline diffs instead of +/-
1680
2030
  */
1681
2031
 
1682
- exports.useColors = isatty;
2032
+ exports.inlineDiffs = false;
1683
2033
 
1684
2034
  /**
1685
2035
  * Default color map.
@@ -1737,7 +2087,7 @@ if ('win32' == process.platform) {
1737
2087
  */
1738
2088
 
1739
2089
  var color = exports.color = function(type, str) {
1740
- if (!exports.useColors) return str;
2090
+ if (!exports.useColors) return String(str);
1741
2091
  return '\u001b[' + exports.colors[type] + 'm' + str + '\u001b[0m';
1742
2092
  };
1743
2093
 
@@ -1761,24 +2111,28 @@ exports.window = {
1761
2111
 
1762
2112
  exports.cursor = {
1763
2113
  hide: function(){
1764
- process.stdout.write('\u001b[?25l');
2114
+ isatty && process.stdout.write('\u001b[?25l');
1765
2115
  },
1766
2116
 
1767
2117
  show: function(){
1768
- process.stdout.write('\u001b[?25h');
2118
+ isatty && process.stdout.write('\u001b[?25h');
1769
2119
  },
1770
2120
 
1771
2121
  deleteLine: function(){
1772
- process.stdout.write('\u001b[2K');
2122
+ isatty && process.stdout.write('\u001b[2K');
1773
2123
  },
1774
2124
 
1775
2125
  beginningOfLine: function(){
1776
- process.stdout.write('\u001b[0G');
2126
+ isatty && process.stdout.write('\u001b[0G');
1777
2127
  },
1778
2128
 
1779
2129
  CR: function(){
1780
- exports.cursor.deleteLine();
1781
- exports.cursor.beginningOfLine();
2130
+ if (isatty) {
2131
+ exports.cursor.deleteLine();
2132
+ exports.cursor.beginningOfLine();
2133
+ } else {
2134
+ process.stdout.write('\r');
2135
+ }
1782
2136
  }
1783
2137
  };
1784
2138
 
@@ -1790,8 +2144,9 @@ exports.cursor = {
1790
2144
  */
1791
2145
 
1792
2146
  exports.list = function(failures){
1793
- console.error();
2147
+ console.log();
1794
2148
  failures.forEach(function(test, i){
2149
+ console.log("test ", test);
1795
2150
  // format
1796
2151
  var fmt = color('error title', ' %s) %s:\n')
1797
2152
  + color('error message', ' %s')
@@ -1801,56 +2156,48 @@ exports.list = function(failures){
1801
2156
  var err = test.err
1802
2157
  , message = err.message || ''
1803
2158
  , stack = err.stack || message
1804
- , index = stack.indexOf(message) + message.length
1805
- , msg = stack.slice(0, index)
2159
+ , index = stack.indexOf(message)
1806
2160
  , actual = err.actual
1807
2161
  , expected = err.expected
1808
2162
  , escape = true;
1809
-
1810
- // explicitly show diff
1811
- if (err.showDiff) {
1812
- escape = false;
1813
- err.actual = actual = JSON.stringify(actual, null, 2);
1814
- err.expected = expected = JSON.stringify(expected, null, 2);
2163
+ if (index === -1) {
2164
+ msg = message;
2165
+ } else {
2166
+ index += message.length;
2167
+ msg = stack.slice(0, index);
2168
+ // remove msg from stack
2169
+ stack = stack.slice(index + 1);
1815
2170
  }
1816
2171
 
1817
- // actual / expected diff
1818
- if ('string' == typeof actual && 'string' == typeof expected) {
1819
- var len = Math.max(actual.length, expected.length);
1820
-
1821
- if (len < 20) msg = errorDiff(err, 'Chars', escape);
1822
- else msg = errorDiff(err, 'Words', escape);
2172
+ // uncaught
2173
+ if (err.uncaught) {
2174
+ msg = 'Uncaught ' + msg;
2175
+ }
2176
+ // explicitly show diff
2177
+ if (err.showDiff !== false && sameType(actual, expected)
2178
+ && expected !== undefined) {
1823
2179
 
1824
- // linenos
1825
- var lines = msg.split('\n');
1826
- if (lines.length > 4) {
1827
- var width = String(lines.length).length;
1828
- msg = lines.map(function(str, i){
1829
- return pad(++i, width) + ' |' + ' ' + str;
1830
- }).join('\n');
2180
+ if ('string' !== typeof actual) {
2181
+ escape = false;
2182
+ err.actual = actual = utils.stringify(actual);
2183
+ err.expected = expected = utils.stringify(expected);
1831
2184
  }
1832
2185
 
1833
- // legend
1834
- msg = '\n'
1835
- + color('diff removed', 'actual')
1836
- + ' '
1837
- + color('diff added', 'expected')
1838
- + '\n\n'
1839
- + msg
1840
- + '\n';
1841
-
1842
- // indent
1843
- msg = msg.replace(/^/gm, ' ');
2186
+ fmt = color('error title', ' %s) %s:\n%s') + color('error stack', '\n%s\n');
2187
+ var match = message.match(/^([^:]+): expected/);
2188
+ msg = '\n ' + color('error message', match ? match[1] : msg);
1844
2189
 
1845
- fmt = color('error title', ' %s) %s:\n%s')
1846
- + color('error stack', '\n%s\n');
2190
+ if (exports.inlineDiffs) {
2191
+ msg += inlineDiff(err, escape);
2192
+ } else {
2193
+ msg += unifiedDiff(err, escape);
2194
+ }
1847
2195
  }
1848
2196
 
1849
- // indent stack trace without msg
1850
- stack = stack.slice(index ? index + 1 : index)
1851
- .replace(/^/gm, ' ');
2197
+ // indent stack trace
2198
+ stack = stack.replace(/^/gm, ' ');
1852
2199
 
1853
- console.error(fmt, (i + 1), test.fullTitle(), msg, stack);
2200
+ console.log(fmt, (i + 1), test.fullTitle(), msg, stack);
1854
2201
  });
1855
2202
  };
1856
2203
 
@@ -1928,48 +2275,37 @@ function Base(runner) {
1928
2275
  */
1929
2276
 
1930
2277
  Base.prototype.epilogue = function(){
1931
- var stats = this.stats
1932
- , fmt
1933
- , tests;
2278
+ var stats = this.stats;
2279
+ var tests;
2280
+ var fmt;
1934
2281
 
1935
2282
  console.log();
1936
2283
 
1937
- function pluralize(n) {
1938
- return 1 == n ? 'test' : 'tests';
1939
- }
1940
-
1941
- // failure
1942
- if (stats.failures) {
1943
- fmt = color('bright fail', ' ' + exports.symbols.err)
1944
- + color('fail', ' %d of %d %s failed')
1945
- + color('light', ':')
1946
-
1947
- console.error(fmt,
1948
- stats.failures,
1949
- this.runner.total,
1950
- pluralize(this.runner.total));
1951
-
1952
- Base.list(this.failures);
1953
- console.error();
1954
- return;
1955
- }
1956
-
1957
- // pass
2284
+ // passes
1958
2285
  fmt = color('bright pass', ' ')
1959
- + color('green', ' %d %s complete')
2286
+ + color('green', ' %d passing')
1960
2287
  + color('light', ' (%s)');
1961
2288
 
1962
2289
  console.log(fmt,
1963
- stats.tests || 0,
1964
- pluralize(stats.tests),
2290
+ stats.passes || 0,
1965
2291
  ms(stats.duration));
1966
2292
 
1967
2293
  // pending
1968
2294
  if (stats.pending) {
1969
2295
  fmt = color('pending', ' ')
1970
- + color('pending', ' %d %s pending');
2296
+ + color('pending', ' %d pending');
2297
+
2298
+ console.log(fmt, stats.pending);
2299
+ }
2300
+
2301
+ // failures
2302
+ if (stats.failures) {
2303
+ fmt = color('fail', ' %d failing');
2304
+
2305
+ console.log(fmt, stats.failures);
1971
2306
 
1972
- console.log(fmt, stats.pending, pluralize(stats.pending));
2307
+ Base.list(this.failures);
2308
+ console.log();
1973
2309
  }
1974
2310
 
1975
2311
  console.log();
@@ -1989,6 +2325,73 @@ function pad(str, len) {
1989
2325
  return Array(len - str.length + 1).join(' ') + str;
1990
2326
  }
1991
2327
 
2328
+
2329
+ /**
2330
+ * Returns an inline diff between 2 strings with coloured ANSI output
2331
+ *
2332
+ * @param {Error} Error with actual/expected
2333
+ * @return {String} Diff
2334
+ * @api private
2335
+ */
2336
+
2337
+ function inlineDiff(err, escape) {
2338
+ var msg = errorDiff(err, 'WordsWithSpace', escape);
2339
+
2340
+ // linenos
2341
+ var lines = msg.split('\n');
2342
+ if (lines.length > 4) {
2343
+ var width = String(lines.length).length;
2344
+ msg = lines.map(function(str, i){
2345
+ return pad(++i, width) + ' |' + ' ' + str;
2346
+ }).join('\n');
2347
+ }
2348
+
2349
+ // legend
2350
+ msg = '\n'
2351
+ + color('diff removed', 'actual')
2352
+ + ' '
2353
+ + color('diff added', 'expected')
2354
+ + '\n\n'
2355
+ + msg
2356
+ + '\n';
2357
+
2358
+ // indent
2359
+ msg = msg.replace(/^/gm, ' ');
2360
+ return msg;
2361
+ }
2362
+
2363
+ /**
2364
+ * Returns a unified diff between 2 strings
2365
+ *
2366
+ * @param {Error} Error with actual/expected
2367
+ * @return {String} Diff
2368
+ * @api private
2369
+ */
2370
+
2371
+ function unifiedDiff(err, escape) {
2372
+ var indent = ' ';
2373
+ function cleanUp(line) {
2374
+ if (escape) {
2375
+ line = escapeInvisibles(line);
2376
+ }
2377
+ if (line[0] === '+') return indent + colorLines('diff added', line);
2378
+ if (line[0] === '-') return indent + colorLines('diff removed', line);
2379
+ if (line.match(/\@\@/)) return null;
2380
+ if (line.match(/\\ No newline/)) return null;
2381
+ else return indent + line;
2382
+ }
2383
+ function notBlank(line) {
2384
+ return line != null;
2385
+ }
2386
+ var msg = diff.createPatch('string', err.actual, err.expected);
2387
+ var lines = msg.split('\n').splice(4);
2388
+ return '\n '
2389
+ + colorLines('diff added', '+ expected') + ' '
2390
+ + colorLines('diff removed', '- actual')
2391
+ + '\n\n'
2392
+ + lines.map(cleanUp).filter(notBlank).join('\n');
2393
+ }
2394
+
1992
2395
  /**
1993
2396
  * Return a character diff for `err`.
1994
2397
  *
@@ -1998,19 +2401,28 @@ function pad(str, len) {
1998
2401
  */
1999
2402
 
2000
2403
  function errorDiff(err, type, escape) {
2001
- return diff['diff' + type](err.actual, err.expected).map(function(str){
2002
- if (escape) {
2003
- str.value = str.value
2004
- .replace(/\t/g, '<tab>')
2005
- .replace(/\r/g, '<CR>')
2006
- .replace(/\n/g, '<LF>\n');
2007
- }
2404
+ var actual = escape ? escapeInvisibles(err.actual) : err.actual;
2405
+ var expected = escape ? escapeInvisibles(err.expected) : err.expected;
2406
+ return diff['diff' + type](actual, expected).map(function(str){
2008
2407
  if (str.added) return colorLines('diff added', str.value);
2009
2408
  if (str.removed) return colorLines('diff removed', str.value);
2010
2409
  return str.value;
2011
2410
  }).join('');
2012
2411
  }
2013
2412
 
2413
+ /**
2414
+ * Returns a string with all invisible characters in plain text
2415
+ *
2416
+ * @param {String} line
2417
+ * @return {String}
2418
+ * @api private
2419
+ */
2420
+ function escapeInvisibles(line) {
2421
+ return line.replace(/\t/g, '<tab>')
2422
+ .replace(/\r/g, '<CR>')
2423
+ .replace(/\n/g, '<LF>\n');
2424
+ }
2425
+
2014
2426
  /**
2015
2427
  * Color lines for `str`, using the color `name`.
2016
2428
  *
@@ -2026,10 +2438,24 @@ function colorLines(name, str) {
2026
2438
  }).join('\n');
2027
2439
  }
2028
2440
 
2441
+ /**
2442
+ * Check that a / b have the same type.
2443
+ *
2444
+ * @param {Object} a
2445
+ * @param {Object} b
2446
+ * @return {Boolean}
2447
+ * @api private
2448
+ */
2449
+
2450
+ function sameType(a, b) {
2451
+ a = Object.prototype.toString.call(a);
2452
+ b = Object.prototype.toString.call(b);
2453
+ return a == b;
2454
+ }
2455
+
2029
2456
  }); // module: reporters/base.js
2030
2457
 
2031
2458
  require.register("reporters/doc.js", function(module, exports, require){
2032
-
2033
2459
  /**
2034
2460
  * Module dependencies.
2035
2461
  */
@@ -2084,12 +2510,18 @@ function Doc(runner) {
2084
2510
  var code = utils.escape(utils.clean(test.fn.toString()));
2085
2511
  console.log('%s <dd><pre><code>%s</code></pre></dd>', indent(), code);
2086
2512
  });
2513
+
2514
+ runner.on('fail', function(test, err){
2515
+ console.log('%s <dt class="error">%s</dt>', indent(), utils.escape(test.title));
2516
+ var code = utils.escape(utils.clean(test.fn.toString()));
2517
+ console.log('%s <dd class="error"><pre><code>%s</code></pre></dd>', indent(), code);
2518
+ console.log('%s <dd class="error">%s</dd>', indent(), utils.escape(err));
2519
+ });
2087
2520
  }
2088
2521
 
2089
2522
  }); // module: reporters/doc.js
2090
2523
 
2091
2524
  require.register("reporters/dot.js", function(module, exports, require){
2092
-
2093
2525
  /**
2094
2526
  * Module dependencies.
2095
2527
  */
@@ -2116,13 +2548,14 @@ function Dot(runner) {
2116
2548
  var self = this
2117
2549
  , stats = this.stats
2118
2550
  , width = Base.window.width * .75 | 0
2119
- , n = 0;
2551
+ , n = -1;
2120
2552
 
2121
2553
  runner.on('start', function(){
2122
- process.stdout.write('\n ');
2554
+ process.stdout.write('\n');
2123
2555
  });
2124
2556
 
2125
2557
  runner.on('pending', function(test){
2558
+ if (++n % width == 0) process.stdout.write('\n ');
2126
2559
  process.stdout.write(color('pending', Base.symbols.dot));
2127
2560
  });
2128
2561
 
@@ -2155,10 +2588,10 @@ F.prototype = Base.prototype;
2155
2588
  Dot.prototype = new F;
2156
2589
  Dot.prototype.constructor = Dot;
2157
2590
 
2591
+
2158
2592
  }); // module: reporters/dot.js
2159
2593
 
2160
2594
  require.register("reporters/html-cov.js", function(module, exports, require){
2161
-
2162
2595
  /**
2163
2596
  * Module dependencies.
2164
2597
  */
@@ -2209,10 +2642,10 @@ function coverageClass(n) {
2209
2642
  if (n >= 25) return 'low';
2210
2643
  return 'terrible';
2211
2644
  }
2645
+
2212
2646
  }); // module: reporters/html-cov.js
2213
2647
 
2214
2648
  require.register("reporters/html.js", function(module, exports, require){
2215
-
2216
2649
  /**
2217
2650
  * Module dependencies.
2218
2651
  */
@@ -2233,7 +2666,7 @@ var Date = global.Date
2233
2666
  , clearInterval = global.clearInterval;
2234
2667
 
2235
2668
  /**
2236
- * Expose `Doc`.
2669
+ * Expose `HTML`.
2237
2670
  */
2238
2671
 
2239
2672
  exports = module.exports = HTML;
@@ -2250,13 +2683,13 @@ var statsTemplate = '<ul id="mocha-stats">'
2250
2683
  + '</ul>';
2251
2684
 
2252
2685
  /**
2253
- * Initialize a new `Doc` reporter.
2686
+ * Initialize a new `HTML` reporter.
2254
2687
  *
2255
2688
  * @param {Runner} runner
2256
2689
  * @api public
2257
2690
  */
2258
2691
 
2259
- function HTML(runner, root) {
2692
+ function HTML(runner) {
2260
2693
  Base.call(this, runner);
2261
2694
 
2262
2695
  var self = this
@@ -2274,8 +2707,7 @@ function HTML(runner, root) {
2274
2707
  , stack = [report]
2275
2708
  , progress
2276
2709
  , ctx
2277
-
2278
- root = root || document.getElementById('mocha');
2710
+ , root = document.getElementById('mocha');
2279
2711
 
2280
2712
  if (canvas.getContext) {
2281
2713
  var ratio = window.devicePixelRatio || 1;
@@ -2315,7 +2747,7 @@ function HTML(runner, root) {
2315
2747
  if (suite.root) return;
2316
2748
 
2317
2749
  // suite
2318
- var url = '?grep=' + encodeURIComponent(suite.fullTitle());
2750
+ var url = self.suiteURL(suite);
2319
2751
  var el = fragment('<li class="suite"><h1><a href="%s">%s</a></h1></li>', url, escape(suite.title));
2320
2752
 
2321
2753
  // container
@@ -2334,8 +2766,6 @@ function HTML(runner, root) {
2334
2766
  });
2335
2767
 
2336
2768
  runner.on('test end', function(test){
2337
- window.scrollTo(0, document.body.scrollHeight);
2338
-
2339
2769
  // TODO: add to stats
2340
2770
  var percent = stats.tests / this.total * 100 | 0;
2341
2771
  if (progress) progress.update(percent).draw(ctx);
@@ -2348,11 +2778,12 @@ function HTML(runner, root) {
2348
2778
 
2349
2779
  // test
2350
2780
  if ('passed' == test.state) {
2351
- var el = fragment('<li class="test pass %e"><h2>%e<span class="duration">%ems</span> <a href="?grep=%e" class="replay">‣</a></h2></li>', test.speed, test.title, test.duration, encodeURIComponent(test.fullTitle()));
2781
+ var url = self.testURL(test);
2782
+ var el = fragment('<li class="test pass %e"><h2>%e<span class="duration">%ems</span> <a href="%s" class="replay">‣</a></h2></li>', test.speed, test.title, test.duration, url);
2352
2783
  } else if (test.pending) {
2353
2784
  var el = fragment('<li class="test pass pending"><h2>%e</h2></li>', test.title);
2354
2785
  } else {
2355
- var el = fragment('<li class="test fail"><h2>%e <a href="?grep=%e" class="replay">‣</a></h2></li>', test.title, encodeURIComponent(test.fullTitle()));
2786
+ var el = fragment('<li class="test fail"><h2>%e <a href="%e" class="replay">‣</a></h2></li>', test.title, self.testURL(test));
2356
2787
  var str = test.err.stack || test.err.toString();
2357
2788
 
2358
2789
  // FF / Opera do not add the message
@@ -2393,6 +2824,41 @@ function HTML(runner, root) {
2393
2824
  });
2394
2825
  }
2395
2826
 
2827
+ /**
2828
+ * Makes a URL, preserving querystring ("search") parameters.
2829
+ * @param {string} s
2830
+ * @returns {string} your new URL
2831
+ */
2832
+ var makeUrl = function makeUrl(s) {
2833
+ var search = window.location.search;
2834
+
2835
+ // Remove previous grep query parameter if present
2836
+ if (search) {
2837
+ search = search.replace(/[?&]grep=[^&\s]*/g, '').replace(/^&/, '?');
2838
+ }
2839
+
2840
+ return window.location.pathname + (search ? search + '&' : '?' ) + 'grep=' + encodeURIComponent(s);
2841
+ };
2842
+
2843
+ /**
2844
+ * Provide suite URL
2845
+ *
2846
+ * @param {Object} [suite]
2847
+ */
2848
+ HTML.prototype.suiteURL = function(suite){
2849
+ return makeUrl(suite.fullTitle());
2850
+ };
2851
+
2852
+ /**
2853
+ * Provide test URL
2854
+ *
2855
+ * @param {Object} [test]
2856
+ */
2857
+
2858
+ HTML.prototype.testURL = function(test){
2859
+ return makeUrl(test.fullTitle());
2860
+ };
2861
+
2396
2862
  /**
2397
2863
  * Display error `msg`.
2398
2864
  */
@@ -2471,7 +2937,6 @@ function on(el, event, fn) {
2471
2937
  }); // module: reporters/html.js
2472
2938
 
2473
2939
  require.register("reporters/index.js", function(module, exports, require){
2474
-
2475
2940
  exports.Base = require('./base');
2476
2941
  exports.Dot = require('./dot');
2477
2942
  exports.Doc = require('./doc');
@@ -2489,12 +2954,10 @@ exports.Landing = require('./landing');
2489
2954
  exports.JSONCov = require('./json-cov');
2490
2955
  exports.HTMLCov = require('./html-cov');
2491
2956
  exports.JSONStream = require('./json-stream');
2492
- exports.Teamcity = require('./teamcity');
2493
2957
 
2494
2958
  }); // module: reporters/index.js
2495
2959
 
2496
2960
  require.register("reporters/json-cov.js", function(module, exports, require){
2497
-
2498
2961
  /**
2499
2962
  * Module dependencies.
2500
2963
  */
@@ -2585,7 +3048,7 @@ function map(cov) {
2585
3048
  }
2586
3049
 
2587
3050
  return ret;
2588
- };
3051
+ }
2589
3052
 
2590
3053
  /**
2591
3054
  * Map jscoverage data for a single source file
@@ -2651,7 +3114,6 @@ function clean(test) {
2651
3114
  }); // module: reporters/json-cov.js
2652
3115
 
2653
3116
  require.register("reporters/json-stream.js", function(module, exports, require){
2654
-
2655
3117
  /**
2656
3118
  * Module dependencies.
2657
3119
  */
@@ -2688,7 +3150,9 @@ function List(runner) {
2688
3150
  });
2689
3151
 
2690
3152
  runner.on('fail', function(test, err){
2691
- console.log(JSON.stringify(['fail', clean(test)]));
3153
+ test = clean(test);
3154
+ test.err = err.message;
3155
+ console.log(JSON.stringify(['fail', test]));
2692
3156
  });
2693
3157
 
2694
3158
  runner.on('end', function(){
@@ -2712,10 +3176,10 @@ function clean(test) {
2712
3176
  , duration: test.duration
2713
3177
  }
2714
3178
  }
3179
+
2715
3180
  }); // module: reporters/json-stream.js
2716
3181
 
2717
3182
  require.register("reporters/json.js", function(module, exports, require){
2718
-
2719
3183
  /**
2720
3184
  * Module dependencies.
2721
3185
  */
@@ -2742,6 +3206,7 @@ function JSONReporter(runner) {
2742
3206
  Base.call(this, runner);
2743
3207
 
2744
3208
  var tests = []
3209
+ , pending = []
2745
3210
  , failures = []
2746
3211
  , passes = [];
2747
3212
 
@@ -2757,14 +3222,21 @@ function JSONReporter(runner) {
2757
3222
  failures.push(test);
2758
3223
  });
2759
3224
 
3225
+ runner.on('pending', function(test){
3226
+ pending.push(test);
3227
+ });
3228
+
2760
3229
  runner.on('end', function(){
2761
3230
  var obj = {
2762
- stats: self.stats
2763
- , tests: tests.map(clean)
2764
- , failures: failures.map(clean)
2765
- , passes: passes.map(clean)
3231
+ stats: self.stats,
3232
+ tests: tests.map(clean),
3233
+ pending: pending.map(clean),
3234
+ failures: failures.map(clean),
3235
+ passes: passes.map(clean)
2766
3236
  };
2767
3237
 
3238
+ runner.testResults = obj;
3239
+
2768
3240
  process.stdout.write(JSON.stringify(obj, null, 2));
2769
3241
  });
2770
3242
  }
@@ -2780,15 +3252,30 @@ function JSONReporter(runner) {
2780
3252
 
2781
3253
  function clean(test) {
2782
3254
  return {
2783
- title: test.title
2784
- , fullTitle: test.fullTitle()
2785
- , duration: test.duration
3255
+ title: test.title,
3256
+ fullTitle: test.fullTitle(),
3257
+ duration: test.duration,
3258
+ err: errorJSON(test.err || {})
2786
3259
  }
2787
3260
  }
3261
+
3262
+ /**
3263
+ * Transform `error` into a JSON object.
3264
+ * @param {Error} err
3265
+ * @return {Object}
3266
+ */
3267
+
3268
+ function errorJSON(err) {
3269
+ var res = {};
3270
+ Object.getOwnPropertyNames(err).forEach(function(key) {
3271
+ res[key] = err[key];
3272
+ }, err);
3273
+ return res;
3274
+ }
3275
+
2788
3276
  }); // module: reporters/json.js
2789
3277
 
2790
3278
  require.register("reporters/landing.js", function(module, exports, require){
2791
-
2792
3279
  /**
2793
3280
  * Module dependencies.
2794
3281
  */
@@ -2846,7 +3333,7 @@ function Landing(runner) {
2846
3333
  }
2847
3334
 
2848
3335
  runner.on('start', function(){
2849
- stream.write('\n ');
3336
+ stream.write('\n\n\n ');
2850
3337
  cursor.hide();
2851
3338
  });
2852
3339
 
@@ -2863,7 +3350,7 @@ function Landing(runner) {
2863
3350
  }
2864
3351
 
2865
3352
  // render landing strip
2866
- stream.write('\u001b[4F\n\n');
3353
+ stream.write('\u001b['+(width+1)+'D\u001b[2A');
2867
3354
  stream.write(runway());
2868
3355
  stream.write('\n ');
2869
3356
  stream.write(color('runway', Array(col).join('⋅')));
@@ -2889,10 +3376,10 @@ F.prototype = Base.prototype;
2889
3376
  Landing.prototype = new F;
2890
3377
  Landing.prototype.constructor = Landing;
2891
3378
 
3379
+
2892
3380
  }); // module: reporters/landing.js
2893
3381
 
2894
3382
  require.register("reporters/list.js", function(module, exports, require){
2895
-
2896
3383
  /**
2897
3384
  * Module dependencies.
2898
3385
  */
@@ -2971,6 +3458,12 @@ require.register("reporters/markdown.js", function(module, exports, require){
2971
3458
  var Base = require('./base')
2972
3459
  , utils = require('../utils');
2973
3460
 
3461
+ /**
3462
+ * Constants
3463
+ */
3464
+
3465
+ var SUITE_PREFIX = '$';
3466
+
2974
3467
  /**
2975
3468
  * Expose `Markdown`.
2976
3469
  */
@@ -3001,8 +3494,9 @@ function Markdown(runner) {
3001
3494
  }
3002
3495
 
3003
3496
  function mapTOC(suite, obj) {
3004
- var ret = obj;
3005
- obj = obj[suite.title] = obj[suite.title] || { suite: suite };
3497
+ var ret = obj,
3498
+ key = SUITE_PREFIX + suite.title;
3499
+ obj = obj[key] = obj[key] || { suite: suite };
3006
3500
  suite.suites.forEach(function(suite){
3007
3501
  mapTOC(suite, obj);
3008
3502
  });
@@ -3015,11 +3509,13 @@ function Markdown(runner) {
3015
3509
  var link;
3016
3510
  for (var key in obj) {
3017
3511
  if ('suite' == key) continue;
3018
- if (key) link = ' - [' + key + '](#' + utils.slug(obj[key].suite.fullTitle()) + ')\n';
3019
- if (key) buf += Array(level).join(' ') + link;
3512
+ if (key !== SUITE_PREFIX) {
3513
+ link = ' - [' + key.substring(1) + ']';
3514
+ link += '(#' + utils.slug(obj[key].suite.fullTitle()) + ')\n';
3515
+ buf += Array(level).join(' ') + link;
3516
+ }
3020
3517
  buf += stringifyTOC(obj[key], level);
3021
3518
  }
3022
- --level;
3023
3519
  return buf;
3024
3520
  }
3025
3521
 
@@ -3055,10 +3551,10 @@ function Markdown(runner) {
3055
3551
  process.stdout.write(buf);
3056
3552
  });
3057
3553
  }
3554
+
3058
3555
  }); // module: reporters/markdown.js
3059
3556
 
3060
3557
  require.register("reporters/min.js", function(module, exports, require){
3061
-
3062
3558
  /**
3063
3559
  * Module dependencies.
3064
3560
  */
@@ -3100,16 +3596,15 @@ F.prototype = Base.prototype;
3100
3596
  Min.prototype = new F;
3101
3597
  Min.prototype.constructor = Min;
3102
3598
 
3599
+
3103
3600
  }); // module: reporters/min.js
3104
3601
 
3105
3602
  require.register("reporters/nyan.js", function(module, exports, require){
3106
-
3107
3603
  /**
3108
3604
  * Module dependencies.
3109
3605
  */
3110
3606
 
3111
- var Base = require('./base')
3112
- , color = Base.color;
3607
+ var Base = require('./base');
3113
3608
 
3114
3609
  /**
3115
3610
  * Expose `Dot`.
@@ -3126,7 +3621,6 @@ exports = module.exports = NyanCat;
3126
3621
 
3127
3622
  function NyanCat(runner) {
3128
3623
  Base.call(this, runner);
3129
-
3130
3624
  var self = this
3131
3625
  , stats = this.stats
3132
3626
  , width = Base.window.width * .75 | 0
@@ -3142,19 +3636,19 @@ function NyanCat(runner) {
3142
3636
 
3143
3637
  runner.on('start', function(){
3144
3638
  Base.cursor.hide();
3145
- self.draw('start');
3639
+ self.draw();
3146
3640
  });
3147
3641
 
3148
3642
  runner.on('pending', function(test){
3149
- self.draw('pending');
3643
+ self.draw();
3150
3644
  });
3151
3645
 
3152
3646
  runner.on('pass', function(test){
3153
- self.draw('pass');
3647
+ self.draw();
3154
3648
  });
3155
3649
 
3156
3650
  runner.on('fail', function(test, err){
3157
- self.draw('fail');
3651
+ self.draw();
3158
3652
  });
3159
3653
 
3160
3654
  runner.on('end', function(){
@@ -3165,17 +3659,16 @@ function NyanCat(runner) {
3165
3659
  }
3166
3660
 
3167
3661
  /**
3168
- * Draw the nyan cat with runner `status`.
3662
+ * Draw the nyan cat
3169
3663
  *
3170
- * @param {String} status
3171
3664
  * @api private
3172
3665
  */
3173
3666
 
3174
- NyanCat.prototype.draw = function(status){
3667
+ NyanCat.prototype.draw = function(){
3175
3668
  this.appendRainbow();
3176
3669
  this.drawScoreboard();
3177
3670
  this.drawRainbow();
3178
- this.drawNyanCat(status);
3671
+ this.drawNyanCat();
3179
3672
  this.tick = !this.tick;
3180
3673
  };
3181
3674
 
@@ -3188,17 +3681,16 @@ NyanCat.prototype.draw = function(status){
3188
3681
 
3189
3682
  NyanCat.prototype.drawScoreboard = function(){
3190
3683
  var stats = this.stats;
3191
- var colors = Base.colors;
3192
3684
 
3193
- function draw(color, n) {
3685
+ function draw(type, n) {
3194
3686
  write(' ');
3195
- write('\u001b[' + color + 'm' + n + '\u001b[0m');
3687
+ write(Base.color(type, n));
3196
3688
  write('\n');
3197
3689
  }
3198
3690
 
3199
- draw(colors.green, stats.passes);
3200
- draw(colors.fail, stats.failures);
3201
- draw(colors.pending, stats.pending);
3691
+ draw('green', stats.passes);
3692
+ draw('fail', stats.failures);
3693
+ draw('pending', stats.pending);
3202
3694
  write('\n');
3203
3695
 
3204
3696
  this.cursorUp(this.numberOfLines);
@@ -3240,65 +3732,69 @@ NyanCat.prototype.drawRainbow = function(){
3240
3732
  };
3241
3733
 
3242
3734
  /**
3243
- * Draw the nyan cat with `status`.
3735
+ * Draw the nyan cat
3244
3736
  *
3245
- * @param {String} status
3246
3737
  * @api private
3247
3738
  */
3248
3739
 
3249
- NyanCat.prototype.drawNyanCat = function(status) {
3740
+ NyanCat.prototype.drawNyanCat = function() {
3250
3741
  var self = this;
3251
3742
  var startWidth = this.scoreboardWidth + this.trajectories[0].length;
3743
+ var dist = '\u001b[' + startWidth + 'C';
3744
+ var padding = '';
3252
3745
 
3253
- [0, 1, 2, 3].forEach(function(index) {
3254
- write('\u001b[' + startWidth + 'C');
3746
+ write(dist);
3747
+ write('_,------,');
3748
+ write('\n');
3255
3749
 
3256
- switch (index) {
3257
- case 0:
3258
- write('_,------,');
3259
- write('\n');
3260
- break;
3261
- case 1:
3262
- var padding = self.tick ? ' ' : ' ';
3263
- write('_|' + padding + '/\\_/\\ ');
3264
- write('\n');
3265
- break;
3266
- case 2:
3267
- var padding = self.tick ? '_' : '__';
3268
- var tail = self.tick ? '~' : '^';
3269
- var face;
3270
- switch (status) {
3271
- case 'pass':
3272
- face = '( ^ .^)';
3273
- break;
3274
- case 'fail':
3275
- face = '( o .o)';
3276
- break;
3277
- default:
3278
- face = '( - .-)';
3279
- }
3280
- write(tail + '|' + padding + face + ' ');
3281
- write('\n');
3282
- break;
3283
- case 3:
3284
- var padding = self.tick ? ' ' : ' ';
3285
- write(padding + '"" "" ');
3286
- write('\n');
3287
- break;
3288
- }
3289
- });
3750
+ write(dist);
3751
+ padding = self.tick ? ' ' : ' ';
3752
+ write('_|' + padding + '/\\_/\\ ');
3753
+ write('\n');
3754
+
3755
+ write(dist);
3756
+ padding = self.tick ? '_' : '__';
3757
+ var tail = self.tick ? '~' : '^';
3758
+ var face;
3759
+ write(tail + '|' + padding + this.face() + ' ');
3760
+ write('\n');
3761
+
3762
+ write(dist);
3763
+ padding = self.tick ? ' ' : ' ';
3764
+ write(padding + '"" "" ');
3765
+ write('\n');
3290
3766
 
3291
3767
  this.cursorUp(this.numberOfLines);
3292
3768
  };
3293
3769
 
3294
3770
  /**
3295
- * Move cursor up `n`.
3771
+ * Draw nyan cat face.
3296
3772
  *
3297
- * @param {Number} n
3773
+ * @return {String}
3298
3774
  * @api private
3299
3775
  */
3300
3776
 
3301
- NyanCat.prototype.cursorUp = function(n) {
3777
+ NyanCat.prototype.face = function() {
3778
+ var stats = this.stats;
3779
+ if (stats.failures) {
3780
+ return '( x .x)';
3781
+ } else if (stats.pending) {
3782
+ return '( o .o)';
3783
+ } else if(stats.passes) {
3784
+ return '( ^ .^)';
3785
+ } else {
3786
+ return '( - .-)';
3787
+ }
3788
+ };
3789
+
3790
+ /**
3791
+ * Move cursor up `n`.
3792
+ *
3793
+ * @param {Number} n
3794
+ * @api private
3795
+ */
3796
+
3797
+ NyanCat.prototype.cursorUp = function(n) {
3302
3798
  write('\u001b[' + n + 'A');
3303
3799
  };
3304
3800
 
@@ -3344,6 +3840,8 @@ NyanCat.prototype.generateColors = function(){
3344
3840
  */
3345
3841
 
3346
3842
  NyanCat.prototype.rainbowify = function(str){
3843
+ if (!Base.useColors)
3844
+ return str;
3347
3845
  var color = this.rainbowColors[this.colorIndex % this.rainbowColors.length];
3348
3846
  this.colorIndex += 1;
3349
3847
  return '\u001b[38;5;' + color + 'm' + str + '\u001b[0m';
@@ -3370,7 +3868,6 @@ NyanCat.prototype.constructor = NyanCat;
3370
3868
  }); // module: reporters/nyan.js
3371
3869
 
3372
3870
  require.register("reporters/progress.js", function(module, exports, require){
3373
-
3374
3871
  /**
3375
3872
  * Module dependencies.
3376
3873
  */
@@ -3408,7 +3905,8 @@ function Progress(runner, options) {
3408
3905
  , width = Base.window.width * .50 | 0
3409
3906
  , total = runner.total
3410
3907
  , complete = 0
3411
- , max = Math.max;
3908
+ , max = Math.max
3909
+ , lastN = -1;
3412
3910
 
3413
3911
  // default chars
3414
3912
  options.open = options.open || '[';
@@ -3431,6 +3929,12 @@ function Progress(runner, options) {
3431
3929
  , n = width * percent | 0
3432
3930
  , i = width - n;
3433
3931
 
3932
+ if (lastN === n && !options.verbose) {
3933
+ // Don't re-render the line if it hasn't changed
3934
+ return;
3935
+ }
3936
+ lastN = n;
3937
+
3434
3938
  cursor.CR();
3435
3939
  process.stdout.write('\u001b[J');
3436
3940
  process.stdout.write(color('progress', ' ' + options.open));
@@ -3464,7 +3968,6 @@ Progress.prototype.constructor = Progress;
3464
3968
  }); // module: reporters/progress.js
3465
3969
 
3466
3970
  require.register("reporters/spec.js", function(module, exports, require){
3467
-
3468
3971
  /**
3469
3972
  * Module dependencies.
3470
3973
  */
@@ -3512,10 +4015,6 @@ function Spec(runner) {
3512
4015
  if (1 == indents) console.log();
3513
4016
  });
3514
4017
 
3515
- runner.on('test', function(test){
3516
- process.stdout.write(indent() + color('pass', ' ◦ ' + test.title + ': '));
3517
- });
3518
-
3519
4018
  runner.on('pending', function(test){
3520
4019
  var fmt = indent() + color('pending', ' - %s');
3521
4020
  console.log(fmt, test.title);
@@ -3525,14 +4024,14 @@ function Spec(runner) {
3525
4024
  if ('fast' == test.speed) {
3526
4025
  var fmt = indent()
3527
4026
  + color('checkmark', ' ' + Base.symbols.ok)
3528
- + color('pass', ' %s ');
4027
+ + color('pass', ' %s');
3529
4028
  cursor.CR();
3530
4029
  console.log(fmt, test.title);
3531
4030
  } else {
3532
4031
  var fmt = indent()
3533
4032
  + color('checkmark', ' ' + Base.symbols.ok)
3534
- + color('pass', ' %s ')
3535
- + color(test.speed, '(%dms)');
4033
+ + color('pass', ' %s')
4034
+ + color(test.speed, ' (%dms)');
3536
4035
  cursor.CR();
3537
4036
  console.log(fmt, test.title, test.duration);
3538
4037
  }
@@ -3559,7 +4058,6 @@ Spec.prototype.constructor = Spec;
3559
4058
  }); // module: reporters/spec.js
3560
4059
 
3561
4060
  require.register("reporters/tap.js", function(module, exports, require){
3562
-
3563
4061
  /**
3564
4062
  * Module dependencies.
3565
4063
  */
@@ -3635,83 +4133,14 @@ function title(test) {
3635
4133
 
3636
4134
  }); // module: reporters/tap.js
3637
4135
 
3638
- require.register("reporters/teamcity.js", function(module, exports, require){
3639
-
3640
- /**
3641
- * Module dependencies.
3642
- */
3643
-
3644
- var Base = require('./base');
3645
-
3646
- /**
3647
- * Expose `Teamcity`.
3648
- */
3649
-
3650
- exports = module.exports = Teamcity;
3651
-
3652
- /**
3653
- * Initialize a new `Teamcity` reporter.
3654
- *
3655
- * @param {Runner} runner
3656
- * @api public
3657
- */
3658
-
3659
- function Teamcity(runner) {
3660
- Base.call(this, runner);
3661
- var stats = this.stats;
3662
-
3663
- runner.on('start', function() {
3664
- console.log("##teamcity[testSuiteStarted name='mocha.suite']");
3665
- });
3666
-
3667
- runner.on('test', function(test) {
3668
- console.log("##teamcity[testStarted name='" + escape(test.fullTitle()) + "']");
3669
- });
3670
-
3671
- runner.on('fail', function(test, err) {
3672
- console.log("##teamcity[testFailed name='" + escape(test.fullTitle()) + "' message='" + escape(err.message) + "']");
3673
- });
3674
-
3675
- runner.on('pending', function(test) {
3676
- console.log("##teamcity[testIgnored name='" + escape(test.fullTitle()) + "' message='pending']");
3677
- });
3678
-
3679
- runner.on('test end', function(test) {
3680
- console.log("##teamcity[testFinished name='" + escape(test.fullTitle()) + "' duration='" + test.duration + "']");
3681
- });
3682
-
3683
- runner.on('end', function() {
3684
- console.log("##teamcity[testSuiteFinished name='mocha.suite' duration='" + stats.duration + "']");
3685
- });
3686
- }
3687
-
3688
- /**
3689
- * Escape the given `str`.
3690
- */
3691
-
3692
- function escape(str) {
3693
- return str
3694
- .replace(/\|/g, "||")
3695
- .replace(/\n/g, "|n")
3696
- .replace(/\r/g, "|r")
3697
- .replace(/\[/g, "|[")
3698
- .replace(/\]/g, "|]")
3699
- .replace(/\u0085/g, "|x")
3700
- .replace(/\u2028/g, "|l")
3701
- .replace(/\u2029/g, "|p")
3702
- .replace(/'/g, "|'");
3703
- }
3704
-
3705
- }); // module: reporters/teamcity.js
3706
-
3707
4136
  require.register("reporters/xunit.js", function(module, exports, require){
3708
-
3709
4137
  /**
3710
4138
  * Module dependencies.
3711
4139
  */
3712
4140
 
3713
4141
  var Base = require('./base')
3714
4142
  , utils = require('../utils')
4143
+ , fs = require('browser/fs')
3715
4144
  , escape = utils.escape;
3716
4145
 
3717
4146
  /**
@@ -3737,12 +4166,23 @@ exports = module.exports = XUnit;
3737
4166
  * @api public
3738
4167
  */
3739
4168
 
3740
- function XUnit(runner) {
4169
+ function XUnit(runner, options) {
3741
4170
  Base.call(this, runner);
3742
4171
  var stats = this.stats
3743
4172
  , tests = []
3744
4173
  , self = this;
3745
4174
 
4175
+ if (options.reporterOptions && options.reporterOptions.output) {
4176
+ if (! fs.createWriteStream) {
4177
+ throw new Error('file output not supported in browser');
4178
+ }
4179
+ self.fileStream = fs.createWriteStream(options.reporterOptions.output);
4180
+ }
4181
+
4182
+ runner.on('pending', function(test){
4183
+ tests.push(test);
4184
+ });
4185
+
3746
4186
  runner.on('pass', function(test){
3747
4187
  tests.push(test);
3748
4188
  });
@@ -3752,21 +4192,34 @@ function XUnit(runner) {
3752
4192
  });
3753
4193
 
3754
4194
  runner.on('end', function(){
3755
- console.log(tag('testsuite', {
4195
+ self.write(tag('testsuite', {
3756
4196
  name: 'Mocha Tests'
3757
4197
  , tests: stats.tests
3758
4198
  , failures: stats.failures
3759
4199
  , errors: stats.failures
3760
- , skip: stats.tests - stats.failures - stats.passes
4200
+ , skipped: stats.tests - stats.failures - stats.passes
3761
4201
  , timestamp: (new Date).toUTCString()
3762
- , time: stats.duration / 1000
4202
+ , time: (stats.duration / 1000) || 0
3763
4203
  }, false));
3764
4204
 
3765
- tests.forEach(test);
3766
- console.log('</testsuite>');
4205
+ tests.forEach(function(t) { self.test(t); });
4206
+ self.write('</testsuite>');
3767
4207
  });
3768
4208
  }
3769
4209
 
4210
+ /**
4211
+ * Override done to close the stream (if it's a file).
4212
+ */
4213
+ XUnit.prototype.done = function(failures, fn) {
4214
+ if (this.fileStream) {
4215
+ this.fileStream.end(function() {
4216
+ fn(failures);
4217
+ });
4218
+ } else {
4219
+ fn(failures);
4220
+ }
4221
+ };
4222
+
3770
4223
  /**
3771
4224
  * Inherit from `Base.prototype`.
3772
4225
  */
@@ -3777,27 +4230,37 @@ XUnit.prototype = new F;
3777
4230
  XUnit.prototype.constructor = XUnit;
3778
4231
 
3779
4232
 
4233
+ /**
4234
+ * Write out the given line
4235
+ */
4236
+ XUnit.prototype.write = function(line) {
4237
+ if (this.fileStream) {
4238
+ this.fileStream.write(line + '\n');
4239
+ } else {
4240
+ console.log(line);
4241
+ }
4242
+ };
4243
+
3780
4244
  /**
3781
4245
  * Output tag for the given `test.`
3782
4246
  */
3783
4247
 
3784
- function test(test) {
4248
+ XUnit.prototype.test = function(test, ostream) {
3785
4249
  var attrs = {
3786
4250
  classname: test.parent.fullTitle()
3787
4251
  , name: test.title
3788
- , time: test.duration / 1000
4252
+ , time: (test.duration / 1000) || 0
3789
4253
  };
3790
4254
 
3791
4255
  if ('failed' == test.state) {
3792
4256
  var err = test.err;
3793
- attrs.message = escape(err.message);
3794
- console.log(tag('testcase', attrs, false, tag('failure', attrs, false, cdata(err.stack))));
4257
+ this.write(tag('testcase', attrs, false, tag('failure', {}, false, cdata(escape(err.message) + "\n" + err.stack))));
3795
4258
  } else if (test.pending) {
3796
- console.log(tag('testcase', attrs, false, tag('skipped', {}, true)));
4259
+ this.write(tag('testcase', attrs, false, tag('skipped', {}, true)));
3797
4260
  } else {
3798
- console.log(tag('testcase', attrs, true) );
4261
+ this.write(tag('testcase', attrs, true) );
3799
4262
  }
3800
- }
4263
+ };
3801
4264
 
3802
4265
  /**
3803
4266
  * HTML tag helper.
@@ -3828,14 +4291,15 @@ function cdata(str) {
3828
4291
  }); // module: reporters/xunit.js
3829
4292
 
3830
4293
  require.register("runnable.js", function(module, exports, require){
3831
-
3832
4294
  /**
3833
4295
  * Module dependencies.
3834
4296
  */
3835
4297
 
3836
4298
  var EventEmitter = require('browser/events').EventEmitter
3837
4299
  , debug = require('browser/debug')('mocha:runnable')
3838
- , milliseconds = require('./ms');
4300
+ , Pending = require('./pending')
4301
+ , milliseconds = require('./ms')
4302
+ , utils = require('./utils');
3839
4303
 
3840
4304
  /**
3841
4305
  * Save timer references to avoid Sinon interfering (see GH-237).
@@ -3874,7 +4338,9 @@ function Runnable(title, fn) {
3874
4338
  this.sync = ! this.async;
3875
4339
  this._timeout = 2000;
3876
4340
  this._slow = 75;
4341
+ this._enableTimeouts = true;
3877
4342
  this.timedOut = false;
4343
+ this._trace = new Error('done() called multiple times')
3878
4344
  }
3879
4345
 
3880
4346
  /**
@@ -3897,6 +4363,7 @@ Runnable.prototype.constructor = Runnable;
3897
4363
 
3898
4364
  Runnable.prototype.timeout = function(ms){
3899
4365
  if (0 == arguments.length) return this._timeout;
4366
+ if (ms === 0) this._enableTimeouts = false;
3900
4367
  if ('string' == typeof ms) ms = milliseconds(ms);
3901
4368
  debug('timeout %d', ms);
3902
4369
  this._timeout = ms;
@@ -3920,6 +4387,31 @@ Runnable.prototype.slow = function(ms){
3920
4387
  return this;
3921
4388
  };
3922
4389
 
4390
+ /**
4391
+ * Set and & get timeout `enabled`.
4392
+ *
4393
+ * @param {Boolean} enabled
4394
+ * @return {Runnable|Boolean} enabled or self
4395
+ * @api private
4396
+ */
4397
+
4398
+ Runnable.prototype.enableTimeouts = function(enabled){
4399
+ if (arguments.length === 0) return this._enableTimeouts;
4400
+ debug('enableTimeouts %s', enabled);
4401
+ this._enableTimeouts = enabled;
4402
+ return this;
4403
+ };
4404
+
4405
+ /**
4406
+ * Halt and mark as pending.
4407
+ *
4408
+ * @api private
4409
+ */
4410
+
4411
+ Runnable.prototype.skip = function(){
4412
+ throw new Pending();
4413
+ };
4414
+
3923
4415
  /**
3924
4416
  * Return the full title generated by recursively
3925
4417
  * concatenating the parent's full title.
@@ -3965,16 +4457,26 @@ Runnable.prototype.inspect = function(){
3965
4457
  */
3966
4458
 
3967
4459
  Runnable.prototype.resetTimeout = function(){
3968
- var self = this
3969
- , ms = this.timeout();
4460
+ var self = this;
4461
+ var ms = this.timeout() || 1e9;
3970
4462
 
4463
+ if (!this._enableTimeouts) return;
3971
4464
  this.clearTimeout();
3972
- if (ms) {
3973
- this.timer = setTimeout(function(){
3974
- self.callback(new Error('timeout of ' + ms + 'ms exceeded'));
3975
- self.timedOut = true;
3976
- }, ms);
3977
- }
4465
+ this.timer = setTimeout(function(){
4466
+ if (!self._enableTimeouts) return;
4467
+ self.callback(new Error('timeout of ' + ms + 'ms exceeded. Ensure the done() callback is being called in this test.'));
4468
+ self.timedOut = true;
4469
+ }, ms);
4470
+ };
4471
+
4472
+ /**
4473
+ * Whitelist these globals for this test run
4474
+ *
4475
+ * @api private
4476
+ */
4477
+ Runnable.prototype.globals = function(arr){
4478
+ var self = this;
4479
+ this._allowedGlobals = arr;
3978
4480
  };
3979
4481
 
3980
4482
  /**
@@ -3986,54 +4488,58 @@ Runnable.prototype.resetTimeout = function(){
3986
4488
 
3987
4489
  Runnable.prototype.run = function(fn){
3988
4490
  var self = this
3989
- , ms = this.timeout()
3990
4491
  , start = new Date
3991
4492
  , ctx = this.ctx
3992
4493
  , finished
3993
4494
  , emitted;
3994
4495
 
3995
- if (ctx) ctx.runnable(this);
3996
-
3997
- // timeout
3998
- if (this.async) {
3999
- if (ms) {
4000
- this.timer = setTimeout(function(){
4001
- done(new Error('timeout of ' + ms + 'ms exceeded'));
4002
- self.timedOut = true;
4003
- }, ms);
4004
- }
4005
- }
4496
+ // Some times the ctx exists but it is not runnable
4497
+ if (ctx && ctx.runnable) ctx.runnable(this);
4006
4498
 
4007
4499
  // called multiple times
4008
4500
  function multiple(err) {
4009
4501
  if (emitted) return;
4010
4502
  emitted = true;
4011
- self.emit('error', err || new Error('done() called multiple times'));
4503
+ self.emit('error', err || new Error('done() called multiple times; stacktrace may be inaccurate'));
4012
4504
  }
4013
4505
 
4014
4506
  // finished
4015
4507
  function done(err) {
4508
+ var ms = self.timeout();
4016
4509
  if (self.timedOut) return;
4017
- if (finished) return multiple(err);
4510
+ if (finished) return multiple(err || self._trace);
4511
+
4512
+ // Discard the resolution if this test has already failed asynchronously
4513
+ if (self.state) return;
4514
+
4018
4515
  self.clearTimeout();
4019
4516
  self.duration = new Date - start;
4020
4517
  finished = true;
4518
+ if (!err && self.duration > ms && self._enableTimeouts) err = new Error('timeout of ' + ms + 'ms exceeded. Ensure the done() callback is being called in this test.');
4021
4519
  fn(err);
4022
4520
  }
4023
4521
 
4024
4522
  // for .resetTimeout()
4025
4523
  this.callback = done;
4026
4524
 
4027
- // async
4525
+ // explicit async with `done` argument
4028
4526
  if (this.async) {
4527
+ this.resetTimeout();
4528
+
4029
4529
  try {
4030
4530
  this.fn.call(ctx, function(err){
4031
4531
  if (err instanceof Error || toString.call(err) === "[object Error]") return done(err);
4032
- if (null != err) return done(new Error('done() invoked with non-Error: ' + err));
4532
+ if (null != err) {
4533
+ if (Object.prototype.toString.call(err) === '[object Object]') {
4534
+ return done(new Error('done() invoked with non-Error: ' + JSON.stringify(err)));
4535
+ } else {
4536
+ return done(new Error('done() invoked with non-Error: ' + err));
4537
+ }
4538
+ }
4033
4539
  done();
4034
4540
  });
4035
4541
  } catch (err) {
4036
- done(err);
4542
+ done(utils.getError(err));
4037
4543
  }
4038
4544
  return;
4039
4545
  }
@@ -4042,31 +4548,51 @@ Runnable.prototype.run = function(fn){
4042
4548
  return done(new Error('--async-only option in use without declaring `done()`'));
4043
4549
  }
4044
4550
 
4045
- // sync
4551
+ // sync or promise-returning
4046
4552
  try {
4047
- if (!this.pending) this.fn.call(ctx);
4048
- this.duration = new Date - start;
4049
- fn();
4553
+ if (this.pending) {
4554
+ done();
4555
+ } else {
4556
+ callFn(this.fn);
4557
+ }
4050
4558
  } catch (err) {
4051
- fn(err);
4559
+ done(utils.getError(err));
4560
+ }
4561
+
4562
+ function callFn(fn) {
4563
+ var result = fn.call(ctx);
4564
+ if (result && typeof result.then === 'function') {
4565
+ self.resetTimeout();
4566
+ result
4567
+ .then(function() {
4568
+ done()
4569
+ },
4570
+ function(reason) {
4571
+ done(reason || new Error('Promise rejected with no or falsy reason'))
4572
+ });
4573
+ } else {
4574
+ done();
4575
+ }
4052
4576
  }
4053
4577
  };
4054
4578
 
4055
4579
  }); // module: runnable.js
4056
4580
 
4057
4581
  require.register("runner.js", function(module, exports, require){
4058
-
4059
4582
  /**
4060
4583
  * Module dependencies.
4061
4584
  */
4062
4585
 
4063
4586
  var EventEmitter = require('browser/events').EventEmitter
4064
4587
  , debug = require('browser/debug')('mocha:runner')
4588
+ , Pending = require('./pending')
4065
4589
  , Test = require('./test')
4066
4590
  , utils = require('./utils')
4067
4591
  , filter = utils.filter
4068
4592
  , keys = utils.keys
4069
- , noop = function(){};
4593
+ , type = utils.type
4594
+ , stringify = utils.stringify
4595
+ , stackFilter = utils.stackTraceFilter();
4070
4596
 
4071
4597
  /**
4072
4598
  * Non-enumerable globals.
@@ -4078,7 +4604,9 @@ var globals = [
4078
4604
  'setInterval',
4079
4605
  'clearInterval',
4080
4606
  'XMLHttpRequest',
4081
- 'Date'
4607
+ 'Date',
4608
+ 'setImmediate',
4609
+ 'clearImmediate'
4082
4610
  ];
4083
4611
 
4084
4612
  /**
@@ -4102,22 +4630,37 @@ module.exports = Runner;
4102
4630
  * - `hook end` (hook) hook complete
4103
4631
  * - `pass` (test) test passed
4104
4632
  * - `fail` (test, err) test failed
4633
+ * - `pending` (test) test pending
4105
4634
  *
4635
+ * @param {Suite} suite Root suite
4636
+ * @param {boolean} [delay] Whether or not to delay execution of root suite
4637
+ * until ready.
4106
4638
  * @api public
4107
4639
  */
4108
4640
 
4109
- function Runner(suite) {
4641
+ function Runner(suite, delay) {
4110
4642
  var self = this;
4111
4643
  this._globals = [];
4644
+ this._abort = false;
4645
+ this._delay = delay;
4112
4646
  this.suite = suite;
4113
4647
  this.total = suite.total();
4114
4648
  this.failures = 0;
4115
4649
  this.on('test end', function(test){ self.checkGlobals(test); });
4116
4650
  this.on('hook end', function(hook){ self.checkGlobals(hook); });
4117
4651
  this.grep(/.*/);
4118
- this.globals(this.globalProps().concat(['errno']));
4652
+ this.globals(this.globalProps().concat(extraGlobals()));
4119
4653
  }
4120
4654
 
4655
+ /**
4656
+ * Wrapper for setImmediate, process.nextTick, or browser polyfill.
4657
+ *
4658
+ * @param {Function} fn
4659
+ * @api private
4660
+ */
4661
+
4662
+ Runner.immediately = global.setImmediate || process.nextTick;
4663
+
4121
4664
  /**
4122
4665
  * Inherit from `EventEmitter.prototype`.
4123
4666
  */
@@ -4198,9 +4741,7 @@ Runner.prototype.globalProps = function() {
4198
4741
  Runner.prototype.globals = function(arr){
4199
4742
  if (0 == arguments.length) return this._globals;
4200
4743
  debug('globals %j', arr);
4201
- utils.forEach(arr, function(arr){
4202
- this._globals.push(arr);
4203
- }, this);
4744
+ this._globals = this._globals.concat(arr);
4204
4745
  return this;
4205
4746
  };
4206
4747
 
@@ -4213,13 +4754,16 @@ Runner.prototype.globals = function(arr){
4213
4754
  Runner.prototype.checkGlobals = function(test){
4214
4755
  if (this.ignoreLeaks) return;
4215
4756
  var ok = this._globals;
4757
+
4216
4758
  var globals = this.globalProps();
4217
- var isNode = process.kill;
4218
4759
  var leaks;
4219
4760
 
4220
- // check length - 2 ('errno' and 'location' globals)
4221
- if (isNode && 1 == ok.length - globals.length) return
4222
- else if (2 == ok.length - globals.length) return;
4761
+ if (test) {
4762
+ ok = ok.concat(test._allowedGlobals || []);
4763
+ }
4764
+
4765
+ if(this.prevGlobalsLength == globals.length) return;
4766
+ this.prevGlobalsLength = globals.length;
4223
4767
 
4224
4768
  leaks = filterLeaks(ok, globals);
4225
4769
  this._globals = this._globals.concat(leaks);
@@ -4239,24 +4783,36 @@ Runner.prototype.checkGlobals = function(test){
4239
4783
  * @api private
4240
4784
  */
4241
4785
 
4242
- Runner.prototype.fail = function(test, err){
4786
+ Runner.prototype.fail = function(test, err) {
4243
4787
  ++this.failures;
4244
4788
  test.state = 'failed';
4245
4789
 
4246
- if ('string' == typeof err) {
4247
- err = new Error('the string "' + err + '" was thrown, throw an Error :)');
4790
+ if (!(err instanceof Error)) {
4791
+ err = new Error('the ' + type(err) + ' ' + stringify(err) + ' was thrown, throw an Error :)');
4248
4792
  }
4249
4793
 
4794
+ err.stack = (this.fullStackTrace || !err.stack)
4795
+ ? err.stack
4796
+ : stackFilter(err.stack);
4797
+
4250
4798
  this.emit('fail', test, err);
4251
4799
  };
4252
4800
 
4253
4801
  /**
4254
4802
  * Fail the given `hook` with `err`.
4255
4803
  *
4256
- * Hook failures (currently) hard-end due
4257
- * to that fact that a failing hook will
4258
- * surely cause subsequent tests to fail,
4259
- * causing jumbled reporting.
4804
+ * Hook failures work in the following pattern:
4805
+ * - If bail, then exit
4806
+ * - Failed `before` hook skips all tests in a suite and subsuites,
4807
+ * but jumps to corresponding `after` hook
4808
+ * - Failed `before each` hook skips remaining tests in a
4809
+ * suite and jumps to corresponding `after each` hook,
4810
+ * which is run only once
4811
+ * - Failed `after` hook does not alter
4812
+ * execution order
4813
+ * - Failed `after each` hook skips remaining tests in a
4814
+ * suite and subsuites, but executes other `after each`
4815
+ * hooks
4260
4816
  *
4261
4817
  * @param {Hook} hook
4262
4818
  * @param {Error} err
@@ -4265,7 +4821,9 @@ Runner.prototype.fail = function(test, err){
4265
4821
 
4266
4822
  Runner.prototype.failHook = function(hook, err){
4267
4823
  this.fail(hook, err);
4268
- this.emit('end');
4824
+ if (this.suite.bail()) {
4825
+ this.emit('end');
4826
+ }
4269
4827
  };
4270
4828
 
4271
4829
  /**
@@ -4287,6 +4845,8 @@ Runner.prototype.hook = function(name, fn){
4287
4845
  if (!hook) return fn();
4288
4846
  self.currentRunnable = hook;
4289
4847
 
4848
+ hook.ctx.currentTest = self.test;
4849
+
4290
4850
  self.emit('hook', hook);
4291
4851
 
4292
4852
  hook.on('error', function(err){
@@ -4297,20 +4857,30 @@ Runner.prototype.hook = function(name, fn){
4297
4857
  hook.removeAllListeners('error');
4298
4858
  var testError = hook.error();
4299
4859
  if (testError) self.fail(self.test, testError);
4300
- if (err) return self.failHook(hook, err);
4860
+ if (err) {
4861
+ if (err instanceof Pending) {
4862
+ suite.pending = true;
4863
+ } else {
4864
+ self.failHook(hook, err);
4865
+
4866
+ // stop executing hooks, notify callee of hook err
4867
+ return fn(err);
4868
+ }
4869
+ }
4301
4870
  self.emit('hook end', hook);
4871
+ delete hook.ctx.currentTest;
4302
4872
  next(++i);
4303
4873
  });
4304
4874
  }
4305
4875
 
4306
- process.nextTick(function(){
4876
+ Runner.immediately(function(){
4307
4877
  next(0);
4308
4878
  });
4309
4879
  };
4310
4880
 
4311
4881
  /**
4312
4882
  * Run hook `name` for the given array of `suites`
4313
- * in order, and callback `fn(err)`.
4883
+ * in order, and callback `fn(err, errSuite)`.
4314
4884
  *
4315
4885
  * @param {String} name
4316
4886
  * @param {Array} suites
@@ -4332,8 +4902,9 @@ Runner.prototype.hooks = function(name, suites, fn){
4332
4902
 
4333
4903
  self.hook(name, function(err){
4334
4904
  if (err) {
4905
+ var errSuite = self.suite;
4335
4906
  self.suite = orig;
4336
- return fn(err);
4907
+ return fn(err, errSuite);
4337
4908
  }
4338
4909
 
4339
4910
  next(suites.pop());
@@ -4421,10 +4992,39 @@ Runner.prototype.runTests = function(suite, fn){
4421
4992
  , tests = suite.tests.slice()
4422
4993
  , test;
4423
4994
 
4424
- function next(err) {
4995
+
4996
+ function hookErr(err, errSuite, after) {
4997
+ // before/after Each hook for errSuite failed:
4998
+ var orig = self.suite;
4999
+
5000
+ // for failed 'after each' hook start from errSuite parent,
5001
+ // otherwise start from errSuite itself
5002
+ self.suite = after ? errSuite.parent : errSuite;
5003
+
5004
+ if (self.suite) {
5005
+ // call hookUp afterEach
5006
+ self.hookUp('afterEach', function(err2, errSuite2) {
5007
+ self.suite = orig;
5008
+ // some hooks may fail even now
5009
+ if (err2) return hookErr(err2, errSuite2, true);
5010
+ // report error suite
5011
+ fn(errSuite);
5012
+ });
5013
+ } else {
5014
+ // there is no need calling other 'after each' hooks
5015
+ self.suite = orig;
5016
+ fn(errSuite);
5017
+ }
5018
+ }
5019
+
5020
+ function next(err, errSuite) {
4425
5021
  // if we bail after first err
4426
5022
  if (self.failures && suite._bail) return fn();
4427
5023
 
5024
+ if (self._abort) return fn();
5025
+
5026
+ if (err) return hookErr(err, errSuite, true);
5027
+
4428
5028
  // next test
4429
5029
  test = tests.shift();
4430
5030
 
@@ -4445,14 +5045,31 @@ Runner.prototype.runTests = function(suite, fn){
4445
5045
 
4446
5046
  // execute test and hook(s)
4447
5047
  self.emit('test', self.test = test);
4448
- self.hookDown('beforeEach', function(){
5048
+ self.hookDown('beforeEach', function(err, errSuite){
5049
+
5050
+ if (suite.pending) {
5051
+ self.emit('pending', test);
5052
+ self.emit('test end', test);
5053
+ return next();
5054
+ }
5055
+ if (err) return hookErr(err, errSuite, false);
5056
+
4449
5057
  self.currentRunnable = self.test;
4450
5058
  self.runTest(function(err){
4451
5059
  test = self.test;
4452
5060
 
4453
5061
  if (err) {
4454
- self.fail(test, err);
5062
+ if (err instanceof Pending) {
5063
+ self.emit('pending', test);
5064
+ } else {
5065
+ self.fail(test, err);
5066
+ }
4455
5067
  self.emit('test end', test);
5068
+
5069
+ if (err instanceof Pending) {
5070
+ return next();
5071
+ }
5072
+
4456
5073
  return self.hookUp('afterEach', next);
4457
5074
  }
4458
5075
 
@@ -4488,21 +5105,37 @@ Runner.prototype.runSuite = function(suite, fn){
4488
5105
 
4489
5106
  this.emit('suite', this.suite = suite);
4490
5107
 
4491
- function next() {
5108
+ function next(errSuite) {
5109
+ if (errSuite) {
5110
+ // current suite failed on a hook from errSuite
5111
+ if (errSuite == suite) {
5112
+ // if errSuite is current suite
5113
+ // continue to the next sibling suite
5114
+ return done();
5115
+ } else {
5116
+ // errSuite is among the parents of current suite
5117
+ // stop execution of errSuite and all sub-suites
5118
+ return done(errSuite);
5119
+ }
5120
+ }
5121
+
5122
+ if (self._abort) return done();
5123
+
4492
5124
  var curr = suite.suites[i++];
4493
5125
  if (!curr) return done();
4494
5126
  self.runSuite(curr, next);
4495
5127
  }
4496
5128
 
4497
- function done() {
5129
+ function done(errSuite) {
4498
5130
  self.suite = suite;
4499
5131
  self.hook('afterAll', function(){
4500
5132
  self.emit('suite end', suite);
4501
- fn();
5133
+ fn(errSuite);
4502
5134
  });
4503
5135
  }
4504
5136
 
4505
- this.hook('beforeAll', function(){
5137
+ this.hook('beforeAll', function(err){
5138
+ if (err) return done();
4506
5139
  self.runTests(suite, next);
4507
5140
  });
4508
5141
  };
@@ -4515,11 +5148,23 @@ Runner.prototype.runSuite = function(suite, fn){
4515
5148
  */
4516
5149
 
4517
5150
  Runner.prototype.uncaught = function(err){
4518
- debug('uncaught exception %s', err.message);
5151
+ if (err) {
5152
+ debug('uncaught exception %s', err !== function () {
5153
+ return this;
5154
+ }.call(err) ? err : ( err.message || err ));
5155
+ } else {
5156
+ debug('uncaught undefined exception');
5157
+ err = utils.undefinedError();
5158
+ }
5159
+ err.uncaught = true;
5160
+
4519
5161
  var runnable = this.currentRunnable;
4520
- if (!runnable || 'failed' == runnable.state) return;
5162
+ if (!runnable) return;
5163
+
4521
5164
  runnable.clearTimeout();
4522
- err.uncaught = true;
5165
+
5166
+ // Ignore errors if complete
5167
+ if (runnable.state) return;
4523
5168
  this.fail(runnable, err);
4524
5169
 
4525
5170
  // recover from test
@@ -4543,35 +5188,59 @@ Runner.prototype.uncaught = function(err){
4543
5188
  */
4544
5189
 
4545
5190
  Runner.prototype.run = function(fn){
4546
- var self = this
4547
- , fn = fn || function(){};
5191
+ var self = this,
5192
+ rootSuite = this.suite;
5193
+
5194
+ fn = fn || function(){};
5195
+
5196
+ function uncaught(err){
5197
+ self.uncaught(err);
5198
+ }
5199
+
5200
+ function start() {
5201
+ self.emit('start');
5202
+ self.runSuite(rootSuite, function(){
5203
+ debug('finished running');
5204
+ self.emit('end');
5205
+ });
5206
+ }
4548
5207
 
4549
5208
  debug('start');
4550
5209
 
4551
5210
  // callback
4552
5211
  this.on('end', function(){
4553
5212
  debug('end');
4554
- process.removeListener('uncaughtException', function(err){
4555
- self.uncaught(err);
4556
- });
5213
+ process.removeListener('uncaughtException', uncaught);
4557
5214
  fn(self.failures);
4558
5215
  });
4559
5216
 
4560
- // run suites
4561
- this.emit('start');
4562
- this.runSuite(this.suite, function(){
4563
- debug('finished running');
4564
- self.emit('end');
4565
- });
4566
-
4567
5217
  // uncaught exception
4568
- process.on('uncaughtException', function(err){
4569
- self.uncaught(err);
4570
- });
5218
+ process.on('uncaughtException', uncaught);
5219
+
5220
+ if (this._delay) {
5221
+ // for reporters, I guess.
5222
+ // might be nice to debounce some dots while we wait.
5223
+ this.emit('waiting', rootSuite);
5224
+ rootSuite.once('run', start);
5225
+ }
5226
+ else {
5227
+ start();
5228
+ }
4571
5229
 
4572
5230
  return this;
4573
5231
  };
4574
5232
 
5233
+ /**
5234
+ * Cleanly abort execution
5235
+ *
5236
+ * @return {Runner} for chaining
5237
+ * @api public
5238
+ */
5239
+ Runner.prototype.abort = function(){
5240
+ debug('aborting');
5241
+ this._abort = true;
5242
+ };
5243
+
4575
5244
  /**
4576
5245
  * Filter leaks with the given globals flagged as `ok`.
4577
5246
  *
@@ -4583,20 +5252,57 @@ Runner.prototype.run = function(fn){
4583
5252
 
4584
5253
  function filterLeaks(ok, globals) {
4585
5254
  return filter(globals, function(key){
5255
+ // Firefox and Chrome exposes iframes as index inside the window object
5256
+ if (/^d+/.test(key)) return false;
5257
+
5258
+ // in firefox
5259
+ // if runner runs in an iframe, this iframe's window.getInterface method not init at first
5260
+ // it is assigned in some seconds
5261
+ if (global.navigator && /^getInterface/.test(key)) return false;
5262
+
5263
+ // an iframe could be approached by window[iframeIndex]
5264
+ // in ie6,7,8 and opera, iframeIndex is enumerable, this could cause leak
5265
+ if (global.navigator && /^\d+/.test(key)) return false;
5266
+
5267
+ // Opera and IE expose global variables for HTML element IDs (issue #243)
5268
+ if (/^mocha-/.test(key)) return false;
5269
+
4586
5270
  var matched = filter(ok, function(ok){
4587
5271
  if (~ok.indexOf('*')) return 0 == key.indexOf(ok.split('*')[0]);
4588
- // Opera and IE expose global variables for HTML element IDs (issue #243)
4589
- if (/^mocha-/.test(key)) return true;
4590
5272
  return key == ok;
4591
5273
  });
4592
5274
  return matched.length == 0 && (!global.navigator || 'onerror' !== key);
4593
5275
  });
4594
5276
  }
4595
5277
 
5278
+ /**
5279
+ * Array of globals dependent on the environment.
5280
+ *
5281
+ * @return {Array}
5282
+ * @api private
5283
+ */
5284
+
5285
+ function extraGlobals() {
5286
+ if (typeof(process) === 'object' &&
5287
+ typeof(process.version) === 'string') {
5288
+
5289
+ var nodeVersion = process.version.split('.').reduce(function(a, v) {
5290
+ return a << 8 | v;
5291
+ });
5292
+
5293
+ // 'errno' was renamed to process._errno in v0.9.11.
5294
+
5295
+ if (nodeVersion < 0x00090B) {
5296
+ return ['errno'];
5297
+ }
5298
+ }
5299
+
5300
+ return [];
5301
+ }
5302
+
4596
5303
  }); // module: runner.js
4597
5304
 
4598
5305
  require.register("suite.js", function(module, exports, require){
4599
-
4600
5306
  /**
4601
5307
  * Module dependencies.
4602
5308
  */
@@ -4644,9 +5350,11 @@ exports.create = function(parent, title){
4644
5350
  * @api private
4645
5351
  */
4646
5352
 
4647
- function Suite(title, ctx) {
5353
+ function Suite(title, parentContext) {
4648
5354
  this.title = title;
4649
- this.ctx = ctx;
5355
+ var context = function() {};
5356
+ context.prototype = parentContext;
5357
+ this.ctx = new context();
4650
5358
  this.suites = [];
4651
5359
  this.tests = [];
4652
5360
  this.pending = false;
@@ -4656,8 +5364,10 @@ function Suite(title, ctx) {
4656
5364
  this._afterAll = [];
4657
5365
  this.root = !title;
4658
5366
  this._timeout = 2000;
5367
+ this._enableTimeouts = true;
4659
5368
  this._slow = 75;
4660
5369
  this._bail = false;
5370
+ this.delayed = false;
4661
5371
  }
4662
5372
 
4663
5373
  /**
@@ -4682,6 +5392,7 @@ Suite.prototype.clone = function(){
4682
5392
  debug('clone');
4683
5393
  suite.ctx = this.ctx;
4684
5394
  suite.timeout(this.timeout());
5395
+ suite.enableTimeouts(this.enableTimeouts());
4685
5396
  suite.slow(this.slow());
4686
5397
  suite.bail(this.bail());
4687
5398
  return suite;
@@ -4697,12 +5408,28 @@ Suite.prototype.clone = function(){
4697
5408
 
4698
5409
  Suite.prototype.timeout = function(ms){
4699
5410
  if (0 == arguments.length) return this._timeout;
5411
+ if (ms.toString() === '0') this._enableTimeouts = false;
4700
5412
  if ('string' == typeof ms) ms = milliseconds(ms);
4701
5413
  debug('timeout %d', ms);
4702
5414
  this._timeout = parseInt(ms, 10);
4703
5415
  return this;
4704
5416
  };
4705
5417
 
5418
+ /**
5419
+ * Set timeout `enabled`.
5420
+ *
5421
+ * @param {Boolean} enabled
5422
+ * @return {Suite|Boolean} self or enabled
5423
+ * @api private
5424
+ */
5425
+
5426
+ Suite.prototype.enableTimeouts = function(enabled){
5427
+ if (arguments.length === 0) return this._enableTimeouts;
5428
+ debug('enableTimeouts %s', enabled);
5429
+ this._enableTimeouts = enabled;
5430
+ return this;
5431
+ };
5432
+
4706
5433
  /**
4707
5434
  * Set slow `ms` or short-hand such as "2s".
4708
5435
  *
@@ -4722,7 +5449,7 @@ Suite.prototype.slow = function(ms){
4722
5449
  /**
4723
5450
  * Sets whether to bail after first error.
4724
5451
  *
4725
- * @parma {Boolean} bail
5452
+ * @param {Boolean} bail
4726
5453
  * @return {Suite|Number} for chaining
4727
5454
  * @api private
4728
5455
  */
@@ -4742,11 +5469,18 @@ Suite.prototype.bail = function(bail){
4742
5469
  * @api private
4743
5470
  */
4744
5471
 
4745
- Suite.prototype.beforeAll = function(fn){
5472
+ Suite.prototype.beforeAll = function(title, fn){
4746
5473
  if (this.pending) return this;
4747
- var hook = new Hook('"before all" hook', fn);
5474
+ if ('function' === typeof title) {
5475
+ fn = title;
5476
+ title = fn.name;
5477
+ }
5478
+ title = '"before all" hook' + (title ? ': ' + title : '');
5479
+
5480
+ var hook = new Hook(title, fn);
4748
5481
  hook.parent = this;
4749
5482
  hook.timeout(this.timeout());
5483
+ hook.enableTimeouts(this.enableTimeouts());
4750
5484
  hook.slow(this.slow());
4751
5485
  hook.ctx = this.ctx;
4752
5486
  this._beforeAll.push(hook);
@@ -4762,11 +5496,18 @@ Suite.prototype.beforeAll = function(fn){
4762
5496
  * @api private
4763
5497
  */
4764
5498
 
4765
- Suite.prototype.afterAll = function(fn){
5499
+ Suite.prototype.afterAll = function(title, fn){
4766
5500
  if (this.pending) return this;
4767
- var hook = new Hook('"after all" hook', fn);
5501
+ if ('function' === typeof title) {
5502
+ fn = title;
5503
+ title = fn.name;
5504
+ }
5505
+ title = '"after all" hook' + (title ? ': ' + title : '');
5506
+
5507
+ var hook = new Hook(title, fn);
4768
5508
  hook.parent = this;
4769
5509
  hook.timeout(this.timeout());
5510
+ hook.enableTimeouts(this.enableTimeouts());
4770
5511
  hook.slow(this.slow());
4771
5512
  hook.ctx = this.ctx;
4772
5513
  this._afterAll.push(hook);
@@ -4782,11 +5523,18 @@ Suite.prototype.afterAll = function(fn){
4782
5523
  * @api private
4783
5524
  */
4784
5525
 
4785
- Suite.prototype.beforeEach = function(fn){
5526
+ Suite.prototype.beforeEach = function(title, fn){
4786
5527
  if (this.pending) return this;
4787
- var hook = new Hook('"before each" hook', fn);
5528
+ if ('function' === typeof title) {
5529
+ fn = title;
5530
+ title = fn.name;
5531
+ }
5532
+ title = '"before each" hook' + (title ? ': ' + title : '');
5533
+
5534
+ var hook = new Hook(title, fn);
4788
5535
  hook.parent = this;
4789
5536
  hook.timeout(this.timeout());
5537
+ hook.enableTimeouts(this.enableTimeouts());
4790
5538
  hook.slow(this.slow());
4791
5539
  hook.ctx = this.ctx;
4792
5540
  this._beforeEach.push(hook);
@@ -4802,11 +5550,18 @@ Suite.prototype.beforeEach = function(fn){
4802
5550
  * @api private
4803
5551
  */
4804
5552
 
4805
- Suite.prototype.afterEach = function(fn){
5553
+ Suite.prototype.afterEach = function(title, fn){
4806
5554
  if (this.pending) return this;
4807
- var hook = new Hook('"after each" hook', fn);
5555
+ if ('function' === typeof title) {
5556
+ fn = title;
5557
+ title = fn.name;
5558
+ }
5559
+ title = '"after each" hook' + (title ? ': ' + title : '');
5560
+
5561
+ var hook = new Hook(title, fn);
4808
5562
  hook.parent = this;
4809
5563
  hook.timeout(this.timeout());
5564
+ hook.enableTimeouts(this.enableTimeouts());
4810
5565
  hook.slow(this.slow());
4811
5566
  hook.ctx = this.ctx;
4812
5567
  this._afterEach.push(hook);
@@ -4825,6 +5580,7 @@ Suite.prototype.afterEach = function(fn){
4825
5580
  Suite.prototype.addSuite = function(suite){
4826
5581
  suite.parent = this;
4827
5582
  suite.timeout(this.timeout());
5583
+ suite.enableTimeouts(this.enableTimeouts());
4828
5584
  suite.slow(this.slow());
4829
5585
  suite.bail(this.bail());
4830
5586
  this.suites.push(suite);
@@ -4843,6 +5599,7 @@ Suite.prototype.addSuite = function(suite){
4843
5599
  Suite.prototype.addTest = function(test){
4844
5600
  test.parent = this;
4845
5601
  test.timeout(this.timeout());
5602
+ test.enableTimeouts(this.enableTimeouts());
4846
5603
  test.slow(this.slow());
4847
5604
  test.ctx = this.ctx;
4848
5605
  this.tests.push(test);
@@ -4897,10 +5654,18 @@ Suite.prototype.eachTest = function(fn){
4897
5654
  return this;
4898
5655
  };
4899
5656
 
5657
+ /**
5658
+ * This will run the root suite if we happen to be running in delayed mode.
5659
+ */
5660
+ Suite.prototype.run = function run() {
5661
+ if (this.root) {
5662
+ this.emit('run');
5663
+ }
5664
+ };
5665
+
4900
5666
  }); // module: suite.js
4901
5667
 
4902
5668
  require.register("test.js", function(module, exports, require){
4903
-
4904
5669
  /**
4905
5670
  * Module dependencies.
4906
5671
  */
@@ -4940,13 +5705,15 @@ Test.prototype.constructor = Test;
4940
5705
  }); // module: test.js
4941
5706
 
4942
5707
  require.register("utils.js", function(module, exports, require){
4943
-
4944
5708
  /**
4945
5709
  * Module dependencies.
4946
5710
  */
4947
5711
 
4948
5712
  var fs = require('browser/fs')
4949
5713
  , path = require('browser/path')
5714
+ , basename = path.basename
5715
+ , exists = fs.existsSync || path.existsSync
5716
+ , glob = require('browser/glob')
4950
5717
  , join = path.join
4951
5718
  , debug = require('browser/debug')('mocha:watch');
4952
5719
 
@@ -4986,6 +5753,22 @@ exports.forEach = function(arr, fn, scope){
4986
5753
  fn.call(scope, arr[i], i);
4987
5754
  };
4988
5755
 
5756
+ /**
5757
+ * Array#map (<=IE8)
5758
+ *
5759
+ * @param {Array} array
5760
+ * @param {Function} fn
5761
+ * @param {Object} scope
5762
+ * @api private
5763
+ */
5764
+
5765
+ exports.map = function(arr, fn, scope){
5766
+ var result = [];
5767
+ for (var i = 0, l = arr.length; i < l; i++)
5768
+ result.push(fn.call(scope, arr[i], i, arr));
5769
+ return result;
5770
+ };
5771
+
4989
5772
  /**
4990
5773
  * Array#indexOf (<=IE8)
4991
5774
  *
@@ -5051,7 +5834,7 @@ exports.filter = function(arr, fn){
5051
5834
 
5052
5835
  exports.keys = Object.keys || function(obj) {
5053
5836
  var keys = []
5054
- , has = Object.prototype.hasOwnProperty // for `window` on <=IE8
5837
+ , has = Object.prototype.hasOwnProperty; // for `window` on <=IE8
5055
5838
 
5056
5839
  for (var key in obj) {
5057
5840
  if (has.call(obj, key)) {
@@ -5081,6 +5864,28 @@ exports.watch = function(files, fn){
5081
5864
  });
5082
5865
  };
5083
5866
 
5867
+ /**
5868
+ * Array.isArray (<=IE8)
5869
+ *
5870
+ * @param {Object} obj
5871
+ * @return {Boolean}
5872
+ * @api private
5873
+ */
5874
+ var isArray = Array.isArray || function (obj) {
5875
+ return '[object Array]' == {}.toString.call(obj);
5876
+ };
5877
+
5878
+ /**
5879
+ * @description
5880
+ * Buffer.prototype.toJSON polyfill
5881
+ * @type {Function}
5882
+ */
5883
+ if(typeof Buffer !== 'undefined' && Buffer.prototype) {
5884
+ Buffer.prototype.toJSON = Buffer.prototype.toJSON || function () {
5885
+ return Array.prototype.slice.call(this, 0);
5886
+ };
5887
+ }
5888
+
5084
5889
  /**
5085
5890
  * Ignored files.
5086
5891
  */
@@ -5096,19 +5901,22 @@ function ignored(path){
5096
5901
  * @api private
5097
5902
  */
5098
5903
 
5099
- exports.files = function(dir, ret){
5904
+ exports.files = function(dir, ext, ret){
5100
5905
  ret = ret || [];
5906
+ ext = ext || ['js'];
5907
+
5908
+ var re = new RegExp('\\.(' + ext.join('|') + ')$');
5101
5909
 
5102
5910
  fs.readdirSync(dir)
5103
- .filter(ignored)
5104
- .forEach(function(path){
5105
- path = join(dir, path);
5106
- if (fs.statSync(path).isDirectory()) {
5107
- exports.files(path, ret);
5108
- } else if (path.match(/\.(js|coffee)$/)) {
5109
- ret.push(path);
5110
- }
5111
- });
5911
+ .filter(ignored)
5912
+ .forEach(function(path){
5913
+ path = join(dir, path);
5914
+ if (fs.statSync(path).isDirectory()) {
5915
+ exports.files(path, ext, ret);
5916
+ } else if (path.match(re)) {
5917
+ ret.push(path);
5918
+ }
5919
+ });
5112
5920
 
5113
5921
  return ret;
5114
5922
  };
@@ -5135,29 +5943,19 @@ exports.slug = function(str){
5135
5943
 
5136
5944
  exports.clean = function(str) {
5137
5945
  str = str
5138
- .replace(/^function *\(.*\) *{/, '')
5946
+ .replace(/\r\n?|[\n\u2028\u2029]/g, "\n").replace(/^\uFEFF/, '')
5947
+ .replace(/^function *\(.*\)\s*{|\(.*\) *=> *{?/, '')
5139
5948
  .replace(/\s+\}$/, '');
5140
5949
 
5141
5950
  var spaces = str.match(/^\n?( *)/)[1].length
5142
- , re = new RegExp('^ {' + spaces + '}', 'gm');
5951
+ , tabs = str.match(/^\n?(\t*)/)[1].length
5952
+ , re = new RegExp('^\n?' + (tabs ? '\t' : ' ') + '{' + (tabs ? tabs : spaces) + '}', 'gm');
5143
5953
 
5144
5954
  str = str.replace(re, '');
5145
5955
 
5146
5956
  return exports.trim(str);
5147
5957
  };
5148
5958
 
5149
- /**
5150
- * Escape regular expression characters in `str`.
5151
- *
5152
- * @param {String} str
5153
- * @return {String}
5154
- * @api private
5155
- */
5156
-
5157
- exports.escapeRegexp = function(str){
5158
- return str.replace(/[-\\^$*+?.()|[\]{}]/g, "\\$&");
5159
- };
5160
-
5161
5959
  /**
5162
5960
  * Trim the given `str`.
5163
5961
  *
@@ -5205,7 +6003,7 @@ function highlight(js) {
5205
6003
  .replace(/('.*?')/gm, '<span class="string">$1</span>')
5206
6004
  .replace(/(\d+\.\d+)/gm, '<span class="number">$1</span>')
5207
6005
  .replace(/(\d+)/gm, '<span class="number">$1</span>')
5208
- .replace(/\bnew *(\w+)/gm, '<span class="keyword">new</span> <span class="init">$1</span>')
6006
+ .replace(/\bnew[ \t]+(\w+)/gm, '<span class="keyword">new</span> <span class="init">$1</span>')
5209
6007
  .replace(/\b(function|new|throw|return|var|if|else)\b/gm, '<span class="keyword">$1</span>')
5210
6008
  }
5211
6009
 
@@ -5217,62 +6015,437 @@ function highlight(js) {
5217
6015
  */
5218
6016
 
5219
6017
  exports.highlightTags = function(name) {
5220
- var code = document.getElementsByTagName(name);
6018
+ var code = document.getElementById('mocha').getElementsByTagName(name);
5221
6019
  for (var i = 0, len = code.length; i < len; ++i) {
5222
6020
  code[i].innerHTML = highlight(code[i].innerHTML);
5223
6021
  }
5224
6022
  };
5225
6023
 
5226
- }); // module: utils.js
5227
6024
  /**
5228
- * Node shims.
6025
+ * If a value could have properties, and has none, this function is called, which returns
6026
+ * a string representation of the empty value.
5229
6027
  *
5230
- * These are meant only to allow
5231
- * mocha.js to run untouched, not
5232
- * to allow running node code in
5233
- * the browser.
6028
+ * Functions w/ no properties return `'[Function]'`
6029
+ * Arrays w/ length === 0 return `'[]'`
6030
+ * Objects w/ no properties return `'{}'`
6031
+ * All else: return result of `value.toString()`
6032
+ *
6033
+ * @param {*} value Value to inspect
6034
+ * @param {string} [type] The type of the value, if known.
6035
+ * @returns {string}
5234
6036
  */
6037
+ var emptyRepresentation = function emptyRepresentation(value, type) {
6038
+ type = type || exports.type(value);
5235
6039
 
5236
- process = {};
5237
- process.exit = function(status){};
5238
- process.stdout = {};
5239
- global = window;
6040
+ switch(type) {
6041
+ case 'function':
6042
+ return '[Function]';
6043
+ case 'object':
6044
+ return '{}';
6045
+ case 'array':
6046
+ return '[]';
6047
+ default:
6048
+ return value.toString();
6049
+ }
6050
+ };
5240
6051
 
5241
6052
  /**
5242
- * next tick implementation.
6053
+ * Takes some variable and asks `{}.toString()` what it thinks it is.
6054
+ * @param {*} value Anything
6055
+ * @example
6056
+ * type({}) // 'object'
6057
+ * type([]) // 'array'
6058
+ * type(1) // 'number'
6059
+ * type(false) // 'boolean'
6060
+ * type(Infinity) // 'number'
6061
+ * type(null) // 'null'
6062
+ * type(new Date()) // 'date'
6063
+ * type(/foo/) // 'regexp'
6064
+ * type('type') // 'string'
6065
+ * type(global) // 'global'
6066
+ * @api private
6067
+ * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/toString
6068
+ * @returns {string}
5243
6069
  */
6070
+ exports.type = function type(value) {
6071
+ if (typeof Buffer !== 'undefined' && Buffer.isBuffer(value)) {
6072
+ return 'buffer';
6073
+ }
6074
+ return Object.prototype.toString.call(value)
6075
+ .replace(/^\[.+\s(.+?)\]$/, '$1')
6076
+ .toLowerCase();
6077
+ };
5244
6078
 
5245
- process.nextTick = (function(){
5246
- // postMessage behaves badly on IE8
5247
- if (window.ActiveXObject || !window.postMessage) {
5248
- return function(fn){ fn() };
6079
+ /**
6080
+ * @summary Stringify `value`.
6081
+ * @description Different behavior depending on type of value.
6082
+ * - If `value` is undefined or null, return `'[undefined]'` or `'[null]'`, respectively.
6083
+ * - If `value` is not an object, function or array, return result of `value.toString()` wrapped in double-quotes.
6084
+ * - If `value` is an *empty* object, function, or array, return result of function
6085
+ * {@link emptyRepresentation}.
6086
+ * - If `value` has properties, call {@link exports.canonicalize} on it, then return result of
6087
+ * JSON.stringify().
6088
+ *
6089
+ * @see exports.type
6090
+ * @param {*} value
6091
+ * @return {string}
6092
+ * @api private
6093
+ */
6094
+
6095
+ exports.stringify = function(value) {
6096
+ var type = exports.type(value);
6097
+
6098
+ if (!~exports.indexOf(['object', 'array', 'function'], type)) {
6099
+ if(type != 'buffer') {
6100
+ return jsonStringify(value);
6101
+ }
6102
+ var json = value.toJSON();
6103
+ // Based on the toJSON result
6104
+ return jsonStringify(json.data && json.type ? json.data : json, 2)
6105
+ .replace(/,(\n|$)/g, '$1');
5249
6106
  }
5250
6107
 
5251
- // based on setZeroTimeout by David Baron
5252
- // - http://dbaron.org/log/20100309-faster-timeouts
5253
- var timeouts = []
5254
- , name = 'mocha-zero-timeout'
6108
+ for (var prop in value) {
6109
+ if (Object.prototype.hasOwnProperty.call(value, prop)) {
6110
+ return jsonStringify(exports.canonicalize(value), 2).replace(/,(\n|$)/g, '$1');
6111
+ }
6112
+ }
6113
+
6114
+ return emptyRepresentation(value, type);
6115
+ };
5255
6116
 
5256
- window.addEventListener('message', function(e){
5257
- if (e.source == window && e.data == name) {
5258
- if (e.stopPropagation) e.stopPropagation();
5259
- if (timeouts.length) timeouts.shift()();
6117
+ /**
6118
+ * @description
6119
+ * like JSON.stringify but more sense.
6120
+ * @param {Object} object
6121
+ * @param {Number=} spaces
6122
+ * @param {number=} depth
6123
+ * @returns {*}
6124
+ * @private
6125
+ */
6126
+ function jsonStringify(object, spaces, depth) {
6127
+ if(typeof spaces == 'undefined') return _stringify(object); // primitive types
6128
+
6129
+ depth = depth || 1;
6130
+ var space = spaces * depth
6131
+ , str = isArray(object) ? '[' : '{'
6132
+ , end = isArray(object) ? ']' : '}'
6133
+ , length = object.length || exports.keys(object).length
6134
+ , repeat = function(s, n) { return new Array(n).join(s); }; // `.repeat()` polyfill
6135
+
6136
+ function _stringify(val) {
6137
+ switch (exports.type(val)) {
6138
+ case 'null':
6139
+ case 'undefined':
6140
+ val = '[' + val + ']';
6141
+ break;
6142
+ case 'array':
6143
+ case 'object':
6144
+ val = jsonStringify(val, spaces, depth + 1);
6145
+ break;
6146
+ case 'boolean':
6147
+ case 'regexp':
6148
+ case 'number':
6149
+ val = val === 0 && (1/val) === -Infinity // `-0`
6150
+ ? '-0'
6151
+ : val.toString();
6152
+ break;
6153
+ case 'date':
6154
+ val = '[Date: ' + val.toISOString() + ']';
6155
+ break;
6156
+ case 'buffer':
6157
+ var json = val.toJSON();
6158
+ // Based on the toJSON result
6159
+ json = json.data && json.type ? json.data : json;
6160
+ val = '[Buffer: ' + jsonStringify(json, 2, depth + 1) + ']';
6161
+ break;
6162
+ default:
6163
+ val = (val == '[Function]' || val == '[Circular]')
6164
+ ? val
6165
+ : '"' + val + '"'; //string
5260
6166
  }
5261
- }, true);
6167
+ return val;
6168
+ }
5262
6169
 
5263
- return function(fn){
5264
- timeouts.push(fn);
5265
- window.postMessage(name, '*');
6170
+ for(var i in object) {
6171
+ if(!object.hasOwnProperty(i)) continue; // not my business
6172
+ --length;
6173
+ str += '\n ' + repeat(' ', space)
6174
+ + (isArray(object) ? '' : '"' + i + '": ') // key
6175
+ + _stringify(object[i]) // value
6176
+ + (length ? ',' : ''); // comma
6177
+ }
6178
+
6179
+ return str + (str.length != 1 // [], {}
6180
+ ? '\n' + repeat(' ', --space) + end
6181
+ : end);
6182
+ }
6183
+
6184
+ /**
6185
+ * Return if obj is a Buffer
6186
+ * @param {Object} arg
6187
+ * @return {Boolean}
6188
+ * @api private
6189
+ */
6190
+ exports.isBuffer = function (arg) {
6191
+ return typeof Buffer !== 'undefined' && Buffer.isBuffer(arg);
6192
+ };
6193
+
6194
+ /**
6195
+ * @summary Return a new Thing that has the keys in sorted order. Recursive.
6196
+ * @description If the Thing...
6197
+ * - has already been seen, return string `'[Circular]'`
6198
+ * - is `undefined`, return string `'[undefined]'`
6199
+ * - is `null`, return value `null`
6200
+ * - is some other primitive, return the value
6201
+ * - is not a primitive or an `Array`, `Object`, or `Function`, return the value of the Thing's `toString()` method
6202
+ * - is a non-empty `Array`, `Object`, or `Function`, return the result of calling this function again.
6203
+ * - is an empty `Array`, `Object`, or `Function`, return the result of calling `emptyRepresentation()`
6204
+ *
6205
+ * @param {*} value Thing to inspect. May or may not have properties.
6206
+ * @param {Array} [stack=[]] Stack of seen values
6207
+ * @return {(Object|Array|Function|string|undefined)}
6208
+ * @see {@link exports.stringify}
6209
+ * @api private
6210
+ */
6211
+
6212
+ exports.canonicalize = function(value, stack) {
6213
+ var canonicalizedObj,
6214
+ type = exports.type(value),
6215
+ prop,
6216
+ withStack = function withStack(value, fn) {
6217
+ stack.push(value);
6218
+ fn();
6219
+ stack.pop();
6220
+ };
6221
+
6222
+ stack = stack || [];
6223
+
6224
+ if (exports.indexOf(stack, value) !== -1) {
6225
+ return '[Circular]';
6226
+ }
6227
+
6228
+ switch(type) {
6229
+ case 'undefined':
6230
+ case 'buffer':
6231
+ case 'null':
6232
+ canonicalizedObj = value;
6233
+ break;
6234
+ case 'array':
6235
+ withStack(value, function () {
6236
+ canonicalizedObj = exports.map(value, function (item) {
6237
+ return exports.canonicalize(item, stack);
6238
+ });
6239
+ });
6240
+ break;
6241
+ case 'function':
6242
+ for (prop in value) {
6243
+ canonicalizedObj = {};
6244
+ break;
6245
+ }
6246
+ if (!canonicalizedObj) {
6247
+ canonicalizedObj = emptyRepresentation(value, type);
6248
+ break;
6249
+ }
6250
+ /* falls through */
6251
+ case 'object':
6252
+ canonicalizedObj = canonicalizedObj || {};
6253
+ withStack(value, function () {
6254
+ exports.forEach(exports.keys(value).sort(), function (key) {
6255
+ canonicalizedObj[key] = exports.canonicalize(value[key], stack);
6256
+ });
6257
+ });
6258
+ break;
6259
+ case 'date':
6260
+ case 'number':
6261
+ case 'regexp':
6262
+ case 'boolean':
6263
+ canonicalizedObj = value;
6264
+ break;
6265
+ default:
6266
+ canonicalizedObj = value.toString();
6267
+ }
6268
+
6269
+ return canonicalizedObj;
6270
+ };
6271
+
6272
+ /**
6273
+ * Lookup file names at the given `path`.
6274
+ */
6275
+ exports.lookupFiles = function lookupFiles(path, extensions, recursive) {
6276
+ var files = [];
6277
+ var re = new RegExp('\\.(' + extensions.join('|') + ')$');
6278
+
6279
+ if (!exists(path)) {
6280
+ if (exists(path + '.js')) {
6281
+ path += '.js';
6282
+ } else {
6283
+ files = glob.sync(path);
6284
+ if (!files.length) throw new Error("cannot resolve path (or pattern) '" + path + "'");
6285
+ return files;
6286
+ }
5266
6287
  }
5267
- })();
6288
+
6289
+ try {
6290
+ var stat = fs.statSync(path);
6291
+ if (stat.isFile()) return path;
6292
+ }
6293
+ catch (ignored) {
6294
+ return;
6295
+ }
6296
+
6297
+ fs.readdirSync(path).forEach(function(file) {
6298
+ file = join(path, file);
6299
+ try {
6300
+ var stat = fs.statSync(file);
6301
+ if (stat.isDirectory()) {
6302
+ if (recursive) {
6303
+ files = files.concat(lookupFiles(file, extensions, recursive));
6304
+ }
6305
+ return;
6306
+ }
6307
+ }
6308
+ catch (ignored) {
6309
+ return;
6310
+ }
6311
+ if (!stat.isFile() || !re.test(file) || basename(file)[0] === '.') return;
6312
+ files.push(file);
6313
+ });
6314
+
6315
+ return files;
6316
+ };
6317
+
6318
+ /**
6319
+ * Generate an undefined error with a message warning the user.
6320
+ *
6321
+ * @return {Error}
6322
+ */
6323
+
6324
+ exports.undefinedError = function() {
6325
+ return new Error('Caught undefined error, did you throw without specifying what?');
6326
+ };
6327
+
6328
+ /**
6329
+ * Generate an undefined error if `err` is not defined.
6330
+ *
6331
+ * @param {Error} err
6332
+ * @return {Error}
6333
+ */
6334
+
6335
+ exports.getError = function(err) {
6336
+ return err || exports.undefinedError();
6337
+ };
6338
+
6339
+
6340
+ /**
6341
+ * @summary
6342
+ * This Filter based on `mocha-clean` module.(see: `github.com/rstacruz/mocha-clean`)
6343
+ * @description
6344
+ * When invoking this function you get a filter function that get the Error.stack as an input,
6345
+ * and return a prettify output.
6346
+ * (i.e: strip Mocha, node_modules, bower and componentJS from stack trace).
6347
+ * @returns {Function}
6348
+ */
6349
+
6350
+ exports.stackTraceFilter = function() {
6351
+ var slash = '/'
6352
+ , is = typeof document === 'undefined'
6353
+ ? { node: true }
6354
+ : { browser: true }
6355
+ , cwd = is.node
6356
+ ? process.cwd() + slash
6357
+ : location.href.replace(/\/[^\/]*$/, '/');
6358
+
6359
+ function isNodeModule (line) {
6360
+ return (~line.indexOf('node_modules'));
6361
+ }
6362
+
6363
+ function isMochaInternal (line) {
6364
+ return (~line.indexOf('node_modules' + slash + 'mocha')) ||
6365
+ (~line.indexOf('components' + slash + 'mochajs')) ||
6366
+ (~line.indexOf('components' + slash + 'mocha'));
6367
+ }
6368
+
6369
+ // node_modules, bower, componentJS
6370
+ function isBrowserModule(line) {
6371
+ return (~line.indexOf('node_modules')) ||
6372
+ (~line.indexOf('components'));
6373
+ }
6374
+
6375
+ function isNodeInternal (line) {
6376
+ return (~line.indexOf('(timers.js:')) ||
6377
+ (~line.indexOf('(events.js:')) ||
6378
+ (~line.indexOf('(node.js:')) ||
6379
+ (~line.indexOf('(module.js:')) ||
6380
+ (~line.indexOf('GeneratorFunctionPrototype.next (native)')) ||
6381
+ false
6382
+ }
6383
+
6384
+ return function(stack) {
6385
+ stack = stack.split('\n');
6386
+
6387
+ stack = exports.reduce(stack, function(list, line) {
6388
+ if (is.node && (isNodeModule(line) ||
6389
+ isMochaInternal(line) ||
6390
+ isNodeInternal(line)))
6391
+ return list;
6392
+
6393
+ if (is.browser && (isBrowserModule(line)))
6394
+ return list;
6395
+
6396
+ // Clean up cwd(absolute)
6397
+ list.push(line.replace(cwd, ''));
6398
+ return list;
6399
+ }, []);
6400
+
6401
+ return stack.join('\n');
6402
+ }
6403
+ };
6404
+ }); // module: utils.js
6405
+ // The global object is "self" in Web Workers.
6406
+ var global = (function() { return this; })();
6407
+
6408
+ /**
6409
+ * Save timer references to avoid Sinon interfering (see GH-237).
6410
+ */
6411
+
6412
+ var Date = global.Date;
6413
+ var setTimeout = global.setTimeout;
6414
+ var setInterval = global.setInterval;
6415
+ var clearTimeout = global.clearTimeout;
6416
+ var clearInterval = global.clearInterval;
6417
+
6418
+ /**
6419
+ * Node shims.
6420
+ *
6421
+ * These are meant only to allow
6422
+ * mocha.js to run untouched, not
6423
+ * to allow running node code in
6424
+ * the browser.
6425
+ */
6426
+
6427
+ var process = {};
6428
+ process.exit = function(status){};
6429
+ process.stdout = {};
6430
+
6431
+ var uncaughtExceptionHandlers = [];
6432
+
6433
+ var originalOnerrorHandler = global.onerror;
5268
6434
 
5269
6435
  /**
5270
6436
  * Remove uncaughtException listener.
6437
+ * Revert to original onerror handler if previously defined.
5271
6438
  */
5272
6439
 
5273
- process.removeListener = function(e){
6440
+ process.removeListener = function(e, fn){
5274
6441
  if ('uncaughtException' == e) {
5275
- window.onerror = null;
6442
+ if (originalOnerrorHandler) {
6443
+ global.onerror = originalOnerrorHandler;
6444
+ } else {
6445
+ global.onerror = function() {};
6446
+ }
6447
+ var i = Mocha.utils.indexOf(uncaughtExceptionHandlers, fn);
6448
+ if (i != -1) { uncaughtExceptionHandlers.splice(i, 1); }
5276
6449
  }
5277
6450
  };
5278
6451
 
@@ -5282,59 +6455,111 @@ process.removeListener = function(e){
5282
6455
 
5283
6456
  process.on = function(e, fn){
5284
6457
  if ('uncaughtException' == e) {
5285
- window.onerror = function(err, url, line){
6458
+ global.onerror = function(err, url, line){
5286
6459
  fn(new Error(err + ' (' + url + ':' + line + ')'));
6460
+ return true;
5287
6461
  };
6462
+ uncaughtExceptionHandlers.push(fn);
5288
6463
  }
5289
6464
  };
5290
6465
 
5291
- // boot
5292
- ;(function(){
6466
+ /**
6467
+ * Expose mocha.
6468
+ */
5293
6469
 
5294
- /**
5295
- * Expose mocha.
5296
- */
6470
+ var Mocha = global.Mocha = require('mocha'),
6471
+ mocha = global.mocha = new Mocha({ reporter: 'html' });
5297
6472
 
5298
- var Mocha = window.Mocha = require('mocha'),
5299
- mocha = window.mocha = new Mocha({ reporter: 'html' });
6473
+ // The BDD UI is registered by default, but no UI will be functional in the
6474
+ // browser without an explicit call to the overridden `mocha.ui` (see below).
6475
+ // Ensure that this default UI does not expose its methods to the global scope.
6476
+ mocha.suite.removeAllListeners('pre-require');
5300
6477
 
5301
- /**
5302
- * Override ui to ensure that the ui functions are initialized.
5303
- * Normally this would happen in Mocha.prototype.loadFiles.
5304
- */
6478
+ var immediateQueue = []
6479
+ , immediateTimeout;
5305
6480
 
5306
- mocha.ui = function(ui){
5307
- Mocha.prototype.ui.call(this, ui);
5308
- this.suite.emit('pre-require', window, null, this);
5309
- return this;
5310
- };
6481
+ function timeslice() {
6482
+ var immediateStart = new Date().getTime();
6483
+ while (immediateQueue.length && (new Date().getTime() - immediateStart) < 100) {
6484
+ immediateQueue.shift()();
6485
+ }
6486
+ if (immediateQueue.length) {
6487
+ immediateTimeout = setTimeout(timeslice, 0);
6488
+ } else {
6489
+ immediateTimeout = null;
6490
+ }
6491
+ }
5311
6492
 
5312
- /**
5313
- * Setup mocha with the given setting options.
5314
- */
6493
+ /**
6494
+ * High-performance override of Runner.immediately.
6495
+ */
5315
6496
 
5316
- mocha.setup = function(opts){
5317
- if ('string' == typeof opts) opts = { ui: opts };
5318
- for (var opt in opts) this[opt](opts[opt]);
5319
- return this;
5320
- };
6497
+ Mocha.Runner.immediately = function(callback) {
6498
+ immediateQueue.push(callback);
6499
+ if (!immediateTimeout) {
6500
+ immediateTimeout = setTimeout(timeslice, 0);
6501
+ }
6502
+ };
6503
+
6504
+ /**
6505
+ * Function to allow assertion libraries to throw errors directly into mocha.
6506
+ * This is useful when running tests in a browser because window.onerror will
6507
+ * only receive the 'message' attribute of the Error.
6508
+ */
6509
+ mocha.throwError = function(err) {
6510
+ Mocha.utils.forEach(uncaughtExceptionHandlers, function (fn) {
6511
+ fn(err);
6512
+ });
6513
+ throw err;
6514
+ };
5321
6515
 
5322
- /**
5323
- * Run mocha, returning the Runner.
5324
- */
6516
+ /**
6517
+ * Override ui to ensure that the ui functions are initialized.
6518
+ * Normally this would happen in Mocha.prototype.loadFiles.
6519
+ */
5325
6520
 
5326
- mocha.run = function(fn){
5327
- var options = mocha.options;
5328
- mocha.globals('location');
6521
+ mocha.ui = function(ui){
6522
+ Mocha.prototype.ui.call(this, ui);
6523
+ this.suite.emit('pre-require', global, null, this);
6524
+ return this;
6525
+ };
5329
6526
 
5330
- var query = Mocha.utils.parseQuery(window.location.search || '');
5331
- if (query.grep) mocha.grep(query.grep);
5332
- if (query.invert) mocha.invert();
6527
+ /**
6528
+ * Setup mocha with the given setting options.
6529
+ */
5333
6530
 
5334
- return Mocha.prototype.run.call(mocha, function(){
6531
+ mocha.setup = function(opts){
6532
+ if ('string' == typeof opts) opts = { ui: opts };
6533
+ for (var opt in opts) this[opt](opts[opt]);
6534
+ return this;
6535
+ };
6536
+
6537
+ /**
6538
+ * Run mocha, returning the Runner.
6539
+ */
6540
+
6541
+ mocha.run = function(fn){
6542
+ var options = mocha.options;
6543
+ mocha.globals('location');
6544
+
6545
+ var query = Mocha.utils.parseQuery(global.location.search || '');
6546
+ if (query.grep) mocha.grep(new RegExp(query.grep));
6547
+ if (query.fgrep) mocha.grep(query.fgrep);
6548
+ if (query.invert) mocha.invert();
6549
+
6550
+ return Mocha.prototype.run.call(mocha, function(err){
6551
+ // The DOM Document is not available in Web Workers.
6552
+ var document = global.document;
6553
+ if (document && document.getElementById('mocha') && options.noHighlighting !== true) {
5335
6554
  Mocha.utils.highlightTags('code');
5336
- if (fn) fn();
5337
- });
5338
- };
5339
- })();
6555
+ }
6556
+ if (fn) fn(err);
6557
+ });
6558
+ };
6559
+
6560
+ /**
6561
+ * Expose the process shim.
6562
+ */
6563
+
6564
+ Mocha.process = process;
5340
6565
  })();