teaspoon 1.1.5 → 1.2.0

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 +5 -0
  3. data/MIT.LICENSE +2 -2
  4. data/README.md +37 -28
  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/index.html.erb +1 -1
  9. data/lib/generators/teaspoon/install/install_generator.rb +34 -34
  10. data/lib/generators/teaspoon/install/templates/MISSING_FRAMEWORK +1 -1
  11. data/lib/generators/teaspoon/install/templates/POST_INSTALL +1 -1
  12. data/lib/generators/teaspoon/install/templates/_boot.html.erb +1 -1
  13. data/lib/generators/teaspoon/install/templates/env_comments.rb.tt +8 -8
  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 +40 -40
  18. data/lib/teaspoon/coverage.rb +29 -25
  19. data/lib/teaspoon/deprecated.rb +1 -1
  20. data/lib/teaspoon/driver.rb +0 -1
  21. data/lib/teaspoon/driver/browserstack.rb +48 -51
  22. data/lib/teaspoon/driver/phantomjs.rb +25 -25
  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 +26 -15
  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 -52
  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 +8 -8
  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 +10 -18
  53. data/lib/teaspoon/driver/capybara_webkit.rb +0 -40
@@ -23,7 +23,10 @@ module Teaspoon
23
23
  end
24
24
 
25
25
  def run_specs(runner, url)
26
- driver = ::Selenium::WebDriver.for(driver_options[:client_driver])
26
+ driver = ::Selenium::WebDriver.for(
27
+ driver_options[:client_driver],
28
+ **driver_options[:selenium_options].to_hash.to_options
29
+ )
27
30
  driver.navigate.to(url)
28
31
 
29
32
  ::Selenium::WebDriver::Wait.new(driver_options).until do
@@ -39,14 +42,15 @@ module Teaspoon
39
42
 
40
43
  protected
41
44
 
42
- def driver_options
43
- @driver_options ||= HashWithIndifferentAccess.new(
44
- client_driver: :firefox,
45
- timeout: Teaspoon.configuration.driver_timeout.to_i,
46
- interval: 0.01,
47
- message: "Timed out"
48
- ).merge(@options)
49
- end
45
+ def driver_options
46
+ @driver_options ||= HashWithIndifferentAccess.new(
47
+ client_driver: :firefox,
48
+ timeout: Teaspoon.configuration.driver_timeout.to_i,
49
+ interval: 0.01,
50
+ message: "Timed out",
51
+ selenium_options: {}
52
+ ).merge(@options)
53
+ end
50
54
  end
51
55
  end
52
56
  end
@@ -82,32 +82,32 @@ module Teaspoon
82
82
 
83
83
  private
84
84
 
85
- def self.using_phantomjs?
86
- Teaspoon::Driver.matches?(Teaspoon.configuration.driver, :phantomjs)
87
- end
85
+ def self.using_phantomjs?
86
+ Teaspoon::Driver.matches?(Teaspoon.configuration.driver, :phantomjs)
87
+ end
88
88
 
89
- def self.render_exceptions_with_javascript
90
- ActionDispatch::DebugExceptions.class_eval do
91
- def render_exception(_env, exception)
92
- message = "#{exception.class.name}: #{exception.message}"
93
- body = "<script>throw Error(#{[message, exception.backtrace].join("\n").inspect})</script>"
94
- [200, { "Content-Type" => "text/html;", "Content-Length" => body.bytesize.to_s }, [body]]
89
+ def self.render_exceptions_with_javascript
90
+ ActionDispatch::DebugExceptions.class_eval do
91
+ def render_exception(_env, exception)
92
+ message = "#{exception.class.name}: #{exception.message}"
93
+ body = "<script>throw Error(#{[message, exception.backtrace].join("\n").inspect})</script>"
94
+ [200, { "Content-Type" => "text/html;", "Content-Length" => body.bytesize.to_s }, [body]]
95
+ end
95
96
  end
96
97
  end
97
- end
98
98
  end
99
99
  end
100
100
  end
101
101
 
102
102
  begin
103
- require 'action_view'
104
- if ActionView::VERSION::STRING >= '4.2.5'
105
- require 'action_view/helpers/asset_tag_helper'
103
+ require "action_view"
104
+ if ActionView.gem_version >= Gem::Version.new("4.2.5")
105
+ require "action_view/helpers/asset_tag_helper"
106
106
  module ActionView::Helpers::AssetTagHelper
107
107
  def javascript_include_tag(*sources)
108
108
  options = sources.extract_options!.stringify_keys
