teaspoon 1.1.5 → 1.2.0

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 +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