konacha 2.0.0 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/History.md CHANGED
@@ -1,5 +1,15 @@
1
1
  # master
2
2
 
3
+ # 2.1.0
4
+
5
+ * Improve capybara-webkit compatibility (#79)
6
+ * Update mocha (1.7.0+)
7
+ * Fix mocha error detection in `done()` (#74)
8
+ * Make spec file path is available to reporters
9
+ * Improve error reporting for `konacha:run` output
10
+
11
+ # 2.0.0
12
+
3
13
  * Run tests in an iframe, with `<body id="konacha">`. Each test file is run in
4
14
  isolation.
5
15
  * Removed support for konacha_config.js and Konacha.mochaOptions in favor of
data/README.md CHANGED
@@ -192,8 +192,8 @@ The `defined?` check is necessary to avoid a dependency on Konacha in the produc
192
192
  environment.
193
193
 
194
194
  The `spec_dir` option tells Konacha where to find JavaScript specs. `driver`
195
- names a Capybara driver used for the `run` task (try `:webkit`, after
196
- installing [capybara-webkit](https://github.com/thoughtbot/capybara-webkit)).
195
+ names a Capybara driver used for the `run` task (try `:poltergeist`, after
196
+ installing [PhantomJS](https://github.com/jonleighton/poltergeist#installing-phantomjs)).
197
197
  The `stylesheets` option sets the stylesheets to be linked from the `<head>`
198
198
  of the test runner iframe. The values above are the defaults.
199
199
 
@@ -11,19 +11,34 @@ mocha.reporter(function(runner) {
11
11
  fullTitle:test.fullTitle(),
12
12
  duration:test.duration,
13
13
  parentFullTitle:test.parent.fullTitle(),
14
- status:status
14
+ status:status,
15
+ path:test.parent.path
15
16
  };
16
17
 
17
- if (status == "failed")
18
- obj.error = test.err; // Contains message, expected, actual, operator, stack
18
+ if (status == "failed") {
19
+ // Error objects don't serialize properly, so we copy attributes. Note
20
+ // that iterating over test.err skips name and message.
21
+ obj.error = {
22
+ name: test.err.name,
23
+ message: test.err.message,
24
+ // We could copy stack, fileName, and lineNumber here, but they're not
25
+ // available for AssertionErrors. If we had them reliably, we could
26
+ // easily display them as well.
27
+ };
28
+ }
19
29
 
20
30
  return obj;
21
31
  };
22
32
 
23
33
  var createSuiteObject = function(suite) {
34
+ // We need to propagate the path down the suite tree
35
+ if (suite.parent)
36
+ suite.path = suite.parent.path;
37
+
24
38
  var obj = {
25
39
  title:suite.title,
26
- fullTitle:suite.fullTitle()
40
+ fullTitle:suite.fullTitle(),
41
+ path:suite.path
27
42
  };
28
43
 
29
44
  if (suite.parent)
@@ -10,8 +10,7 @@
10
10
  <% end %>
11
11
 
12
12
  <%= javascript_include_tag "chai", "konacha/iframe", :debug => false %>
13
-
14
- <%= spec_include_tag @spec %>
13
+ <%= javascript_include_tag @spec.asset_name %>
15
14
  </head>
16
15
  <body>
17
16
  </body>
data/config/routes.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  Konacha::Engine.routes.draw do
2
- match '/iframe/*name' => 'specs#iframe'
3
- match '/' => 'specs#parent'
4
- match '*path' => 'specs#parent'
2
+ get '/iframe/*name' => 'specs#iframe'
3
+ get '/' => 'specs#parent'
4
+ get '*path' => 'specs#parent'
5
5
  end
data/konacha.gemspec CHANGED
@@ -17,7 +17,7 @@ the asset pipeline and engines.}
17
17
  gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
18
  gem.name = "konacha"
19
19
  gem.require_paths = ["lib"]
20
- gem.version = "2.0.0"
20
+ gem.version = "2.1.0"
21
21
 
22
22
  gem.add_dependency "railties", "~> 3.1"
23
23
  gem.add_dependency "actionpack", "~> 3.1"
@@ -24,8 +24,7 @@ module Konacha
24
24
  end
25
25
 
26
26
  def file_path
27
- STDERR.puts "file_path not implemented" if Konacha.config.verbose
28
- "" # RSpec's BaseFormatter expects the return value to be a string
27
+ data['path']
29
28
  end
30
29
 
31
30
  alias_method :location, :file_path
@@ -49,7 +48,7 @@ module Konacha
49
48
  return unless data['status'] == "failed"
50
49
 
51
50
  @exception ||= begin
52
- e = Reporter::SpecException.new(data['error']['message'])
51
+ e = Reporter::SpecException.new("#{data['error']['name']}: #{data['error']['message']}")
53
52
  e.set_backtrace([])
54
53
  e
55
54
  end
@@ -19,7 +19,7 @@ module Konacha
19
19
  done = false
20
20
  begin
21
21
  sleep 0.1
22
- events = JSON.parse(session.evaluate_script('Konacha.getEvents()'))
22
+ events = JSON.parse(session.evaluate_script('window.top.Konacha.getEvents()'))
23
23
  if events
24
24
  events[events_consumed..-1].each do |event|
25
25
  done = true if event['event'] == 'end'
@@ -2,4 +2,10 @@ describe("failure", function(){
2
2
  it("fails", function(){
3
3
  (2 + 2).should.equal(5);
4
4
  });
5
+
6
+ it("errors", function() {
7
+ // Mocha catches and re-throws string exceptions, so we only need to test
8
+ // throwing real Error objects.
9
+ throw new Error("this one errors out");
10
+ });
5
11
  });
@@ -28,9 +28,9 @@ describe Konacha::Reporter::Metadata do
28
28
  end
29
29
 
30
30
  it "builds a SpecException object" do
31
- subject.update('status' => 'failed', 'error' => {'message' => 'expected this to work'})
31
+ subject.update('status' => 'failed', 'error' => {'name' => 'Error', 'message' => 'expected this to work'})
32
32
  subject.exception.should be_a(Konacha::Reporter::SpecException)
33
- subject.exception.message.should == 'expected this to work'
33
+ subject.exception.message.should == 'Error: expected this to work'
34
34
  subject.exception.backtrace.should == []
35
35
  end
36
36
  end
@@ -52,17 +52,22 @@ describe Konacha::Reporter::Metadata do
52
52
  end
53
53
  end
54
54
 
55
- describe "#description" do
56
- it "looks for data['title']" do
57
- subject.update('title' => 'super test')
58
- subject.description.should == 'super test'
55
+ shared_examples_for "data delegation method" do |key, method|
56
+ it "returns data['#{key}']" do
57
+ subject.update(key => 'super test')
58
+ subject.send(method).should == 'super test'
59
59
  end
60
60
  end
61
61
 
62
+ describe "#file_path" do
63
+ it_behaves_like "data delegation method", "path", "file_path"
64
+ end
65
+
66
+ describe "#description" do
67
+ it_behaves_like "data delegation method", "title", "description"
68
+ end
69
+
62
70
  describe "#full_description" do
63
- it "looks for data['fullTitle']" do
64
- subject.update('fullTitle' => 'super test')
65
- subject.full_description.should == 'super test'
66
- end
71
+ it_behaves_like "data delegation method", "fullTitle", "full_description"
67
72
  end
68
73
  end
data/spec/runner_spec.rb CHANGED
@@ -32,7 +32,8 @@ describe Konacha::Runner do
32
32
  'type' => 'suite',
33
33
  'data' => {
34
34
  'title' => 'failure',
35
- 'fullTitle' => 'failure'
35
+ 'fullTitle' => 'failure',
36
+ 'path' => 'failing_spec.js'
36
37
  }}
37
38
  end
38
39
 
@@ -41,7 +42,8 @@ describe Konacha::Runner do
41
42
  'type' => 'suite',
42
43
  'data' => {
43
44
  'title' => 'failure',
44
- 'fullTitle' => 'failure'
45
+ 'fullTitle' => 'failure',
46
+ 'path' => 'failing_spec.js'
45
47
  }}
46
48
  end
47
49
 
@@ -51,7 +53,8 @@ describe Konacha::Runner do
51
53
  'data' => {
52
54
  'title' => 'fails',
53
55
  'fullTitle' => 'failure fails',
54
- 'parentFullTitle' => 'failure'}}
56
+ 'parentFullTitle' => 'failure',
57
+ 'path' => 'failing_spec.js'}}
55
58
  end
56
59
 
57
60
  let(:failure) do
@@ -62,7 +65,20 @@ describe Konacha::Runner do
62
65
  'fullTitle' => 'failure fails',
63
66
  'parentFullTitle' => 'failure',
64
67
  'status' => 'failed',
65
- 'error' => {'message' => 'expected 4 to equal 5', 'expected' => 5}}}
68
+ 'path' => 'failing_spec.js',
69
+ 'error' => {'message' => 'expected 4 to equal 5', 'name' => 'AssertionError'}}}
70
+ end
71
+
72
+ let(:error) do
73
+ {'event' => 'fail',
74
+ 'type' => 'test',
75
+ 'data' => {
76
+ 'title' => 'errors',
77
+ 'fullTitle' => 'failure errors',
78
+ 'parentFullTitle' => 'failure',
79
+ 'status' => 'failed',
80
+ 'path' => 'failing_spec.js',
81
+ 'error' => {'message' => 'this one errors out', 'name' => 'Error'}}}
66
82
  end