109
- path_options = options.extract!('protocol', 'extname', 'host').symbolize_keys
110
- path_options[:debug] = options['allow_non_precompiled']
109
+ path_options = options.extract!("protocol", "extname", "host").symbolize_keys
110
+ path_options[:debug] = options["allow_non_precompiled"]
111
111
  sources.uniq.map { |source|
112
112
  tag_options = {
113
113
  "src" => path_to_javascript(source, path_options)
@@ -119,3 +119,14 @@ begin
119
119
  end
120
120
  rescue
121
121
  end
122
+
123
+ # Some Sprockets patches to work with Sprockets 2.x
124
+ unless Sprockets::Asset.public_method_defined?(:filename)
125
+ module Sprockets
126
+ class Asset
127
+ def filename
128
+ pathname.to_s
129
+ end
130
+ end
131
+ end
132
+ end
@@ -26,41 +26,41 @@ module Teaspoon
26
26
 
27
27
  private
28
28
 
29
- def self.find_env(override = nil)
30
- override ||= ENV["TEASPOON_ENV"]
31
- env_files = override && !override.empty? ? [override] : standard_environments
29
+ def self.find_env(override = nil)
30
+ override ||= ENV["TEASPOON_ENV"]
31
+ env_files = override && !override.empty? ? [override] : standard_environments
32
32
 
33
- env_files.each do |filename|
34
- file = File.expand_path(filename, Dir.pwd)
35
- ENV["TEASPOON_ENV"] = file if override
36
- return file if File.exists?(file)
37
- end
33
+ env_files.each do |filename|
34
+ file = File.expand_path(filename, Teaspoon.root)
35
+ ENV["TEASPOON_ENV"] = file if override
36
+ return file if File.exist?(file)
37
+ end
38
38
 
39
- raise Teaspoon::EnvironmentNotFound.new(searched: env_files.join(", "))
40
- end
39
+ raise Teaspoon::EnvironmentNotFound.new(searched: env_files.join(", "))
40
+ end
41
41
 
42
- def self.standard_environments
43
- ["spec/teaspoon_env.rb", "test/teaspoon_env.rb", "teaspoon_env.rb"]
44
- end
42
+ def self.standard_environments
43
+ ["spec/teaspoon_env.rb", "test/teaspoon_env.rb", "teaspoon_env.rb"]
44
+ end
45
45
 
46
- def self.require_env(file)
47
- ::Kernel.load(file)
48
- end
46
+ def self.require_env(file)
47
+ ::Kernel.load(file)
48
+ end
49
49
 
50
- def self.rails_loaded?
51
- !!defined?(Rails)
52
- end
50
+ def self.rails_loaded?
51
+ !!defined?(Rails)
52
+ end
53
53
 
54
- def self.load_rails
55
- rails_env = ENV["TEASPOON_RAILS_ENV"] || File.expand_path("config/environment.rb", Dir.pwd)
54
+ def self.load_rails
55
+ rails_env = ENV["TEASPOON_RAILS_ENV"] || File.expand_path("config/environment.rb", Teaspoon.root)
56
56
 
57
- # Try to load rails, assume teaspoon_env will do it if the expected
58
- # environment isn't found.
59
- if File.exists?(rails_env)
60
- require rails_env
61
- else
62
- require_environment
57
+ # Try to load rails, assume teaspoon_env will do it if the expected
58
+ # environment isn't found.
59
+ if File.exist?(rails_env)
60
+ require rails_env
61
+ else
62
+ require_environment
63
+ end
63
64
  end
64
- end
65
65
  end
66
66
  end
@@ -2,13 +2,13 @@ module Teaspoon
2
2
  class Error < StandardError
3
3
  protected
4
4
 
5
- def build_message(msg_or_options)
6
- if msg_or_options.is_a?(String)
7
- msg_or_options
8
- else
9
- yield msg_or_options
5
+ def build_message(msg_or_options)
6
+ if msg_or_options.is_a?(String)
7
+ msg_or_options
8
+ else
9
+ yield msg_or_options
10
+ end
10
11
  end
11
- end
12
12
  end
13
13
 
14
14
  class Failure < Teaspoon::Error
@@ -29,7 +29,7 @@ module Teaspoon
29
29
  super(build_message(msg_or_options) do |options|
30
30
  msg = "Unknown framework: expected \"#{options[:name]}\" to be a registered framework. Available frameworks are #{options[:available]}."
31
31
  if options[:available].blank?
32
- msg += " Do you need to update your Gemfile to use the teaspoon-#{options[:name]} gem? If you are upgrading, please see https://github.com/modeset/teaspoon/blob/master/CHANGELOG.md"
32
+ msg + " Do you need to update your Gemfile to use the teaspoon-#{options[:name]} gem? If you are upgrading, please see https://github.com/jejacks0n/teaspoon/blob/master/CHANGELOG.md"
33
33
  end
34
34
  end)
35
35
  end
@@ -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