cucumber 3.1.2 → 8.0.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 +1880 -1146
- data/CONTRIBUTING.md +220 -61
- data/README.md +143 -22
- data/bin/cucumber +1 -1
- data/lib/autotest/cucumber_mixin.rb +49 -53
- data/lib/autotest/discover.rb +3 -2
- data/lib/cucumber/cli/configuration.rb +32 -7
- data/lib/cucumber/cli/main.rb +16 -15
- data/lib/cucumber/cli/options.rb +111 -79
- data/lib/cucumber/cli/profile_loader.rb +45 -26
- data/lib/cucumber/cli/rerun_file.rb +1 -1
- data/lib/cucumber/configuration.rb +47 -31
- data/lib/cucumber/constantize.rb +3 -6
- data/lib/cucumber/deprecate.rb +32 -7
- data/lib/cucumber/errors.rb +5 -7
- data/lib/cucumber/events/envelope.rb +9 -0
- data/lib/cucumber/events/gherkin_source_parsed.rb +11 -0
- data/lib/cucumber/events/hook_test_step_created.rb +12 -0
- data/lib/cucumber/events/step_activated.rb +0 -5
- data/lib/cucumber/events/step_definition_registered.rb +0 -5
- data/lib/cucumber/events/test_case_created.rb +12 -0
- data/lib/cucumber/events/test_case_ready.rb +12 -0
- data/lib/cucumber/events/test_run_finished.rb +2 -1
- data/lib/cucumber/events/test_step_created.rb +12 -0
- data/lib/cucumber/events/undefined_parameter_type.rb +9 -0
- data/lib/cucumber/events.rb +15 -8
- data/lib/cucumber/file_specs.rb +8 -7
- data/lib/cucumber/filters/activate_steps.rb +6 -3
- data/lib/cucumber/filters/broadcast_test_case_ready_event.rb +12 -0
- data/lib/cucumber/filters/prepare_world.rb +5 -9
- data/lib/cucumber/filters/quit.rb +1 -3
- data/lib/cucumber/filters/tag_limits/verifier.rb +3 -7
- data/lib/cucumber/filters/tag_limits.rb +1 -3
- data/lib/cucumber/filters.rb +1 -0
- data/lib/cucumber/formatter/ansicolor.rb +74 -86
- data/lib/cucumber/formatter/ast_lookup.rb +163 -0
- data/lib/cucumber/formatter/backtrace_filter.rb +10 -7
- data/lib/cucumber/formatter/console.rb +76 -68
- data/lib/cucumber/formatter/console_counts.rb +4 -9
- data/lib/cucumber/formatter/console_issues.rb +12 -4
- data/lib/cucumber/formatter/duration.rb +1 -1
- data/lib/cucumber/formatter/duration_extractor.rb +4 -1
- data/lib/cucumber/formatter/errors.rb +7 -0
- data/lib/cucumber/formatter/fanout.rb +3 -1
- data/lib/cucumber/formatter/html.rb +11 -598
- data/lib/cucumber/formatter/http_io.rb +152 -0
- data/lib/cucumber/formatter/ignore_missing_messages.rb +2 -2
- data/lib/cucumber/formatter/interceptor.rb +11 -30
- data/lib/cucumber/formatter/io.rb +57 -13
- data/lib/cucumber/formatter/json.rb +119 -124
- data/lib/cucumber/formatter/junit.rb +75 -55
- data/lib/cucumber/formatter/message.rb +23 -0
- data/lib/cucumber/formatter/message_builder.rb +256 -0
- data/lib/cucumber/formatter/pretty.rb +370 -153
- data/lib/cucumber/formatter/progress.rb +31 -32
- data/lib/cucumber/formatter/publish_banner_printer.rb +77 -0
- data/lib/cucumber/formatter/query/hook_by_test_step.rb +32 -0
- data/lib/cucumber/formatter/query/pickle_by_test.rb +26 -0
- data/lib/cucumber/formatter/query/pickle_step_by_test_step.rb +26 -0
- data/lib/cucumber/formatter/query/step_definitions_by_test_step.rb +40 -0
- data/lib/cucumber/formatter/query/test_case_started_by_test_case.rb +42 -0
- data/lib/cucumber/formatter/rerun.rb +24 -4
- data/lib/cucumber/formatter/stepdefs.rb +1 -2
- data/lib/cucumber/formatter/steps.rb +8 -6
- data/lib/cucumber/formatter/summary.rb +17 -8
- data/lib/cucumber/formatter/unicode.rb +18 -20
- data/lib/cucumber/formatter/url_reporter.rb +17 -0
- data/lib/cucumber/formatter/usage.rb +18 -15
- data/lib/cucumber/gherkin/data_table_parser.rb +18 -6
- data/lib/cucumber/gherkin/formatter/ansi_escapes.rb +14 -18
- data/lib/cucumber/gherkin/formatter/escaping.rb +2 -2
- data/lib/cucumber/gherkin/steps_parser.rb +17 -8
- data/lib/cucumber/glue/dsl.rb +29 -15
- data/lib/cucumber/glue/hook.rb +37 -11
- data/lib/cucumber/glue/invoke_in_world.rb +17 -22
- data/lib/cucumber/glue/proto_world.rb +47 -53
- data/lib/cucumber/glue/registry_and_more.rb +62 -17
- data/lib/cucumber/glue/registry_wrapper.rb +31 -0
- data/lib/cucumber/glue/snippet.rb +23 -22
- data/lib/cucumber/glue/step_definition.rb +48 -23
- data/lib/cucumber/glue/world_factory.rb +1 -1
- data/lib/cucumber/hooks.rb +12 -11
- data/lib/cucumber/multiline_argument/data_table/diff_matrices.rb +4 -3
- data/lib/cucumber/multiline_argument/data_table.rb +143 -123
- data/lib/cucumber/multiline_argument/doc_string.rb +1 -1
- data/lib/cucumber/multiline_argument.rb +4 -6
- data/lib/cucumber/platform.rb +5 -5
- data/lib/cucumber/rake/task.rb +34 -25
- data/lib/cucumber/rspec/disable_option_parser.rb +15 -11
- data/lib/cucumber/rspec/doubles.rb +3 -5
- data/lib/cucumber/running_test_case.rb +3 -53
- data/lib/cucumber/runtime/after_hooks.rb +8 -4
- data/lib/cucumber/runtime/before_hooks.rb +8 -4
- data/lib/cucumber/runtime/for_programming_languages.rb +4 -2
- data/lib/cucumber/runtime/meta_message_builder.rb +106 -0
- data/lib/cucumber/runtime/step_hooks.rb +6 -2
- data/lib/cucumber/runtime/support_code.rb +16 -15
- data/lib/cucumber/runtime/user_interface.rb +10 -19
- data/lib/cucumber/runtime.rb +78 -76
- data/lib/cucumber/step_definition_light.rb +4 -3
- data/lib/cucumber/step_definitions.rb +2 -2
- data/lib/cucumber/step_match.rb +17 -20
- data/lib/cucumber/step_match_search.rb +5 -3
- data/lib/cucumber/term/ansicolor.rb +72 -48
- data/lib/cucumber/term/banner.rb +57 -0
- data/lib/cucumber/version +1 -1
- data/lib/cucumber.rb +3 -2
- data/lib/simplecov_setup.rb +1 -1
- metadata +279 -81
- data/lib/cucumber/core_ext/string.rb +0 -11
- data/lib/cucumber/events/gherkin_source_parsed.rb~ +0 -14
- data/lib/cucumber/formatter/ast_lookup.rb~ +0 -9
- data/lib/cucumber/formatter/cucumber.css +0 -286
- data/lib/cucumber/formatter/cucumber.sass +0 -247
- data/lib/cucumber/formatter/hook_query_visitor.rb +0 -42
- data/lib/cucumber/formatter/html_builder.rb +0 -121
- data/lib/cucumber/formatter/inline-js.js +0 -30
- data/lib/cucumber/formatter/jquery-min.js +0 -154
- data/lib/cucumber/formatter/json_pretty.rb +0 -11
- data/lib/cucumber/formatter/legacy_api/adapter.rb +0 -1028
- data/lib/cucumber/formatter/legacy_api/ast.rb +0 -394
- data/lib/cucumber/formatter/legacy_api/results.rb +0 -50
- data/lib/cucumber/formatter/legacy_api/runtime_facade.rb +0 -32
- data/lib/cucumber/step_argument.rb +0 -25
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
# rubocop:disable Metrics/ModuleLength
|
4
|
+
|
3
5
|
require 'cucumber/formatter/ansicolor'
|
4
6
|
require 'cucumber/formatter/duration'
|
5
7
|
require 'cucumber/gherkin/i18n'
|
@@ -32,7 +34,7 @@ module Cucumber
|
|
32
34
|
|
33
35
|
def format_step(keyword, step_match, status, source_indent)
|
34
36
|
comment = if source_indent
|
35
|
-
c = (
|
37
|
+
c = indent("# #{step_match.location}", source_indent)
|
36
38
|
format_string(c, :comment)
|
37
39
|
else
|
38
40
|
''
|
@@ -46,7 +48,7 @@ module Cucumber
|
|
46
48
|
def format_string(o, status)
|
47
49
|
fmt = format_for(status)
|
48
50
|
o.to_s.split("\n").map do |line|
|
49
|
-
if Proc
|
51
|
+
if Proc == fmt.class
|
50
52
|
fmt.call(line)
|
51
53
|
else
|
52
54
|
fmt % line
|
@@ -54,10 +56,6 @@ module Cucumber
|
|
54
56
|
end.join("\n")
|
55
57
|
end
|
56
58
|
|
57
|
-
def print_steps(status)
|
58
|
-
print_elements(runtime.steps(status), status, 'steps')
|
59
|
-
end
|
60
|
-
|
61
59
|
def print_elements(elements, status, kind)
|
62
60
|
return if elements.empty?
|
63
61
|
|
@@ -101,36 +99,43 @@ module Cucumber
|
|
101
99
|
@io.puts(format_string(string, status))
|
102
100
|
end
|
103
101
|
|
104
|
-
def exception_message_string(e,
|
102
|
+
def exception_message_string(e, indent_amount)
|
105
103
|
message = "#{e.message} (#{e.class})".dup.force_encoding('UTF-8')
|
106
104
|
message = linebreaks(message, ENV['CUCUMBER_TRUNCATE_OUTPUT'].to_i)
|
107
105
|
|
108
|
-
"#{message}\n#{e.backtrace.join("\n")}"
|
106
|
+
indent("#{message}\n#{e.backtrace.join("\n")}", indent_amount)
|
109
107
|
end
|
110
108
|
|
111
109
|
# http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/10655
|
112
|
-
def linebreaks(
|
113
|
-
return
|
114
|
-
|
110
|
+
def linebreaks(msg, max)
|
111
|
+
return msg unless max && max > 0
|
112
|
+
|
113
|
+
msg.gsub(/.{1,#{max}}(?:\s|\Z)/) do
|
114
|
+
(Regexp.last_match(0) + 5.chr).gsub(/\n\005/, "\n").gsub(/\005/, "\n")
|
115
|
+
end.rstrip
|
115
116
|
end
|
116
117
|
|
117
|
-
def collect_snippet_data(test_step,
|
118
|
+
def collect_snippet_data(test_step, ast_lookup)
|
118
119
|
# collect snippet data for undefined steps
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
120
|
+
keyword = ast_lookup.snippet_step_keyword(test_step)
|
121
|
+
@snippets_input << Console::SnippetData.new(keyword, test_step)
|
122
|
+
end
|
123
|
+
|
124
|
+
def collect_undefined_parameter_type_names(undefined_parameter_type)
|
125
|
+
@undefined_parameter_types << undefined_parameter_type.type_name
|
124
126
|
end
|
125
127
|
|
126
128
|
def print_snippets(options)
|
127
129
|
return unless options[:snippets]
|
128
|
-
return if runtime.steps(:undefined).empty?
|
129
130
|
|
130
131
|
snippet_text_proc = lambda do |step_keyword, step_name, multiline_arg|
|
131
|
-
|
132
|
+
snippet_text(step_keyword, step_name, multiline_arg)
|
133
|
+
end
|
134
|
+
do_print_snippets(snippet_text_proc) unless @snippets_input.empty?
|
135
|
+
|
136
|
+
@undefined_parameter_types.map do |type_name|
|
137
|
+
do_print_undefined_parameter_type_snippet(type_name)
|
132
138
|
end
|
133
|
-
do_print_snippets(snippet_text_proc)
|
134
139
|
end
|
135
140
|
|
136
141
|
def do_print_snippets(snippet_text_proc)
|
@@ -146,10 +151,15 @@ module Cucumber
|
|
146
151
|
@io.flush
|
147
152
|
end
|
148
153
|
|
149
|
-
def print_passing_wip(
|
150
|
-
return unless
|
151
|
-
|
152
|
-
|
154
|
+
def print_passing_wip(config, passed_test_cases, ast_lookup)
|
155
|
+
return unless config.wip?
|
156
|
+
|
157
|
+
messages = passed_test_cases.map do |test_case|
|
158
|
+
scenario_source = ast_lookup.scenario_source(test_case)
|
159
|
+
keyword = scenario_source.type == :Scenario ? scenario_source.scenario.keyword : scenario_source.scenario_outline.keyword
|
160
|
+
linebreaks("#{test_case.location.on_line(test_case.location.lines.max)}:in `#{keyword}: #{test_case.name}'", ENV['CUCUMBER_TRUNCATE_OUTPUT'].to_i)
|
161
|
+
end
|
162
|
+
do_print_passing_wip(messages)
|
153
163
|
end
|
154
164
|
|
155
165
|
def do_print_passing_wip(passed_messages)
|
@@ -161,59 +171,57 @@ module Cucumber
|
|
161
171
|
end
|
162
172
|
end
|
163
173
|
|
164
|
-
def
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
# define @delayed_messages = [] in your Formatter if you want to
|
169
|
-
# activate this feature
|
170
|
-
def puts(*messages)
|
171
|
-
if @delayed_messages
|
172
|
-
@delayed_messages += messages
|
173
|
-
else
|
174
|
-
if @io
|
175
|
-
@io.puts
|
176
|
-
messages.each do |message|
|
177
|
-
@io.puts(format_string(message, :tag))
|
178
|
-
end
|
179
|
-
@io.flush
|
180
|
-
end
|
181
|
-
end
|
182
|
-
end
|
183
|
-
|
184
|
-
def print_messages
|
185
|
-
@delayed_messages.each { |message| print_message(message) }
|
186
|
-
empty_messages
|
187
|
-
end
|
174
|
+
def attach(src, media_type)
|
175
|
+
return unless media_type == 'text/x.cucumber.log+plain'
|
176
|
+
return unless @io
|
188
177
|
|
189
|
-
|
190
|
-
|
191
|
-
@io.print(format_string(@delayed_messages.join(', '), :tag).indent(2))
|
192
|
-
@io.flush
|
193
|
-
empty_messages
|
194
|
-
end
|
195
|
-
|
196
|
-
def print_message(message)
|
197
|
-
@io.puts(format_string(message, :tag).indent(@indent))
|
178
|
+
@io.puts
|
179
|
+
@io.puts(format_string(src, :tag))
|
198
180
|
@io.flush
|
199
181
|
end
|
200
182
|
|
201
|
-
def empty_messages
|
202
|
-
@delayed_messages = []
|
203
|
-
end
|
204
|
-
|
205
183
|
def print_profile_information
|
206
184
|
return if @options[:skip_profile_information] || @options[:profiles].nil? || @options[:profiles].empty?
|
185
|
+
|
207
186
|
do_print_profile_information(@options[:profiles])
|
208
187
|
end
|
209
188
|
|
210
189
|
def do_print_profile_information(profiles)
|
211
|
-
profiles_sentence = profiles.size == 1
|
212
|
-
|
190
|
+
profiles_sentence = if profiles.size == 1
|
191
|
+
profiles.first
|
192
|
+
else
|
193
|
+
"#{profiles[0...-1].join(', ')} and #{profiles.last}"
|
194
|
+
end
|
213
195
|
|
214
196
|
@io.puts "Using the #{profiles_sentence} profile#{'s' if profiles.size > 1}..."
|
215
197
|
end
|
216
198
|
|
199
|
+
def do_print_undefined_parameter_type_snippet(type_name)
|
200
|
+
camelized = type_name.split(/_|-/).collect(&:capitalize).join
|
201
|
+
|
202
|
+
@io.puts [
|
203
|
+
"The parameter #{type_name} is not defined. You can define a new one with:",
|
204
|
+
'',
|
205
|
+
'ParameterType(',
|
206
|
+
" name: '#{type_name}',",
|
207
|
+
' regexp: /some regexp here/,',
|
208
|
+
" type: #{camelized},",
|
209
|
+
' # The transformer takes as many arguments as there are capture groups in the regexp,',
|
210
|
+
' # or just one if there are none.',
|
211
|
+
" transformer: ->(s) { #{camelized}.new(s) }",
|
212
|
+
')',
|
213
|
+
''
|
214
|
+
].join("\n")
|
215
|
+
end
|
216
|
+
|
217
|
+
def indent(string, padding)
|
218
|
+
if padding >= 0
|
219
|
+
string.gsub(/^/, ' ' * padding)
|
220
|
+
else
|
221
|
+
string.gsub(/^ {0,#{-padding}}/, '')
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
217
225
|
private
|
218
226
|
|
219
227
|
FORMATS = Hash.new { |hash, format| hash[format] = method(format).to_proc }
|
@@ -222,11 +230,8 @@ module Cucumber
|
|
222
230
|
key = keys.join('_').to_sym
|
223
231
|
fmt = FORMATS[key]
|
224
232
|
raise "No format for #{key.inspect}: #{FORMATS.inspect}" if fmt.nil?
|
225
|
-
fmt
|
226
|
-
end
|
227
233
|
|
228
|
-
|
229
|
-
not test_step.source.last.respond_to?(:actual_keyword)
|
234
|
+
fmt
|
230
235
|
end
|
231
236
|
|
232
237
|
def element_messages(elements, status)
|
@@ -248,10 +253,13 @@ module Cucumber
|
|
248
253
|
|
249
254
|
class SnippetData
|
250
255
|
attr_reader :actual_keyword, :step
|
256
|
+
|
251
257
|
def initialize(actual_keyword, step)
|
252
|
-
@actual_keyword
|
258
|
+
@actual_keyword = actual_keyword
|
259
|
+
@step = step
|
253
260
|
end
|
254
261
|
end
|
255
262
|
end
|
256
263
|
end
|
257
264
|
end
|
265
|
+
# rubocop:enable Metrics/ModuleLength
|
@@ -29,15 +29,10 @@ module Cucumber
|
|
29
29
|
end
|
30
30
|
|
31
31
|
def status_counts(summary)
|
32
|
-
counts = Core::Test::Result::TYPES.map
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
count > 0
|
37
|
-
end.map do |status, count|
|
38
|
-
format_string("#{count} #{status}", status)
|
39
|
-
end
|
40
|
-
"(#{counts.join(", ")})" if counts.any?
|
32
|
+
counts = Core::Test::Result::TYPES.map { |status| [status, summary.total(status)] }
|
33
|
+
counts = counts.select { |_status, count| count > 0 }
|
34
|
+
counts = counts.map { |status, count| format_string("#{count} #{status}", status) }
|
35
|
+
"(#{counts.join(', ')})" if counts.any?
|
41
36
|
end
|
42
37
|
end
|
43
38
|
end
|
@@ -5,7 +5,7 @@ module Cucumber
|
|
5
5
|
class ConsoleIssues
|
6
6
|
include Console
|
7
7
|
|
8
|
-
def initialize(config)
|
8
|
+
def initialize(config, ast_lookup = AstLookup.new(config))
|
9
9
|
@previous_test_case = nil
|
10
10
|
@issues = Hash.new { |h, k| h[k] = [] }
|
11
11
|
@config = config
|
@@ -18,10 +18,12 @@ module Cucumber
|
|
18
18
|
@issues[:failed].delete(event.test_case)
|
19
19
|
end
|
20
20
|
end
|
21
|
+
@ast_lookup = ast_lookup
|
21
22
|
end
|
22
23
|
|
23
24
|
def to_s
|
24
25
|
return if @issues.empty?
|
26
|
+
|
25
27
|
result = Core::Test::Result::TYPES.map { |type| scenario_listing(type, @issues[type]) }
|
26
28
|
result.flatten.join("\n")
|
27
29
|
end
|
@@ -34,9 +36,12 @@ module Cucumber
|
|
34
36
|
|
35
37
|
def scenario_listing(type, test_cases)
|
36
38
|
return [] if test_cases.empty?
|
39
|
+
|
37
40
|
[format_string("#{type_heading(type)} Scenarios:", type)] + test_cases.map do |test_case|
|
38
|
-
|
39
|
-
|
41
|
+
scenario_source = @ast_lookup.scenario_source(test_case)
|
42
|
+
keyword = scenario_source.type == :Scenario ? scenario_source.scenario.keyword : scenario_source.scenario_outline.keyword
|
43
|
+
source = @config.source? ? format_string(" # #{keyword}: #{test_case.name}", :comment) : ''
|
44
|
+
format_string("cucumber #{profiles_string}#{test_case.location.file}:#{test_case.location.lines.max}", type) + source
|
40
45
|
end
|
41
46
|
end
|
42
47
|
|
@@ -51,7 +56,10 @@ module Cucumber
|
|
51
56
|
|
52
57
|
def profiles_string
|
53
58
|
return if @config.custom_profiles.empty?
|
54
|
-
|
59
|
+
|
60
|
+
profiles = @config.custom_profiles.map { |profile| "-p #{profile}" }.join(' ')
|
61
|
+
|
62
|
+
"#{profiles} "
|
55
63
|
end
|
56
64
|
end
|
57
65
|
end
|
@@ -4,6 +4,7 @@ module Cucumber
|
|
4
4
|
module Formatter
|
5
5
|
class DurationExtractor
|
6
6
|
attr_reader :result_duration
|
7
|
+
|
7
8
|
def initialize(result)
|
8
9
|
@result_duration = 0
|
9
10
|
result.describe_to(self)
|
@@ -22,8 +23,10 @@ module Cucumber
|
|
22
23
|
def exception(*) end
|
23
24
|
|
24
25
|
def duration(duration, *)
|
25
|
-
duration.tap { |
|
26
|
+
duration.tap { |dur| @result_duration = dur.nanoseconds / 10**9.0 }
|
26
27
|
end
|
28
|
+
|
29
|
+
def attach(*) end
|
27
30
|
end
|
28
31
|
end
|
29
32
|
end
|
@@ -13,13 +13,15 @@ module Cucumber
|
|
13
13
|
end
|
14
14
|
|
15
15
|
def method_missing(message, *args)
|
16
|
+
super unless recipients
|
17
|
+
|
16
18
|
recipients.each do |recipient|
|
17
19
|
recipient.send(message, *args) if recipient.respond_to?(message)
|
18
20
|
end
|
19
21
|
end
|
20
22
|
|
21
23
|
def respond_to_missing?(name, include_private = false)
|
22
|
-
recipients.any? { |recipient| recipient.respond_to?(name, include_private) }
|
24
|
+
recipients.any? { |recipient| recipient.respond_to?(name, include_private) } || super(name, include_private)
|
23
25
|
end
|
24
26
|
end
|
25
27
|
end
|