teaspoon 1.1.3 → 1.2.2

Sign up to get free protection for your applications and to get access to all the features.
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