67
83
 
68
84
  let(:pass) do
@@ -73,6 +89,7 @@ describe Konacha::Runner do
73
89
  'fullTitle' => 'the body#konacha element is empty',
74
90
  'parentFullTitle' => 'the body#konacha element',
75
91
  'status' => 'passed',
92
+ 'path' => 'body_spec.js.coffee',
76
93
  'duration' => anything}}
77
94
  end
78
95
 
@@ -83,6 +100,7 @@ describe Konacha::Runner do
83
100
  'title' => 'is pending',
84
101
  'fullTitle' => 'pending test is pending',
85
102
  'parentFullTitle' => 'pending test',
103
+ 'path' => 'pending_spec.js',
86
104
  'status' => 'pending'}}
87
105
  end
88
106
 
@@ -95,6 +113,7 @@ describe Konacha::Runner do
95
113
  subject.reporter.should_receive(:process_mocha_event).with(suite_end)
96
114
  subject.reporter.should_receive(:process_mocha_event).with(test)
97
115
  subject.reporter.should_receive(:process_mocha_event).with(failure)
116
+ subject.reporter.should_receive(:process_mocha_event).with(error)
98
117
  subject.reporter.should_receive(:process_mocha_event).with(pass)
99
118
  subject.reporter.should_receive(:process_mocha_event).with(pending)
