teaspoon 1.1.3 → 1.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +47 -0
  3. data/MIT.LICENSE +2 -2
  4. data/README.md +56 -35
  5. data/app/assets/javascripts/teaspoon/hook.coffee +1 -1
  6. data/app/assets/javascripts/teaspoon/teaspoon.coffee +13 -1
  7. data/app/controllers/teaspoon/suite_controller.rb +18 -13
  8. data/app/views/teaspoon/suite/_boot.html.erb +1 -1
  9. data/app/views/teaspoon/suite/index.html.erb +1 -1
  10. data/lib/generators/teaspoon/install/install_generator.rb +34 -34
  11. data/lib/generators/teaspoon/install/templates/MISSING_FRAMEWORK +1 -1
  12. data/lib/generators/teaspoon/install/templates/POST_INSTALL +1 -1
  13. data/lib/generators/teaspoon/install/templates/env_comments.rb.tt +9 -7
  14. data/lib/tasks/teaspoon/info.rake +1 -1
  15. data/lib/teaspoon/command_line.rb +76 -76
  16. data/lib/teaspoon/configuration.rb +4 -4
  17. data/lib/teaspoon/console.rb +41 -40
  18. data/lib/teaspoon/coverage.rb +29 -25
  19. data/lib/teaspoon/deprecated.rb +1 -1
  20. data/lib/teaspoon/driver.rb +1 -1
  21. data/lib/teaspoon/driver/browserstack.rb +111 -0
  22. data/lib/teaspoon/driver/phantomjs.rb +25 -26
  23. data/lib/teaspoon/driver/phantomjs/runner.js +31 -3
  24. data/lib/teaspoon/driver/selenium.rb +13 -9
  25. data/lib/teaspoon/engine.rb +32 -27
  26. data/lib/teaspoon/environment.rb +28 -28
  27. data/lib/teaspoon/exceptions.rb +7 -7
  28. data/lib/teaspoon/exporter.rb +23 -23
  29. data/lib/teaspoon/formatter/base.rb +64 -46
  30. data/lib/teaspoon/formatter/clean.rb +2 -2
  31. data/lib/teaspoon/formatter/documentation.rb +40 -40
  32. data/lib/teaspoon/formatter/dot.rb +12 -12
  33. data/lib/teaspoon/formatter/json.rb +21 -21
  34. data/lib/teaspoon/formatter/junit.rb +52 -51
  35. data/lib/teaspoon/formatter/modules/report_module.rb +34 -32
  36. data/lib/teaspoon/formatter/pride.rb +21 -21
  37. data/lib/teaspoon/formatter/rspec_html.rb +31 -31
  38. data/lib/teaspoon/formatter/snowday.rb +6 -5
  39. data/lib/teaspoon/formatter/swayze_or_oprah.rb +91 -91
  40. data/lib/teaspoon/formatter/tap.rb +29 -29
  41. data/lib/teaspoon/formatter/tap_y.rb +57 -57
  42. data/lib/teaspoon/formatter/teamcity.rb +63 -63
  43. data/lib/teaspoon/framework/base.rb +1 -1
  44. data/lib/teaspoon/instrumentation.rb +18 -18
  45. data/lib/teaspoon/registry.rb +9 -9
  46. data/lib/teaspoon/registry/has_default.rb +2 -2
  47. data/lib/teaspoon/runner.rb +37 -37
  48. data/lib/teaspoon/server.rb +30 -29
  49. data/lib/teaspoon/suite.rb +68 -57
  50. data/lib/teaspoon/utility.rb +6 -0
  51. data/lib/teaspoon/version.rb +1 -1
  52. metadata +22 -15
  53. data/lib/teaspoon/driver/capybara_webkit.rb +0 -40
@@ -20,33 +20,33 @@ module Teaspoon
20
20
 
21
21
  private
22
22
 
23
- def executable
24
- return @executable if @executable
25
- @executable = which("wget")
26
- return @executable unless @executable.blank?
27
- raise Teaspoon::MissingDependencyError.new("Unable to locate `wget` for exporter.")
28
- end
23
+ def executable
24
+ return @executable if @executable
25
+ @executable = which("wget")
26
+ return @executable unless @executable.blank?
27
+ raise Teaspoon::MissingDependencyError.new("Unable to locate `wget` for exporter.")
28
+ end
29
29
 
30
- def create_export(path)
31
- Dir.chdir(path) do
32
- update_relative_paths
33
- cleanup_output
34
- move_output
30
+ def create_export(path)
31
+ Dir.chdir(path) do
32
+ update_relative_paths
33
+ cleanup_output
34
+ move_output
35
+ end
35
36
  end
