konacha 2.0.0.beta2 → 2.0.0.beta3

Sign up to get free protection for your applications and to get access to all the features.
data/History.md CHANGED
@@ -1,9 +1,11 @@
1
1
  # master
2
2
 
3
- * Run tests in an iframe, with `<body id="konacha">`
3
+ * Run tests in an iframe, with `<body id="konacha">`. Each test file is run in
4
+ isolation.
4
5
  * Removed support for konacha_config.js and Konacha.mochaOptions in favor of
5
6
  Mocha's own configuration methods. See the README for update instructions.
6
- * Update mocha (1.5.0)
7
+ * Update mocha (1.6.0) and chai (1.3.0)
8
+ * Adopt the RSpec reporter interface
7
9
 
8
10
  # 1.x-stable
9
11
 
data/LICENSE CHANGED
@@ -88,3 +88,28 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
88
88
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
89
89
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
90
90
  THE SOFTWARE.
91
+
92
+ Portions derived from RSpec (https://github.com/rspec/rspec-core)
93
+
94
+ Copyright (c) 2009 Chad Humphries, David Chelimsky
95
+ Copyright (c) 2006 David Chelimsky, The RSpec Development Team
96
+ Copyright (c) 2005 Steven Baker
97
+
98
+ Permission is hereby granted, free of charge, to any person obtaining
99
+ a copy of this software and associated documentation files (the
100
+ "Software"), to deal in the Software without restriction, including
101
+ without limitation the rights to use, copy, modify, merge, publish,
102
+ distribute, sublicense, and/or sell copies of the Software, and to
103
+ permit persons to whom the Software is furnished to do so, subject to
104
+ the following conditions:
105
+
106
+ The above copyright notice and this permission notice shall be
107
+ included in all copies or substantial portions of the Software.
108
+
109
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
110
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
111
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
112
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
113
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
114
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
115
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md CHANGED
@@ -112,6 +112,23 @@ $ bundle exec rake konacha:run SPEC=foo_spec
112
112
  $ bundle exec rake konacha:run SPEC=foo_spec,bar_spec,etc_spec
113
113
  ```
114
114
 
115
+ Konacha includes a default formatter modeled upon RSpec's ProgressFormatter.
116
+ Additionally, Konacha's runner implements the same protocol as RSpec, so many
117
+ RSpec formatters also work with Konacha.
118
+
119
+ To specify one or more formatters, provide a comma separated list of class names
120
+ in the `FORMAT` environment variable. For example, you can run both Ruby and JavaScript
121
+ specs with CI integration using [ci_reporter](https://github.com/nicksieger/ci_reporter):
122
+
123
+ ```
124
+ $ bundle exec rake ci:setup:rspec spec konacha:run FORMAT=CI::Reporter::RSpec
125
+ ```
126
+
127
+ You will need to `require` any formatters you use. It's a good idea to do this
128
+ within a `defined?` check in your [Konacha initializer](#configuration).
129
+
130
+ To automatically trigger reruns when files change, try [guard-konacha](https://github.com/alexgb/guard-konacha).
131
+
115
132
  ## Spec Helper
116
133
 
117
134
  Since Konacha integrates with the asset pipeline, using setup helpers in your specs is
@@ -232,8 +249,13 @@ describe("templating", function() {
232
249
 
233
250
  As of Konacha 2.0, each test file is run inside an isolated iframe. For
234
251
  compatibility with Konacha 1.x, the iframe's `<body>` element will have
235
- `id="konacha"` set on it. If your specs are already self-contained, you may be
236
- able to upgrade without any changes to your test code.
252
+ `id="konacha"` set on it.
253
+
254
+ Previously, all test files would run in the same environment. Thus, if only
255
+ one test file pulled in an external library, all tests would be able to use
256
+ it. Now test files are run in isolation. If you encounter an undefined
257
+ JavaScript module in your test, you may be missing an explicit `//= require`
258
+ call somewhere.
237
259
 
238
260
  ### Options
239
261
 
@@ -4,7 +4,8 @@ window.onload = function () {
4
4
  if (!iframes[i].contentWindow.mocha) {
5
5
  (function (path) {
6
6
  mocha.suite.addTest(new Mocha.Test(path, function () {
7
- throw new Error("Failed to load " + path + ". Perhaps it failed to compile?");
7
+ throw new Error("Failed to load " + path + ".\n" +
8
+ "Perhaps it failed to compile? Check the rake output for errors.");
8
9
  }));
9
10
  })(iframes[i].getAttribute("data-path"));
10
11
  }
@@ -1,45 +1,70 @@
1
1
  Konacha = {
2
- dots: "",
3
- getResults: function() {
4
- return JSON.stringify(Konacha.results);
2
+ getEvents: function() {
3
+ return JSON.stringify(Konacha.events);
5
4
  }
6
5
  };
7
6
 
8
7
  mocha.reporter(function(runner) {
8
+ var createTestObject = function(test, status) {
9
+ var obj = {
10
+ title:test.title,
11
+ fullTitle:test.fullTitle(),
12
+ duration:test.duration,
13
+ parentFullTitle:test.parent.fullTitle(),
14
+ status:status
15
+ };
16
+
17
+ if (status == "failed")
18
+ obj.error = test.err; // Contains message, expected, actual, operator, stack
19
+
20
+ return obj;
21
+ };
22
+
23
+ var createSuiteObject = function(suite) {
24
+ var obj = {
25
+ title:suite.title,
26
+ fullTitle:suite.fullTitle()
27
+ };
28
+
29
+ if (suite.parent)
30
+ obj.parentFullTitle = suite.parent.fullTitle();
31
+
32
+ return obj;
33
+ };
34
+
9
35
  Mocha.reporters.Base.call(this, runner);
10
36
 
11
37
  runner.on('start', function() {
12
- Konacha.results = [];
38
+ Konacha.events = [];
39
+ });
40
+
41
+ runner.on('suite', function(suite) {
42
+ if (suite.fullTitle() && suite.fullTitle().length > 0)
43
+ Konacha.events.push({event:'suite', data:createSuiteObject(suite), type:'suite'});
44
+ });
45
+
46
+ runner.on('test', function(test) {
47
+ Konacha.events.push({event:'test', data:createTestObject(test), type:'test'});
13
48
  });
14
49
 
15
50
  runner.on('pass', function(test) {
16
- Konacha.dots += ".";
17
- Konacha.results.push({
18
- name:test.title,
19
- passed:true
20
- });
51
+ Konacha.events.push({event:'pass', data:createTestObject(test, "passed"), type:'test'});
21
52
  });
22
53
 
23
54
  runner.on('fail', function(test) {
24
- Konacha.dots += "F";
25
- Konacha.results.push({
26
- name:test.title,
27
- passed:false,
28
- message:test.err.message,
29
- trace:test.err.stack
30
- });
55
+ Konacha.events.push({event:'fail', data:createTestObject(test, "failed"), type:'test'});
31
56
  });
32
57
 
33
58
  runner.on('pending', function(test) {
34
- Konacha.dots += "P";
35
- Konacha.results.push({
36
- name:test.title,
37
- passed:false,
38
- pending:true
39
- });
59
+ Konacha.events.push({event:'pending', data:createTestObject(test, "pending"), type:'test'});
60
+ });
61
+
62
+ runner.on('suite end', function(suite) {
63
+ if (suite.fullTitle() && suite.fullTitle().length > 0)
64
+ Konacha.events.push({event:'suite end', data:createSuiteObject(suite), type:'suite'});
40
65
  });
41
66
 
42
67
  runner.on('end', function() {
43
- Konacha.done = true;
68
+ Konacha.events.push({event:'end', data:{}});
44
69
  });
45
70
  });
@@ -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.beta2"
20
+ gem.version = "2.0.0.beta3"
21
21
 
22
22
  gem.add_dependency "railties", "~> 3.1"
23
23
  gem.add_dependency "actionpack", "~> 3.1"
@@ -2,6 +2,8 @@ require "tilt"
2
2
  require "konacha/engine"
3
3
  require "konacha/runner"
4
4
  require "konacha/server"
5
+ require "konacha/reporter"
6
+ require "konacha/formatter"
5
7
 
6
8
  module Konacha
7
9
  class << self
@@ -32,6 +32,7 @@ module Konacha
32
32
  options.application ||= self.class.application(app)
33
33
  options.driver ||= :selenium
34
34
  options.stylesheets ||= %w(application)
35
+ options.verbose ||= false
35
36
 
36
37
  app.config.assets.paths << app.root.join(options.spec_dir).to_s
37
38
  end
@@ -0,0 +1,80 @@
1
+ require "colorize"
2
+
3
+ module Konacha
4
+ class Formatter
5
+ attr_reader :io, :examples
6
+
7
+ def initialize(io)
8
+ @io = io
9
+ @examples = []
10
+ end
11
+
12
+ def start(expected_example_count=nil); end
13
+ def example_group_started(group); end
14
+ def example_started(example); end
15
+
16
+ def example_passed(example)
17
+ @examples << example
18
+ io.write(".".green)
19
+ end
20
+
21
+ def example_failed(example)
22
+ @examples << example
23
+ io.write("F".red)
24
+ end
25
+
26
+ def example_pending(example)
27
+ @examples << example
28
+ io.write("P".yellow)
29
+ end
30
+
31
+ def example_group_finished(group); end
32
+ def stop; end
33
+
34
+ def start_dump
35
+ io.puts ""
36
+ end
37
+
38
+ def dump_pending
39
+ pending_examples = examples.select(&:pending?)
40
+ if pending_examples.present?
41
+ io.puts ""
42
+ io.puts(pending_examples.map {|example| pending_message(example)}.join("\n\n"))
43
+ end
44
+ end
45
+
46
+ def dump_failures
47
+ failed_examples = examples.select(&:failed?)
48
+ if failed_examples.present?
49
+ io.puts ""
50
+ io.puts(failed_examples.map {|example| failure_message(example)}.join("\n\n"))
51
+ end
52
+ end
53
+
54
+ def dump_summary(duration, example_count, failure_count, pending_count)
55
+ seconds = "%.2f" % duration
56
+ io.puts ""
57
+ io.puts "Finished in #{seconds} seconds"
58
+ io.puts "#{example_count} examples, #{failure_count} failed, #{pending_count} pending"
59
+ end
60
+
61
+ def seed(seed); end
62
+
63
+ def close
64
+ io.close if IO === io && io != $stdout
65
+ end
66
+
67
+ private
68
+ def failure_message(example)
69
+ msg = []
70
+ msg << " Failed: #{example.full_description}"
71
+ msg << " #{example.exception.message}"
72
+ msg << " in #{example.exception.backtrace.first}" if example.exception.backtrace.present?
73
+ msg.join("\n").red
74
+ end
75
+
76
+ def pending_message(example)
77
+ " Pending: #{example.full_description}".yellow
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,91 @@
1
+ require "konacha/reporter/example"
2
+ require "konacha/reporter/example_group"
3
+
4
+ # The Konacha Reporter implements the same protocol as the RSpec Reporter.
5
+ # More details on the RSpec Reporter protocol are available in the rspec-core
6
+ # repository: https://github.com/rspec/rspec-core/blob/1852a7f4221c5731e108484cb2debfbaca60b283/lib/rspec/core/formatters/base_formatter.rb#L8-L25
7
+
8
+ module Konacha
9
+ class Reporter
10
+ EVENT_CONVERSIONS = {
11
+ 'suite' => :example_group_started,
12
+ 'test' => :example_started,
13
+ 'pass' => :example_passed,
14
+ 'fail' => :example_failed,
15
+ 'pending' => :example_pending,
16
+ 'suite end' => :example_group_finished,
17
+ }
18
+
19
+ attr_reader :start_time, :duration, :example_count, :failure_count, :pending_count
20
+
21
+ def initialize(*formatters)
22
+ @formatters = formatters
23
+ @example_count = @failure_count = @pending_count = 0
24
+ @duration = @start_time = nil
25
+ @examples, @groups = {}, {}
26
+ end
27
+
28
+ def start(expected_example_count=nil)
29
+ @start_time = Time.now
30
+ process_event :start, expected_example_count
31
+ end
32
+
33
+ def finish(seed=nil)
34
+ begin
35
+ stop
36
+ process_event :start_dump
37
+ process_event :dump_pending
38
+ process_event :dump_failures
39
+ process_event :dump_summary, @duration, @example_count, @failure_count, @pending_count
40
+ process_event :seed, seed if seed
41
+ ensure
42
+ process_event :close
43
+ end
44
+ end
45
+
46
+ def stop
47
+ @duration = Time.now - @start_time if @start_time
48
+ process_event :stop
49
+ end
50
+
51
+ def passed?
52
+ @examples.values.all? { |example| example.passed? || example.pending? }
53
+ end
54
+
55
+ def process_mocha_event(event)
56
+ if event['type']
57
+ object = update_or_create_object(event['data'], event['type'])
58
+ process_event EVENT_CONVERSIONS[event['event']], object
59
+ end
60
+ end
61
+
62
+ def process_event(method, *args, &block)
63
+ case method
64
+ when :example_started
65
+ @example_count += 1
66
+ when :example_failed
67
+ @failure_count += 1
68
+ when :example_pending
69
+ @pending_count += 1
70
+ end
71
+
72
+ @formatters.each do |formatter|
73
+ formatter.send method, *args, &block
74
+ end
75
+ end
76
+
77
+ def update_or_create_object(data, type)
78
+ collection = type == 'test' ? @examples : @groups
79
+ object = collection[data['fullTitle']]
80
+ if object
81
+ object.update_metadata(data)
82
+ else
83
+ klass = type == 'test' ? Example : ExampleGroup
84
+ parent = @groups[data['parentFullTitle']]
85
+ object = collection[data['fullTitle']] = klass.new(data, parent)
86
+ end
87
+
88
+ object
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,34 @@
1
+ require "konacha/reporter/metadata"
2
+
3
+ # The Example class mimics the public interface of RSpec::Core::Example.
4
+
5
+ module Konacha
6
+ class Reporter
7
+ class Example
8
+ attr_reader :metadata, :parent
9
+
10
+ def initialize(data, parent)
11
+ @metadata = Metadata.new(data)
12
+ @parent = parent
13
+ end
14
+
15
+ delegate :full_description, :description, :location, :file_path, :line_number, :pending, :pending_message, :exception, :execution_result, :to => :metadata
16
+
17
+ alias_method :pending?, :pending
18
+ alias_method :options, :metadata
19
+ alias_method :example_group, :parent
20
+
21
+ def passed?
22
+ execution_result[:status] == "passed"
23
+ end
24
+
25
+ def failed?
26
+ execution_result[:status] == "failed"
27
+ end
28
+
29
+ def update_metadata(data)
30
+ metadata.update(data)
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,37 @@
1
+ require "konacha/reporter/metadata"
2
+
3
+ # The ExampleGroup class mimics the public interface of RSpec::Core::ExampleGroup.
4
+
5
+ module Konacha
6
+ class Reporter
7
+ class ExampleGroup
8
+ attr_reader :metadata, :parent
9
+
10
+ def initialize(data, parent)
11
+ @metadata = Metadata.new(data)
12
+ @parent = parent
13
+ end
14
+
15
+ delegate :full_description, :description, :file_path, :described_class, :to => :metadata
16
+
17
+ alias_method :display_name, :description
18
+
19
+ def parent_groups
20
+ ancestor = parent
21
+ groups = []
22
+ while ancestor
23
+ groups << ancestor
24
+ ancestor = ancestor.parent
25
+ end
26
+
27
+ groups
28
+ end
29
+
30
+ alias_method :ancestors, :parent_groups
31
+
32
+ def update_metadata(data)
33
+ metadata.update(data)
34
+ end
35
+ end
36
+ end
37
+ end