100
119
  subject.reporter.should_receive(:process_mocha_event).with(end_event)
@@ -5,54 +5,21 @@ describe "konacha/specs/iframe" do
5
5
  assign(:stylesheets, [])
6
6
  end
7
7
 
8
- def asset_double(asset_name, dependencies = [])
9
- asset = double("asset called '#{asset_name}'")
10
- asset.stub(:to_a).and_return([dependencies, asset].flatten)
11
- asset.stub(:logical_path).and_return(asset_name)
12
- view.asset_paths.stub(:asset_for).with(asset_name, "js").and_return(asset)
13
- asset
14
- end
15
-
16
- def spec_double(asset_name, dependencies = [])
17
- asset_double(asset_name, dependencies)
8
+ def spec_double(asset_name)
18
9
  double("spec called '#{asset_name}'", :asset_name => asset_name, :path => "#{asset_name}.js")
19
10
  end
20
11
 
21
- let(:dependency) { asset_double("dependency") }
22
-
23
12
  it "renders a script tag for @spec" do
24
13
  assign(:spec, spec_double("a_spec"))
25
14
 
26
15
  render
27
16
 
28
- rendered.should have_selector("script[src='/assets/a_spec.js?body=1']")
29
- end
30
-
31
- it "renders a script tag for a spec's dependencies" do
32
- assign(:spec, spec_double("spec", [dependency]))
33
-
34
- render
35
-
36
- rendered.should have_selector("script[src='/assets/dependency.js?body=1']")
37
- rendered.should have_selector("script[src='/assets/spec.js?body=1']")
38
- end
39
-
40
- it "renders only one script tag for dependencies of dependencies" do
41
- dependency_a = asset_double("dependency_a")
42
- dependency_b = asset_double("dependency_b", [dependency_a])
43
-
44
- assign(:spec, spec_double("a_spec", [dependency_a, dependency_b]))
45
-
46
- render
47
-
48
- rendered.should have_selector("script[src='/assets/dependency_a.js?body=1']", :count => 1)
49
- rendered.should have_selector("script[src='/assets/dependency_b.js?body=1']", :count => 1)
17
+ rendered.should have_selector("script[src='/assets/a_spec.js']")
50
18
  end
51
19
 
52
- it "render the stylesheets" do
20
+ it "renders the stylesheets" do
53
21
  assign(:spec, spec_double("a_spec"))
54
22
  assign(:stylesheets, %w(foo bar))
55
- assign(:specs, [])
56
23
 
57
24
  render
58
25
 
@@ -591,7 +591,7 @@ module.exports = function(suite){
591
591
  context.describe = context.context = function(title, fn){
592
592
  var suite = Suite.create(suites[0], title);
593
593
  suites.unshift(suite);
594
- fn();
594
+ fn.call(suite);
595
595
  suites.shift();
596
596
  return suite;
597
597
  };
@@ -606,7 +606,7 @@ module.exports = function(suite){
606
606
  var suite = Suite.create(suites[0], title);
607
607
  suite.pending = true;
608
608
  suites.unshift(suite);
609
- fn();
609
+ fn.call(suite);
610
610
  suites.shift();
611
611
  };
612
612
 
@@ -903,7 +903,7 @@ module.exports = function(suite){
903
903
  context.suite = function(title, fn){
904
904
  var suite = Suite.create(suites[0], title);
905
905
  suites.unshift(suite);
906
- fn();
906
+ fn.call(suite);
907
907
  suites.shift();
908
908
  return suite;
909
909
  };
@@ -937,6 +937,14 @@ module.exports = function(suite){
937
937
  var test = context.test(title, fn);
938
938
  mocha.grep(test.fullTitle());
939
939
  };
940
+
941
+ /**
942
+ * Pending test case.
943
+ */
944
+
945
+ context.test.skip = function(title){
946
+ context.test(title);
947
+ };
940
948
  });
941
949
  };
942
950
 
@@ -1211,6 +1219,18 @@ Mocha.prototype.slow = function(slow){
1211
1219
  return this;
1212
1220
  };
1213
1221
 