36
- end
37
37
 
38
- def update_relative_paths
39
- html = File.read(".#{Teaspoon.configuration.mount_at}/#{@suite}.html")
40
- File.write("index.html", html.gsub!('"../', '"'))
41
- end
38
+ def update_relative_paths
39
+ html = File.read(".#{Teaspoon.configuration.mount_at}/#{@suite}.html")
40
+ File.write("index.html", html.gsub!('"../', '"'))
41
+ end
42
42
 
43
- def cleanup_output
44
- FileUtils.rm_r(Dir["{.#{Teaspoon.configuration.mount_at},robots.txt.html}"])
45
- end
43
+ def cleanup_output
44
+ FileUtils.rm_r(Dir["{.#{Teaspoon.configuration.mount_at},robots.txt.html}"])
45
+ end
46
46
 
47
- def move_output
48
- FileUtils.mkdir_p(@output_path)
49
- FileUtils.mv(Dir["*"], @output_path, force: true)
50
- end
47
+ def move_output
48
+ FileUtils.mkdir_p(@output_path)
49
+ FileUtils.mv(Dir["*"], @output_path, force: true)
50
+ end
51
51
  end
52
52
  end
@@ -7,7 +7,7 @@ module Teaspoon
7
7
 
8
8
  def initialize(suite_name = :default, output_file = nil)
9
9
  @suite_name = suite_name.to_s
10
- @output_file = output_file
10
+ @output_file = parse_output_file(output_file)
11
11
  @stdout = ""
12
12
  @suite = nil
13
13
  @last_suite = nil
@@ -86,74 +86,92 @@ module Teaspoon
86
86
 
87
87
  protected
88
88
 
89
- def log_runner(_result); end
89
+ def log_runner(_result); end
90
90
 
91
- def log_suite(_result); end
91
+ def log_suite(_result); end
92
92
 
93
- def log_spec(result)
94
- return log_passing_spec(result) if result.passing?
95
- return log_pending_spec(result) if result.pending?
96
- log_failing_spec(result)
97
- end
93
+ def log_spec(result)
94
+ return log_passing_spec(result) if result.passing?
95
+ return log_pending_spec(result) if result.pending?
96
+ log_failing_spec(result)
97
+ end
98
98
 
99
- def log_passing_spec(_result); end
99
+ def log_passing_spec(_result); end
100
100
 
101
- def log_pending_spec(_result); end
101
+ def log_pending_spec(_result); end
102
102
 
103
- def log_failing_spec(_result); end
103
+ def log_failing_spec(_result); end
104
104
 
105
- def log_error(_result); end
105
+ def log_error(_result); end
106
106
 
107
- def log_exception(_result); end
107
+ def log_exception(_result); end
108
108
 
109
- def log_console(_message); end
109
+ def log_console(_message); end
110
110
 
111
- def log_result(_result); end
111
+ def log_result(_result); end
112
112
 
113
- def log_coverage(_message); end
113
+ def log_coverage(_message); end
114
114
 
115
- def log_threshold_failure(_message); end
115
+ def log_threshold_failure(_message); end
116
116
 
117
- def log_complete(_failure_count); end
117
+ def log_complete(_failure_count); end
118
118
 
119
119
  private
120
120
 
121
- def log_str(str, color_code = nil)
122
- return log_to_file(str, @output_file) if @output_file
123
- STDOUT.print(color_code ? colorize(str, color_code) : str)
124
- end
121
+ def log_str(str, color_code = nil)
122
+ return log_to_file(str, @output_file) if @output_file
123
+ STDOUT.print(color_code ? colorize(str, color_code) : str)
124
+ end
125
125
 
126
- def log_line(str = "", color_code = nil)
127
- return log_to_file("#{str}\n", @output_file) if @output_file
128
- STDOUT.print("#{color_code ? colorize(str, color_code) : str}\n")
129
- end
126
+ def log_line(str = "", color_code = nil)
127
+ return log_to_file("#{str}\n", @output_file) if @output_file
128
+ STDOUT.print("#{color_code ? colorize(str, color_code) : str}\n")
129
+ end
130
130
 
131
- def log_to_file(str, output_file)
132
- @_output_file = File.open(output_file, "a") { |f| f.write(str) }
133
- rescue IOError => e
134
- raise Teaspoon::FileWriteError.new(e.message)
135
- end
131
+ def log_to_file(str, output_file)
132
+ @_output_file = File.open(output_file, "a") { |f| f.write(str) }
133
+ rescue IOError => e
134
+ raise Teaspoon::FileWriteError.new(e.message)
135
+ end
136
136
 
