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.
- checksums.yaml +5 -5
- data/CHANGELOG.md +5 -0
- data/MIT.LICENSE +2 -2
- data/README.md +37 -28
- data/app/assets/javascripts/teaspoon/hook.coffee +1 -1
- data/app/assets/javascripts/teaspoon/teaspoon.coffee +13 -1
- data/app/controllers/teaspoon/suite_controller.rb +18 -13
- data/app/views/teaspoon/suite/index.html.erb +1 -1
- data/lib/generators/teaspoon/install/install_generator.rb +34 -34
- data/lib/generators/teaspoon/install/templates/MISSING_FRAMEWORK +1 -1
- data/lib/generators/teaspoon/install/templates/POST_INSTALL +1 -1
- data/lib/generators/teaspoon/install/templates/_boot.html.erb +1 -1
- data/lib/generators/teaspoon/install/templates/env_comments.rb.tt +8 -8
- data/lib/tasks/teaspoon/info.rake +1 -1
- data/lib/teaspoon/command_line.rb +76 -76
- data/lib/teaspoon/configuration.rb +4 -4
- data/lib/teaspoon/console.rb +40 -40
- data/lib/teaspoon/coverage.rb +29 -25
- data/lib/teaspoon/deprecated.rb +1 -1
- data/lib/teaspoon/driver.rb +0 -1
- data/lib/teaspoon/driver/browserstack.rb +48 -51
- data/lib/teaspoon/driver/phantomjs.rb +25 -25
- data/lib/teaspoon/driver/phantomjs/runner.js +31 -3
- data/lib/teaspoon/driver/selenium.rb +13 -9
- data/lib/teaspoon/engine.rb +26 -15
- data/lib/teaspoon/environment.rb +28 -28
- data/lib/teaspoon/exceptions.rb +7 -7
- data/lib/teaspoon/exporter.rb +23 -23
- data/lib/teaspoon/formatter/base.rb +64 -46
- data/lib/teaspoon/formatter/clean.rb +2 -2
- data/lib/teaspoon/formatter/documentation.rb +40 -40
- data/lib/teaspoon/formatter/dot.rb +12 -12
- data/lib/teaspoon/formatter/json.rb +21 -21
- data/lib/teaspoon/formatter/junit.rb +52 -52
- data/lib/teaspoon/formatter/modules/report_module.rb +34 -32
- data/lib/teaspoon/formatter/pride.rb +21 -21
- data/lib/teaspoon/formatter/rspec_html.rb +31 -31
- data/lib/teaspoon/formatter/snowday.rb +6 -5
- data/lib/teaspoon/formatter/swayze_or_oprah.rb +91 -91
- data/lib/teaspoon/formatter/tap.rb +29 -29
- data/lib/teaspoon/formatter/tap_y.rb +57 -57
- data/lib/teaspoon/formatter/teamcity.rb +63 -63
- data/lib/teaspoon/framework/base.rb +1 -1
- data/lib/teaspoon/instrumentation.rb +18 -18
- data/lib/teaspoon/registry.rb +8 -8
- data/lib/teaspoon/registry/has_default.rb +2 -2
- data/lib/teaspoon/runner.rb +37 -37
- data/lib/teaspoon/server.rb +30 -29
- data/lib/teaspoon/suite.rb +68 -57
- data/lib/teaspoon/utility.rb +6 -0
- data/lib/teaspoon/version.rb +1 -1
- metadata +10 -18
- 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(
|
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
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
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
|
data/lib/teaspoon/engine.rb
CHANGED
@@ -82,32 +82,32 @@ module Teaspoon
|
|
82
82
|
|
83
83
|
private
|
84
84
|
|
85
|
-
|
86
|
-
|
87
|
-
|
85
|
+
def self.using_phantomjs?
|
86
|
+
Teaspoon::Driver.matches?(Teaspoon.configuration.driver, :phantomjs)
|
87
|
+
end
|
88
88
|
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
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
|
104
|
-
if ActionView
|
105
|
-
require
|
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!(
|
110
|
-
path_options[:debug] = options[
|
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
|
data/lib/teaspoon/environment.rb
CHANGED
@@ -26,41 +26,41 @@ module Teaspoon
|
|
26
26
|
|
27
27
|
private
|
28
28
|
|
29
|
-
|
30
|
-
|
31
|
-
|
29
|
+
def self.find_env(override = nil)
|
30
|
+
override ||= ENV["TEASPOON_ENV"]
|
31
|
+
env_files = override && !override.empty? ? [override] : standard_environments
|
32
32
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
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
|
-
|
40
|
-
|
39
|
+
raise Teaspoon::EnvironmentNotFound.new(searched: env_files.join(", "))
|
40
|
+
end
|
41
41
|
|
42
|
-
|
43
|
-
|
44
|
-
|
42
|
+
def self.standard_environments
|
43
|
+
["spec/teaspoon_env.rb", "test/teaspoon_env.rb", "teaspoon_env.rb"]
|
44
|
+
end
|
45
45
|
|
46
|
-
|
47
|
-
|
48
|
-
|
46
|
+
def self.require_env(file)
|
47
|
+
::Kernel.load(file)
|
48
|
+
end
|
49
49
|
|
50
|
-
|
51
|
-
|
52
|
-
|
50
|
+
def self.rails_loaded?
|
51
|
+
!!defined?(Rails)
|
52
|
+
end
|
53
53
|
|
54
|
-
|
55
|
-
|
54
|
+
def self.load_rails
|
55
|
+
rails_env = ENV["TEASPOON_RAILS_ENV"] || File.expand_path("config/environment.rb", Teaspoon.root)
|
56
56
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
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
|
data/lib/teaspoon/exceptions.rb
CHANGED
@@ -2,13 +2,13 @@ module Teaspoon
|
|
2
2
|
class Error < StandardError
|
3
3
|
protected
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
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
|
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
|
data/lib/teaspoon/exporter.rb
CHANGED
@@ -20,33 +20,33 @@ module Teaspoon
|
|
20
20
|
|
21
21
|
private
|
22
22
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
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
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
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
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
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
|
-
|
44
|
-
|
45
|
-
|
43
|
+
def cleanup_output
|
44
|
+
FileUtils.rm_r(Dir["{.#{Teaspoon.configuration.mount_at},robots.txt.html}"])
|
45
|
+
end
|
46
46
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
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
|
-
|
89
|
+
def log_runner(_result); end
|
90
90
|
|
91
|
-
|
91
|
+
def log_suite(_result); end
|
92
92
|
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
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
|
-
|
99
|
+
def log_passing_spec(_result); end
|
100
100
|
|
101
|
-
|
101
|
+
def log_pending_spec(_result); end
|
102
102
|
|
103
|
-
|
103
|
+
def log_failing_spec(_result); end
|
104
104
|
|
105
|
-
|
105
|
+
def log_error(_result); end
|
106
106
|
|
107
|
-
|
107
|
+
def log_exception(_result); end
|
108
108
|
|
109
|
-
|
109
|
+
def log_console(_message); end
|
110
110
|
|
111
|
-
|
111
|
+
def log_result(_result); end
|
112
112
|
|
113
|
-
|
113
|
+
def log_coverage(_message); end
|
114
114
|
|
115
|
-
|
115
|
+
def log_threshold_failure(_message); end
|
116
116
|
|
117
|
-
|
117
|
+
def log_complete(_failure_count); end
|
118
118
|
|
119
119
|
private
|
120
120
|
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
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
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
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
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
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
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
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
|
-
|
143
|
-
|
144
|
-
|
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
|
-
|
147
|
-
|
149
|
+
params = String(uri.query).split("&").reject do |param|
|
150
|
+
RESERVED_PARAMS.include?(param.split("=").first)
|
151
|
+
end
|
148
152
|
|
149
|
-
|
150
|
-
|
153
|
+
filename = uri.path.sub(%r(^/assets/), "")
|
154
|
+
filename += "?#{params.join("&")}" if params.any?
|
155
|
+
filename
|
151
156
|
end
|
152
157
|
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
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
|
@@ -8,54 +8,54 @@ module Teaspoon
|
|
8
8
|
|
9
9
|
protected
|
10
10
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
11
|
+
def initialize(*args)
|
12
|
+
@level = 0
|
13
|
+
super
|
14
|
+
end
|
15
15
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
16
|
+
def log_suite(result)
|
17
|
+
log_indent_line(result.label, result.level)
|
18
|
+
@level = result.level
|
19
|
+
end
|
20
20
|
|
21
|
-
|
22
|
-
|
23
|
-
|
21
|
+
def log_passing_spec(result)
|
22
|
+
log_indent_spec(result.label, GREEN)
|
23
|
+
end
|
24
24
|
|
25
|
-
|
26
|
-
|
27
|
-
|
25
|
+
def log_pending_spec(result)
|
26
|
+
log_indent_spec("#{result.label} (PENDING)", YELLOW)
|
27
|
+
end
|
28
28
|
|
29
|
-
|
30
|
-
|
31
|
-
|
29
|
+
def log_failing_spec(result)
|
30
|
+
log_indent_spec("#{result.label} (FAILED - #{@failures.length})", RED)
|
31
|
+
end
|
32
32
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
33
|
+
def log_result(result)
|
34
|
+
log_line
|
35
|
+
super
|
36
|
+
end
|
37
37
|
|
38
38
|
private
|
39
39
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
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
|