1222
+ /**
1223
+ * Makes all tests async (accepting a callback)
1224
+ *
1225
+ * @return {Mocha}
1226
+ * @api public
1227
+ */
1228
+
1229
+ Mocha.prototype.asyncOnly = function(){
1230
+ this.options.asyncOnly = true;
1231
+ return this;
1232
+ };
1233
+
1214
1234
  /**
1215
1235
  * Run tests and invoke `fn()` when complete.
1216
1236
  *
@@ -1226,6 +1246,7 @@ Mocha.prototype.run = function(fn){
1226
1246
  var runner = new exports.Runner(suite);
1227
1247
  var reporter = new this._reporter(runner);
1228
1248
  runner.ignoreLeaks = options.ignoreLeaks;
1249
+ runner.asyncOnly = options.asyncOnly;
1229
1250
  if (options.grep) runner.grep(options.grep, options.invert);
1230
1251
  if (options.globals) runner.globals(options.globals);
1231
1252
  if (options.growl) this._growl(runner, reporter);
@@ -1306,14 +1327,14 @@ function parse(str) {
1306
1327
  */
1307
1328
 
1308
1329
  function format(ms) {
1309
- if (ms == d) return (ms / d) + ' day';
1310
- if (ms > d) return (ms / d) + ' days';
1311
- if (ms == h) return (ms / h) + ' hour';
1312
- if (ms > h) return (ms / h) + ' hours';
1313
- if (ms == m) return (ms / m) + ' minute';
1314
- if (ms > m) return (ms / m) + ' minutes';
1315
- if (ms == s) return (ms / s) + ' second';
1316
- if (ms > s) return (ms / s) + ' seconds';
1330
+ if (ms == d) return Math.round(ms / d) + ' day';
1331
+ if (ms > d) return Math.round(ms / d) + ' days';
1332
+ if (ms == h) return Math.round(ms / h) + ' hour';
1333
+ if (ms > h) return Math.round(ms / h) + ' hours';
1334
+ if (ms == m) return Math.round(ms / m) + ' minute';
1335
+ if (ms > m) return Math.round(ms / m) + ' minutes';
1336
+ if (ms == s) return Math.round(ms / s) + ' second';
1337
+ if (ms > s) return Math.round(ms / s) + ' seconds';
1317
1338
  return ms + ' ms';
1318
1339
  }
1319
1340
  }); // module: ms.js
@@ -1382,6 +1403,23 @@ exports.colors = {
1382
1403
  , 'diff removed': 41
1383
1404
  };
1384
1405
 
1406
+ /**
1407
+ * Default symbol map.
1408
+ */
1409
+
1410
+ exports.symbols = {
1411
+ ok: '✔',
1412
+ err: '✖',
1413
+ dot: '․'
1414
+ };
1415
+
1416
+ // With node.js on Windows: use symbols available in terminal default fonts
1417
+ if ('win32' == process.platform) {
1418
+ exports.symbols.ok = '\u221A';
1419
+ exports.symbols.err = '\u00D7';
1420
+ exports.symbols.dot = '.';
1421
+ }
1422
+
1385
1423
  /**
1386
1424
  * Color `str` with the given `type`,
1387
1425
  * allowing colors to be disabled,
@@ -1532,6 +1570,8 @@ function Base(runner) {
1532
1570
  if (!runner) return;
1533
1571
  this.runner = runner;
1534
1572
 
1573
+ runner.stats = stats;
1574
+
1535
1575
  runner.on('start', function(){
1536
1576
  stats.start = new Date;
1537
1577
  });
@@ -1596,7 +1636,7 @@ Base.prototype.epilogue = function(){
1596
1636
 
1597
1637
  // failure
1598
1638
  if (stats.failures) {
1599
- fmt = color('bright fail', ' ')
1639
+ fmt = color('bright fail', ' ' + exports.symbols.err)
1600
1640
  + color('fail', ' %d of %d %s failed')
1601
1641
  + color('light', ':')
1602
1642
 
@@ -1611,7 +1651,7 @@ Base.prototype.epilogue = function(){
1611
1651
  }
1612
1652
 
1613
1653
  // pass
1614
- fmt = color('bright pass', ' ')
1654
+ fmt = color('bright pass', ' ' + exports.symbols.ok)
1615
1655
  + color('green', ' %d %s complete')
1616
1656
  + color('light', ' (%s)');
1617
1657
 
@@ -1723,7 +1763,7 @@ function Doc(runner) {
1723
1763
  ++indents;
1724
1764
  console.log('%s<section class="suite">', indent());
1725
1765
  ++indents;
1726
- console.log('%s<h1>%s</h1>', indent(), suite.title);
1766
+ console.log('%s<h1>%s</h1>', indent(), utils.escape(suite.title));
1727
1767
  console.log('%s<dl>', indent());
1728
1768
  });
1729
1769
 
@@ -1736,7 +1776,7 @@ function Doc(runner) {
1736
1776
  });
1737
1777
 
1738
1778
  runner.on('pass', function(test){
1739
- console.log('%s <dt>%s</dt>', indent(), test.title);
1779
+ console.log('%s <dt>%s</dt>', indent(), utils.escape(test.title));
1740
1780
  var code = utils.escape(utils.clean(test.fn.toString()));
1741
1781
  console.log('%s <dd><pre><code>%s</code></pre></dd>', indent(), code);
1742
1782
  });
@@ -1772,7 +1812,6 @@ function Dot(runner) {
1772
1812
  var self = this
1773
1813
  , stats = this.stats
1774
1814
  , width = Base.window.width * .75 | 0
1775
- , c = '․'
1776
1815
  , n = 0;
1777
1816
 
1778
1817
  runner.on('start', function(){
@@ -1780,21 +1819,21 @@ function Dot(runner) {
1780
1819
  });
1781
1820
 
1782
1821
  runner.on('pending', function(test){
1783
- process.stdout.write(color('pending', c));
1822
+ process.stdout.write(color('pending', Base.symbols.dot));
1784
1823
  });
1785
1824
 
1786
1825
  runner.on('pass', function(test){
1787
1826
  if (++n % width == 0) process.stdout.write('\n ');
1788
1827
  if ('slow' == test.speed) {
1789
- process.stdout.write(color('bright yellow', c));
1828
+ process.stdout.write(color('bright yellow', Base.symbols.dot));
1790
1829
  } else {
1791
- process.stdout.write(color(test.speed, c));
1830
+ process.stdout.write(color(test.speed, Base.symbols.dot));
1792
1831
  }
1793
1832
  });
1794
1833
 
1795
1834
  runner.on('fail', function(test, err){
1796
1835
  if (++n % width == 0) process.stdout.write('\n ');
1797
- process.stdout.write(color('fail', c));
1836
+ process.stdout.write(color('fail', Base.symbols.dot));
1798
1837
  });
1799
1838
 
1800
1839
  runner.on('end', function(){
@@ -1897,7 +1936,7 @@ exports = module.exports = HTML;
1897
1936
  * Stats template.
1898
1937
  */