137
- def colorize(str, color_code)
138
- return str unless Teaspoon.configuration.color || @output_file
139
- "\e[#{color_code}m#{str}\e[0m"
140
- end
137
+ def colorize(str, color_code)
138
+ return str unless Teaspoon.configuration.color || @output_file
139
+ "\e[#{color_code}m#{str}\e[0m"
140
+ end
141
141
 
142
- def pluralize(str, value)
143
- value == 1 ? "#{value} #{str}" : "#{value} #{str}s"
144
- end
142
+ def pluralize(str, value)
143
+ value == 1 ? "#{value} #{str}" : "#{value} #{str}s"
144
+ end
145
+
146
+ def filename(file)
147
+ uri = URI(file)
145
148
 
146
- def filename(file)
147
- uri = URI(file)
149
+ params = String(uri.query).split("&").reject do |param|
150
+ RESERVED_PARAMS.include?(param.split("=").first)
151
+ end
148
152
 
149
- params = String(uri.query).split("&").reject do |param|
150
- RESERVED_PARAMS.include?(param.split("=").first)
153
+ filename = uri.path.sub(%r(^/assets/), "")
154
+ filename += "?#{params.join("&")}" if params.any?
155
+ filename
151
156
  end
152
157
 
153
- filename = uri.path.sub(%r(^/assets/), "")
154
- filename += "?#{params.join("&")}" if params.any?
155
- filename
156
- end
158
+ def parse_output_file(output)
159
+ return output unless output
160
+ output.gsub(/%{([^}]*)}/) { parse_output_capture($1) }
161
+ end
162
+
163
+ def parse_output_capture(cap)
164
+ case cap
165
+ when "suite_name"
166
+ @suite_name
167
+ when "date"
168
+ Time.now.to_i
169
+ else
170
+ warn ["Teaspoon::Formatter - Output File can only contain the placeholders %{suite_name} or %{date}.",
171
+ "%{#{cap}} is not supported and will be ignored."].join("\n")
172
+ ""
173
+ end
174
+ end
157
175
  end
158
176
  end
159
177
  end
@@ -5,8 +5,8 @@ module Teaspoon
5
5
  class Clean < Dot
6
6
  private
7
7
 
8
- def log_failed_examples
9
- end
8
+ def log_failed_examples
9
+ end
10
10
  end
11
11
  end
12
12
  end
@@ -8,54 +8,54 @@ module Teaspoon
8
8
 
9
9
  protected
10
10
 
11
- def initialize(*args)
12
- @level = 0
13
- super
14
- end
11
+ def initialize(*args)
12
+ @level = 0
13
+ super
14
+ end
15
15
 
16
- def log_suite(result)
17
- log_indent_line(result.label, result.level)
18
- @level = result.level
19
- end
16
+ def log_suite(result)
17
+ log_indent_line(result.label, result.level)
18
+ @level = result.level
19
+ end
20
20
 
21
- def log_passing_spec(result)
22
- log_indent_spec(result.label, GREEN)
23
- end
21
+ def log_passing_spec(result)
22
+ log_indent_spec(result.label, GREEN)
23
+ end
24
24
 
25
- def log_pending_spec(result)
26
- log_indent_spec("#{result.label} (PENDING)", YELLOW)
27
- end
25
+ def log_pending_spec(result)
26
+ log_indent_spec("#{result.label} (PENDING)", YELLOW)
27
+ end
28
28
 
29
- def log_failing_spec(result)
30
- log_indent_spec("#{result.label} (FAILED - #{@failures.length})", RED)
31
- end
29
+ def log_failing_spec(result)
30
+ log_indent_spec("#{result.label} (FAILED - #{@failures.length})", RED)
31
+ end
32
32
 
33
- def log_result(result)
34
- log_line
35
- super
36
- end
33
+ def log_result(result)
34
+ log_line
35
+ super
36
+ end
37
37
 
38
38
  private
39
39
 