1899
1938
 
1900
- var statsTemplate = '<ul id="stats">'
1939
+ var statsTemplate = '<ul id="mocha-stats">'
1901
1940
  + '<li class="progress"><canvas width="40" height="40"></canvas></li>'
1902
1941
  + '<li class="passes"><a href="#">passes:</a> <em>0</em></li>'
1903
1942
  + '<li class="failures"><a href="#">failures:</a> <em>0</em></li>'
@@ -1925,7 +1964,7 @@ function HTML(runner, root) {
1925
1964
  , failuresLink = items[2].getElementsByTagName('a')[0]
1926
1965
  , duration = items[3].getElementsByTagName('em')[0]
1927
1966
  , canvas = stat.getElementsByTagName('canvas')[0]
1928
- , report = fragment('<ul id="report"></ul>')
1967
+ , report = fragment('<ul id="mocha-report"></ul>')
1929
1968
  , stack = [report]
1930
1969
  , progress
1931
1970
  , ctx
@@ -1992,7 +2031,7 @@ function HTML(runner, root) {
1992
2031
  window.scrollTo(0, document.body.scrollHeight);
1993
2032
 
1994
2033
  // TODO: add to stats
1995
- var percent = stats.tests / total * 100 | 0;
2034
+ var percent = stats.tests / this.total * 100 | 0;
1996
2035
  if (progress) progress.update(percent).draw(ctx);
1997
2036
 
1998
2037
  // update stats
@@ -2003,11 +2042,11 @@ function HTML(runner, root) {
2003
2042
 
2004
2043
  // test
2005
2044
  if ('passed' == test.state) {
2006
- var el = fragment('<li class="test pass %e"><h2>%e<span class="duration">%ems</span></h2></li>', test.speed, test.title, test.duration);
2045
+ 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()));
2007
2046
  } else if (test.pending) {
2008
2047
  var el = fragment('<li class="test pass pending"><h2>%e</h2></li>', test.title);
2009
2048
  } else {
2010
- var el = fragment('<li class="test fail"><h2>%e</h2></li>', test.title);
2049
+ var el = fragment('<li class="test fail"><h2>%e <a href="?grep=%e" class="replay">‣</a></h2></li>', test.title, encodeURIComponent(test.fullTitle()));
2011
2050
  var str = test.err.stack || test.err.toString();
2012
2051
 
2013
2052
  // FF / Opera do not add the message
@@ -2043,7 +2082,8 @@ function HTML(runner, root) {
2043
2082
  pre.style.display = 'none';
2044
2083
  }
2045
2084
 
2046
- stack[0].appendChild(el);
2085
+ // Don't call .appendChild if #mocha-report was already .shift()'ed off the stack.
2086
+ if (stack[0]) stack[0].appendChild(el);
2047
2087
  });
2048
2088
  }
2049
2089
 
@@ -2052,7 +2092,7 @@ function HTML(runner, root) {
2052
2092
  */
2053
2093
 
2054
2094
  function error(msg) {
2055
- document.body.appendChild(fragment('<div id="error">%s</div>', msg));
2095
+ document.body.appendChild(fragment('<div id="mocha-error">%s</div>', msg));
2056
2096
  }
2057
2097
 
2058
2098
  /**
@@ -2230,6 +2270,10 @@ function map(cov) {
2230
2270
  ret.sloc += data.sloc;
2231
2271
  }
2232
2272
 
2273
+ ret.files.sort(function(a, b) {
2274
+ return a.filename.localeCompare(b.filename);
2275
+ });
2276
+
2233
2277
  if (ret.sloc > 0) {
2234
2278
  ret.coverage = (ret.hits / ret.sloc) * 100;
2235
2279
  }
@@ -2584,7 +2628,7 @@ function List(runner) {
2584
2628
  });
2585
2629
 
2586
2630
  runner.on('pass', function(test){
2587
- var fmt = color('checkmark', ' ')
2631
+ var fmt = color('checkmark', ' '+Base.symbols.dot)
2588
2632
  + color('pass', ' %s: ')
2589
2633
  + color(test.speed, '%dms');
2590
2634
  cursor.CR();
@@ -2680,7 +2724,7 @@ function Markdown(runner) {
2680
2724
  runner.on('suite', function(suite){
2681
2725
  ++level;
2682
2726
  var slug = utils.slug(suite.fullTitle());
2683
- buf += '<a name="' + slug + '" />' + '\n';
2727
+ buf += '<a name="' + slug + '"></a>' + '\n';
2684
2728
  buf += title(suite.title) + '\n';
2685
2729
  });
2686
2730
 
@@ -3056,7 +3100,7 @@ function Progress(runner, options) {
3056
3100
  // default chars
3057
3101
  options.open = options.open || '[';
3058
3102
  options.complete = options.complete || '▬';
3059
- options.incomplete = options.incomplete || '⋅';
3103
+ options.incomplete = options.incomplete || Base.symbols.dot;
3060
3104
  options.close = options.close || ']';
3061
3105
  options.verbose = false;
3062
3106
 
@@ -3165,13 +3209,13 @@ function Spec(runner) {
3165
3209
  runner.on('pass', function(test){
3166
3210
  if ('fast' == test.speed) {
3167
3211
  var fmt = indent()
3168
- + color('checkmark', ' ')
3212
+ + color('checkmark', ' ' + Base.symbols.ok)
3169
3213
  + color('pass', ' %s ');
3170
3214
  cursor.CR();
3171
3215
  console.log(fmt, test.title);
3172
3216
  } else {
3173
3217
  var fmt = indent()
3174
- + color('checkmark', ' ')
3218
+ + color('checkmark', ' ' + Base.symbols.ok)
3175
3219
  + color('pass', ' %s ')
3176
3220
  + color(test.speed, '(%dms)');
3177
3221
  cursor.CR();
@@ -3461,7 +3505,8 @@ require.register("runnable.js", function(module, exports, require){
3461
3505
  */
3462
3506
 
3463
3507
  var EventEmitter = require('browser/events').EventEmitter
3464
- , debug = require('browser/debug')('mocha:runnable');
3508
+ , debug = require('browser/debug')('mocha:runnable')
3509
+ , milliseconds = require('./ms');
3465
3510
 
3466
3511
  /**
3467
3512
  * Save timer references to avoid Sinon interfering (see GH-237).
@@ -3473,6 +3518,12 @@ var Date = global.Date
3473
3518
  , clearTimeout = global.clearTimeout
3474
3519
  , clearInterval = global.clearInterval;
3475
3520
 
3521
+ /**
3522
+ * Object#toString().
3523
+ */
3524
+
3525
+ var toString = Object.prototype.toString;
3526
+
3476
3527
  /**
3477
3528
  * Expose `Runnable`.
3478
3529
  */
@@ -3508,13 +3559,14 @@ Runnable.prototype.constructor = Runnable;
3508
3559
  /**
3509
3560
  * Set & get timeout `ms`.
3510
3561
  *
3511
- * @param {Number} ms
3562
+ * @param {Number|String} ms
3512
3563
  * @return {Runnable|Number} ms or self
3513
3564
  * @api private
3514
3565
  */
3515
3566
 
3516
3567
  Runnable.prototype.timeout = function(ms){
3517
3568
  if (0 == arguments.length) return this._timeout;
3569
+ if ('string' == typeof ms) ms = milliseconds(ms);
3518
3570
  debug('timeout %d', ms);
3519
3571
  this._timeout = ms;
3520
3572
  if (this.timer) this.resetTimeout();
@@ -3524,13 +3576,14 @@ Runnable.prototype.timeout = function(ms){
3524
3576
  /**
3525
3577
  * Set & get slow `ms`.
3526
3578
  *
3527
- * @param {Number} ms
3579
+ * @param {Number|String} ms
3528
3580
  * @return {Runnable|Number} ms or self
3529
3581
  * @api private
3530
3582
  */
3531
3583
 
3532
3584
  Runnable.prototype.slow = function(ms){
3533
3585
  if (0 === arguments.length) return this._slow;
3586
+ if ('string' == typeof ms) ms = milliseconds(ms);
3534
3587
  debug('timeout %d', ms);
3535
3588
  this._slow = ms;
3536
3589
  return this;
@@ -3644,7 +3697,7 @@ Runnable.prototype.run = function(fn){
3644
3697
  if (this.async) {
3645
3698
  try {
3646
3699
  this.fn.call(ctx, function(err){
3647
- if (err instanceof Error) return done(err);
3700
+ if (toString.call(err) === "[object Error]") return done(err);
3648
3701
  if (null != err) return done(new Error('done() invoked with non-Error: ' + err));
3649
3702
  done();
3650
3703
  });
@@ -3653,7 +3706,11 @@ Runnable.prototype.run = function(fn){
3653
3706
  }
3654
3707
  return;
3655
3708
  }
3656
-
3709
+
3710
+ if (this.asyncOnly) {
3711
+ return done(new Error('--async-only option in use without declaring `done()`'));
3712
+ }
3713
+
3657
3714
  // sync
3658
3715
  try {
3659
3716
  if (!this.pending) this.fn.call(ctx);
@@ -3680,6 +3737,19 @@ var EventEmitter = require('browser/events').EventEmitter
3680
3737
  , keys = utils.keys
3681
3738
  , noop = function(){};
3682
3739
 
3740
+ /**
3741
+ * Non-enumerable globals.
3742
+ */
3743
+
3744
+ var globals = [
3745
+ 'setTimeout',
3746
+ 'clearTimeout',
3747
+ 'setInterval',
3748
+ 'clearInterval',
3749
+ 'XMLHttpRequest',
3750
+ 'Date'
3751
+ ];
3752
+
3683
3753
  /**
3684
3754
  * Expose `Runner`.
3685
3755
  */
@@ -3714,7 +3784,7 @@ function Runner(suite) {
3714
3784
  this.on('test end', function(test){ self.checkGlobals(test); });
3715
3785
  this.on('hook end', function(hook){ self.checkGlobals(hook); });
3716
3786
  this.grep(/.*/);
3717
- this.globals(utils.keys(global).concat(['errno']));
3787
+ this.globals(this.globalProps().concat(['errno']));
3718
3788
  }
3719
3789
 
3720
3790
  /**
@@ -3765,6 +3835,25 @@ Runner.prototype.grepTotal = function(suite) {
3765
3835
  return total;
3766
3836
  };
3767
3837
 
3838
+ /**
3839
+ * Return a list of global properties.
3840
+ *
3841
+ * @return {Array}
3842
+ * @api private
3843
+ */
3844
+
3845
+ Runner.prototype.globalProps = function() {
3846
+ var props = utils.keys(global);
3847
+
3848
+ // non-enumerables
3849
+ for (var i = 0; i < globals.length; ++i) {
3850
+ if (~props.indexOf(globals[i])) continue;
3851
+ props.push(globals[i]);
3852
+ }
3853
+
3854
+ return props;
3855
+ };
3856
+
3768
3857
  /**
3769
3858
  * Allow the given `arr` of globals.
3770
3859
  *
@@ -3791,7 +3880,7 @@ Runner.prototype.globals = function(arr){
3791
3880
  Runner.prototype.checkGlobals = function(test){
3792
3881
  if (this.ignoreLeaks) return;
3793
3882
  var ok = this._globals;
3794
- var globals = keys(global);
3883
+ var globals = this.globalProps();
3795
3884
  var isNode = process.kill;
3796
3885
  var leaks;
3797
3886
 
@@ -3971,6 +4060,8 @@ Runner.prototype.runTest = function(fn){
3971
4060
  var test = this.test
3972
4061
  , self = this;
3973
4062
 
4063
+ if (this.asyncOnly) test.asyncOnly = true;
4064
+
3974
4065
  try {
3975
4066
  test.on('error', function(err){
3976
4067
  self.fail(test, err);
@@ -3992,7 +4083,7 @@ Runner.prototype.runTest = function(fn){
3992
4083
 
3993
4084
  Runner.prototype.runTests = function(suite, fn){
3994
4085
  var self = this
3995
- , tests = suite.tests
4086
+ , tests = suite.tests.slice()
3996
4087
  , test;
3997
4088
 
3998
4089
  function next(err) {
@@ -4160,6 +4251,8 @@ function filterLeaks(ok, globals) {
4160
4251
  return filter(globals, function(key){
4161
4252
  var matched = filter(ok, function(ok){
4162
4253
  if (~ok.indexOf('*')) return 0 == key.indexOf(ok.split('*')[0]);
4254
+ // Opera and IE expose global variables for HTML element IDs (issue #243)
4255
+ if (/^mocha-/.test(key)) return true;
4163
4256
  return key == ok;
4164
4257
  });
4165
4258
  return matched.length == 0 && (!global.navigator || 'onerror' !== key);
@@ -4896,6 +4989,7 @@ process.on = function(e, fn){
4896
4989
 
4897
4990
  var query = Mocha.utils.parseQuery(window.location.search || '');
4898
4991
  if (query.grep) mocha.grep(query.grep);
4992
+ if (query.invert) mocha.invert();
4899
4993
 
4900
4994
  return Mocha.prototype.run.call(mocha, function(){
4901
4995
  Mocha.utils.highlightTags('code');
@@ -55,16 +55,6 @@ body {
55
55
  margin-left: 15px;
56
56
  }
57
57
 
58
- #mocha .test:hover h2::after {
59
- position: relative;
60
- top: 0;
61
- right: -10px;
62
- content: '(view source)';
63
- font-size: 12px;
64
- font-family: arial;
65
- color: #888;
66
- }
67
-
68
58
  #mocha .test.pending:hover h2::after {
69
59
  content: '(pending)';
70
60
  font-family: arial;
@@ -134,6 +124,8 @@ body {
134
124
 
135
125
  #mocha .test pre.error {
136
126
  color: #c00;
127
+ max-height: 300px;
128
+ overflow: auto;
137
129
  }
138
130
 
139
131
  #mocha .test pre {
@@ -145,24 +137,56 @@ body {
145
137
  border-bottom-color: #ddd;
146
138
  -webkit-border-radius: 3px;
147
139
  -webkit-box-shadow: 0 1px 3px #eee;
140
+ -moz-border-radius: 3px;
141
+ -moz-box-shadow: 0 1px 3px #eee;
142
+ }
143
+
144
+ #mocha .test h2 {
145
+ position: relative;
146
+ }
147
+
148
+ #mocha .test a.replay {
149
+ position: absolute;
150
+ top: 3px;
151
+ right: -20px;
152
+ text-decoration: none;
153
+ vertical-align: middle;
154
+ display: block;
155
+ width: 15px;
156
+ height: 15px;
157
+ line-height: 15px;
158
+ text-align: center;
159
+ background: #eee;
160
+ font-size: 15px;
161
+ -moz-border-radius: 15px;
162
+ border-radius: 15px;
163
+ -webkit-transition: opacity 200ms;
164
+ -moz-transition: opacity 200ms;
165
+ transition: opacity 200ms;
166
+ opacity: 0.2;
167
+ color: #888;
168
+ }
169
+
170
+ #mocha .test:hover a.replay {
171
+ opacity: 1;
148
172
  }
149
173
 
150
- #report.pass .test.fail {
174
+ #mocha-report.pass .test.fail {
151
175
  display: none;
152
176
  }
153
177
 
154
- #report.fail .test.pass {
178
+ #mocha-report.fail .test.pass {
155
179
  display: none;
156
180
  }
157
181
 
158
- #error {
182
+ #mocha-error {
159
183
  color: #c00;
160
184
  font-size: 1.5 em;
161
185
  font-weight: 100;
162
186
  letter-spacing: 1px;
163
187
  }
164
188
 
165
- #stats {
189
+ #mocha-stats {
166
190
  position: fixed;
167
191
  top: 15px;
168
192
  right: 10px;
@@ -171,25 +195,25 @@ body {
171
195
  color: #888;
172
196
  }
173
197
 
174
- #stats .progress {
198
+ #mocha-stats .progress {
175
199
  float: right;
176
200
  padding-top: 0;
177
201
  }
178
202
 
179
- #stats em {
203
+ #mocha-stats em {
180
204
  color: black;
181
205
  }
182
206
 
183
- #stats a {
207
+ #mocha-stats a {
184
208
  text-decoration: none;
185
209
  color: inherit;
186
210
  }
187
211
 
188
- #stats a:hover {
212
+ #mocha-stats a:hover {
189
213
  border-bottom: 1px solid #eee;
190
214
  }
191
215
 
192
- #stats li {
216
+ #mocha-stats li {
193
217
  display: inline-block;
194
218
  margin: 0 5px;
195
219
  list-style: none;
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: konacha
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0
4
+ version: 2.1.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-11-01 00:00:00.000000000 Z
12
+ date: 2012-11-12 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: railties
@@ -219,7 +219,6 @@ files:
219
219
  - app/assets/javascripts/konacha/runner.js
220
220
  - app/assets/stylesheets/konacha.css
221
221
  - app/controllers/konacha/specs_controller.rb
222
- - app/helpers/konacha/specs_helper.rb
223
222
  - app/models/konacha/spec.rb
224
223
  - app/views/konacha/specs/iframe.html.erb
225
224
  - app/views/konacha/specs/parent.html.erb
@@ -293,7 +292,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
293
292
  version: '0'
294
293
  segments:
295
294
  - 0
296
- hash: 3302802791356111510
295
+ hash: 3925858609207323185
297
296
  required_rubygems_version: !ruby/object:Gem::Requirement
298
297
  none: false
299
298
  requirements:
@@ -302,7 +301,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
302
301
  version: '0'
303
302
  segments:
304
303
  - 0
305
- hash: 3302802791356111510
304
+ hash: 3925858609207323185
306
305
  requirements: []
307
306
  rubyforge_project:
308
307
  rubygems_version: 1.8.24
@@ -1,11 +0,0 @@
1
- module Konacha
2
- module SpecsHelper
3
- def spec_include_tag(*specs)
4
- assets = specs.map do |spec|
5
- asset_paths.asset_for(spec.asset_name, "js").to_a
6
- end.flatten.map(&:logical_path).uniq
7
-
8
- javascript_include_tag *(assets << {:body => true, :debug => false})
9
- end
10
- end
11
- end