40
- def log_indent_spec(str, color)
41
- log_indent_line(str, level = (@last_suite ? @level + 1 : 0), color)
42
- log_intent_stdout(level + 1)
43
- end
44
-
45
- def log_intent_stdout(level)
46
- return if @stdout.blank?
47
- log_indent_line("# #{@stdout.gsub(/\n$/, '').gsub("\n", "\n# ")}", level, CYAN)
48
- end
49
-
50
- def log_indent_line(str = "", level = nil, color = nil)
51
- log_line(indent(str, level || @level), color)
52
- end
53
-
54
- def indent(str = "", level = nil)
55
- indent = " " * (level * 2)
56
- str.gsub!("\n", "\n#{indent}")
57
- "#{indent}#{str}"
58
- end
40
+ def log_indent_spec(str, color)
41
+ log_indent_line(str, level = (@last_suite ? @level + 1 : 0), color)
42
+ log_intent_stdout(level + 1)
43
+ end
44
+
45
+ def log_intent_stdout(level)
46
+ return if @stdout.blank?
47
+ log_indent_line("# #{@stdout.gsub(/\n$/, '').gsub("\n", "\n# ")}", level, CYAN)
48
+ end
49
+
50
+ def log_indent_line(str = "", level = nil, color = nil)
51
+ log_line(indent(str, level || @level), color)
52
+ end
53
+
54
+ def indent(str = "", level = nil)
55
+ indent = " " * (level * 2)
56
+ str.gsub!("\n", "\n#{indent}")
57
+ "#{indent}#{str}"
58
+ end
59
59
  end
60
60
  end
61
61
  end
@@ -8,20 +8,20 @@ module Teaspoon
8
8
 
9
9
  protected
10
10
 
11
- def log_spec(result)
12
- return log_str(".", GREEN) if result.passing?
13
- return log_str("*", YELLOW) if result.pending?
14
- log_str("F", RED)
15
- end
11
+ def log_spec(result)
12
+ return log_str(".", GREEN) if result.passing?
13
+ return log_str("*", YELLOW) if result.pending?
14
+ log_str("F", RED)
15
+ end
16
16
 
17
- def log_console(message)
18
- log_str(message)
19
- end
17
+ def log_console(message)
18
+ log_str(message)
19
+ end
20
20
 
21
- def log_result(result)
22
- log_line("\n")
23
- super
24
- end
21
+ def log_result(result)
22
+ log_line("\n")
23
+ super
24
+ end
25
25
  end
26
26
  end
27
27
  end
@@ -5,33 +5,33 @@ module Teaspoon
5
5
  class Json < Base
6
6
  protected
7
7
 
8
- def log_runner(result)
9
- log_result(result)
10
- end
8
+ def log_runner(result)
9
+ log_result(result)
10
+ end
11
11
 
12
- def log_suite(result)
13
- log_result(result)
14
- end
12
+ def log_suite(result)
13
+ log_result(result)
14
+ end
15
15
 
16
- def log_spec(result)
17
- log_result(result)
18
- end
16
+ def log_spec(result)
17
+ log_result(result)
18
+ end
19
19
 
20
- def log_error(result)
21
- log_result(result)
22
- end
20
+ def log_error(result)
21
+ log_result(result)
22
+ end
23
23
 
24
- def log_exception(result)
25
- log_result(result)
26
- end
24
+ def log_exception(result)
25
+ log_result(result)
26
+ end
27
27
 
28
- def log_console(message)
29
- log_line(%{{"type":"console","log":"#{message.gsub(/\n$/, '').gsub('\n', '\\n')}"}})
30
- end
28
+ def log_console(message)
29
+ log_line(%{{"type":"console","log":"#{message.gsub(/\n$/, '').gsub('\n', '\\n')}"}})
30
+ end
31
31
 
32
- def log_result(result)
33
- log_str(result.original_json)
34
- end
32
+ def log_result(result)
33
+ log_str(result.original_json)
34
+ end
35
35
  end
36
36
  end
37
37
  end
@@ -6,74 +6,75 @@ module Teaspoon
6
6
  class Junit < Base
7
7
  protected
8
8
 
9
- def log_runner(result)
10
- log_line(%{<?xml version="1.0" encoding="UTF-8"?>})
11
- log_line(%{<testsuites name="Teaspoon">})
12
- log_line(%{<testsuite name="#{escape(@suite_name)}" tests="#{@total_count}" time="#{result.start}">})
13
- end
9
+ def log_runner(result)
10
+ log_line(%{<?xml version="1.0" encoding="UTF-8"?>})
11
+ log_line(%{<testsuites name="Teaspoon">})
12
+ start_time = Time.parse(result.start).iso8601
13
+ log_line(%{<testsuite name="#{escape(@suite_name)}" tests="#{@total_count}" timestamp="#{start_time}">})
14
+ end
14
15
 
15
- def log_suite(result)
16
- log_end_suite
17
- log_line(%{<testsuite name="#{escape(result.label)}">})
18
- end
16
+ def log_suite(result)
17
+ log_end_suite
18
+ log_line(%{<testsuite name="#{escape(result.label)}">})
19
+ end
19
20
 
20
- def log_passing_spec(result)
21
- log_junit_spec(suite: result.suite, label: result.label)
22
- end
21
+ def log_passing_spec(result)
22
+ log_junit_spec(suite: result.suite, label: result.label)
23
+ end
23
24
 
24
- def log_pending_spec(result)
25
- log_junit_spec(suite: result.suite, label: result.label) do
26
- log_line(%{ <skipped/>})
25
+ def log_pending_spec(result)
26
+ log_junit_spec(suite: result.suite, label: result.label) do
27
+ log_line(%{ <skipped/>})
28
+ end
27
29
  end
28
- end
29
30
 
30
- def log_failing_spec(result)
31
- log_junit_spec(suite: result.suite, label: result.label) do
32
- log_line(%{ <failure type="AssertionFailed">#{cdata(result.message)}</failure>})
31
+ def log_failing_spec(result)
32
+ log_junit_spec(suite: result.suite, label: result.label) do
33
+ log_line(%{ <failure type="AssertionFailed">#{cdata(result.message)}</failure>})
34
+ end
33
35
  end
34
- end
35
36
 
36
- def log_result(_result)
37
- log_end_suite
38
- end
37
+ def log_result(_result)
38
+ log_end_suite
39
+ end
39
40
 
40
- def log_coverage(message)
41
- properties = "<properties>#{cdata(message)}</properties>"
42
- log_line(%{<testsuite name="Coverage summary" tests="0">\n#{properties}\n</testsuite>})
43
- end
41
+ def log_coverage(message)
42
+ properties = "<properties>#{cdata(message)}</properties>"
43
+ log_line(%{<testsuite name="Coverage summary" tests="0">\n#{properties}\n</testsuite>})
44
+ end
44
45
 
45
- def log_threshold_failure(message)
46
- log_line(%{<testsuite name="Coverage thresholds" tests="1">})
47
- log_junit_spec(suite: "Coverage thresholds", label: "were not met") do
48
- log_line(%{ <failure type="AssertionFailed">#{cdata(message)}</failure>})
46
+ def log_threshold_failure(message)
47
+ log_line(%{<testsuite name="Coverage thresholds" tests="1">})
48
+ log_junit_spec(suite: "Coverage thresholds", label: "were not met") do
49
+ log_line(%{ <failure type="AssertionFailed">#{cdata(message)}</failure>})
50
+ end
51
+ log_line(%{</testsuite>})
49
52
  end
50
- log_line(%{</testsuite>})
51
- end
52
53
 
53
- def log_complete(_failure_count)
54
- log_line(%{</testsuite>\n</testsuites>})
55
- end
54
+ def log_complete(_failure_count)
55
+ log_line(%{</testsuite>\n</testsuites>})
56
+ end
56
57
 
57
58
  private
58
59
 
59
- def log_end_suite
60
- log_line(%{</testsuite>}) if @last_suite
61
- end
60
+ def log_end_suite
61
+ log_line(%{</testsuite>}) if @last_suite
62
+ end
62
63
 
63
- def log_junit_spec(opts, &_block)
64
- log_line(%{<testcase classname="#{escape(opts[:suite])}" name="#{escape(opts[:label])}">})
65
- yield if block_given?
66
- log_line(%{<system-out>#{cdata(@stdout)}</system-out>}) unless @stdout.blank?
67
- log_line(%{</testcase>})
68
- end
64
+ def log_junit_spec(opts, &_block)
65
+ log_line(%{<testcase classname="#{escape(opts[:suite])}" name="#{escape(opts[:label])}">})
66
+ yield if block_given?
67
+ log_line(%{<system-out>#{cdata(@stdout)}</system-out>}) unless @stdout.blank?
68
+ log_line(%{</testcase>})
69
+ end
69
70
 
70
- def escape(str)
71
- CGI::escapeHTML(str)
72
- end
71
+ def escape(str)
72
+ CGI.escapeHTML(str)
73
+ end
73
74
 
74
- def cdata(str)
75
- "\n<![CDATA[\n#{str.gsub(/\n$/, '')}\n]]>\n"
76
- end
75
+ def cdata(str)
76
+ "\n<![CDATA[\n#{str.gsub(/\n$/, '')}\n]]>\n"
77
+ end
77
78
  end
78
79
  end
79
80
  end