cucumber 5.2.0 → 7.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +1400 -1098
- data/CONTRIBUTING.md +229 -52
- data/README.md +140 -20
- data/lib/cucumber/cli/configuration.rb +23 -1
- data/lib/cucumber/cli/options.rb +8 -3
- data/lib/cucumber/formatter/ansicolor.rb +0 -7
- data/lib/cucumber/formatter/backtrace_filter.rb +1 -0
- data/lib/cucumber/formatter/console.rb +11 -3
- data/lib/cucumber/formatter/json.rb +25 -24
- data/lib/cucumber/formatter/junit.rb +18 -1
- data/lib/cucumber/formatter/message.rb +2 -1
- data/lib/cucumber/formatter/message_builder.rb +8 -8
- data/lib/cucumber/formatter/pretty.rb +19 -18
- data/lib/cucumber/formatter/publish_banner_printer.rb +1 -1
- data/lib/cucumber/formatter/steps.rb +5 -2
- data/lib/cucumber/formatter/usage.rb +6 -4
- data/lib/cucumber/gherkin/data_table_parser.rb +1 -1
- data/lib/cucumber/gherkin/steps_parser.rb +1 -1
- data/lib/cucumber/glue/proto_world.rb +15 -31
- data/lib/cucumber/glue/registry_and_more.rb +1 -1
- data/lib/cucumber/glue/step_definition.rb +3 -4
- data/lib/cucumber/runtime.rb +6 -1
- data/lib/cucumber/step_match.rb +1 -7
- data/lib/cucumber/version +1 -1
- metadata +88 -69
- data/lib/cucumber/core_ext/string.rb +0 -11
@@ -126,13 +126,35 @@ module Cucumber
|
|
126
126
|
end
|
127
127
|
|
128
128
|
def arrange_formats
|
129
|
-
|
129
|
+
add_default_formatter if needs_default_formatter?
|
130
|
+
|
130
131
|
@options[:formats] = @options[:formats].sort_by do |f|
|
131
132
|
f[2] == @out_stream ? -1 : 1
|
132
133
|
end
|
133
134
|
@options[:formats].uniq!
|
134
135
|
@options.check_formatter_stream_conflicts
|
135
136
|
end
|
137
|
+
|
138
|
+
def add_default_formatter
|
139
|
+
@options[:formats] << ['pretty', {}, @out_stream]
|
140
|
+
end
|
141
|
+
|
142
|
+
def needs_default_formatter?
|
143
|
+
formatter_missing? || publish_only?
|
144
|
+
end
|
145
|
+
|
146
|
+
def formatter_missing?
|
147
|
+
@options[:formats].empty?
|
148
|
+
end
|
149
|
+
|
150
|
+
def publish_only?
|
151
|
+
@options[:formats]
|
152
|
+
.uniq
|
153
|
+
.map { |formatter, _, stream| [formatter, stream] }
|
154
|
+
.uniq
|
155
|
+
.reject { |formatter, stream| formatter == 'message' && stream != @out_stream }
|
156
|
+
.empty?
|
157
|
+
end
|
136
158
|
end
|
137
159
|
end
|
138
160
|
end
|
data/lib/cucumber/cli/options.rb
CHANGED
@@ -22,9 +22,14 @@ module Cucumber
|
|
22
22
|
"#{INDENT}filename instead."],
|
23
23
|
'stepdefs' => ['Cucumber::Formatter::Stepdefs', "Prints All step definitions with their locations. Same as\n" \
|
24
24
|
"#{INDENT}the usage formatter, except that steps are not printed."],
|
25
|
-
'junit' => ['Cucumber::Formatter::Junit',
|
26
|
-
|
27
|
-
'
|
25
|
+
'junit' => ['Cucumber::Formatter::Junit', "Generates a report similar to Ant+JUnit. Use\n" \
|
26
|
+
"#{INDENT}junit,fileattribute=true to include a file attribute."],
|
27
|
+
'json' => ['Cucumber::Formatter::Json', "Prints the feature as JSON.\n" \
|
28
|
+
"#{INDENT}The JSON format is in maintenance mode.\n" \
|
29
|
+
"#{INDENT}Please consider using the message formatter\n"\
|
30
|
+
"#{INDENT}with the standalone json-formatter\n" \
|
31
|
+
"#{INDENT}(https://github.com/cucumber/cucumber/tree/master/json-formatter)."],
|
32
|
+
'message' => ['Cucumber::Formatter::Message', 'Prints each message in NDJSON form, which can then be consumed by other tools.'],
|
28
33
|
'html' => ['Cucumber::Formatter::HTML', 'Outputs HTML report'],
|
29
34
|
'summary' => ['Cucumber::Formatter::Summary', 'Summary output of feature and scenarios']
|
30
35
|
}.freeze
|
@@ -3,13 +3,6 @@
|
|
3
3
|
require 'cucumber/platform'
|
4
4
|
require 'cucumber/term/ansicolor'
|
5
5
|
|
6
|
-
if Cucumber::WINDOWS_MRI
|
7
|
-
unless ENV['ANSICON']
|
8
|
-
STDERR.puts %{*** WARNING: You must use ANSICON 1.31 or higher (https://github.com/adoxa/ansicon/) to get coloured output on Windows}
|
9
|
-
Cucumber::Term::ANSIColor.coloring = false
|
10
|
-
end
|
11
|
-
end
|
12
|
-
|
13
6
|
Cucumber::Term::ANSIColor.coloring = false if !STDOUT.tty? && !ENV.key?('AUTOTEST')
|
14
7
|
|
15
8
|
module Cucumber
|
@@ -34,7 +34,7 @@ module Cucumber
|
|
34
34
|
|
35
35
|
def format_step(keyword, step_match, status, source_indent)
|
36
36
|
comment = if source_indent
|
37
|
-
c = ('# ' + step_match.location.to_s)
|
37
|
+
c = indent(('# ' + step_match.location.to_s), source_indent)
|
38
38
|
format_string(c, :comment)
|
39
39
|
else
|
40
40
|
''
|
@@ -99,11 +99,11 @@ module Cucumber
|
|
99
99
|
@io.puts(format_string(string, status))
|
100
100
|
end
|
101
101
|
|
102
|
-
def exception_message_string(e,
|
102
|
+
def exception_message_string(e, indent_amount)
|
103
103
|
message = "#{e.message} (#{e.class})".dup.force_encoding('UTF-8')
|
104
104
|
message = linebreaks(message, ENV['CUCUMBER_TRUNCATE_OUTPUT'].to_i)
|
105
105
|
|
106
|
-
"#{message}\n#{e.backtrace.join("\n")}"
|
106
|
+
indent("#{message}\n#{e.backtrace.join("\n")}", indent_amount)
|
107
107
|
end
|
108
108
|
|
109
109
|
# http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/10655
|
@@ -208,6 +208,14 @@ module Cucumber
|
|
208
208
|
].join("\n")
|
209
209
|
end
|
210
210
|
|
211
|
+
def indent(string, padding)
|
212
|
+
if padding >= 0
|
213
|
+
string.gsub(/^/, ' ' * padding)
|
214
|
+
else
|
215
|
+
string.gsub(/^ {0,#{-padding}}/, '')
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
211
219
|
private
|
212
220
|
|
213
221
|
FORMATS = Hash.new { |hash, format| hash[format] = method(format).to_proc }
|
@@ -5,7 +5,6 @@ require 'base64'
|
|
5
5
|
require 'cucumber/formatter/backtrace_filter'
|
6
6
|
require 'cucumber/formatter/io'
|
7
7
|
require 'cucumber/formatter/ast_lookup'
|
8
|
-
require 'cucumber/deprecate'
|
9
8
|
|
10
9
|
module Cucumber
|
11
10
|
module Formatter
|
@@ -14,14 +13,6 @@ module Cucumber
|
|
14
13
|
include Io
|
15
14
|
|
16
15
|
def initialize(config)
|
17
|
-
Cucumber::Deprecate::CliOption.deprecate(
|
18
|
-
config.error_stream,
|
19
|
-
'--format=json',
|
20
|
-
"Please use --format=message and stand-alone json-formatter.\n" \
|
21
|
-
'json-formatter homepage: https://github.com/cucumber/cucumber/tree/master/json-formatter#cucumber-json-formatter',
|
22
|
-
'6.0.0'
|
23
|
-
)
|
24
|
-
|
25
16
|
@io = ensure_io(config.out_stream, config.error_stream)
|
26
17
|
@ast_lookup = AstLookup.new(config)
|
27
18
|
@feature_hashes = []
|
@@ -41,21 +32,23 @@ module Cucumber
|
|
41
32
|
@feature_hashes << @feature_hash
|
42
33
|
end
|
43
34
|
@test_case_hash = builder.test_case_hash
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
@in_background = false
|
50
|
-
feature_elements << @test_case_hash
|
51
|
-
@element_hash = @test_case_hash
|
52
|
-
end
|
35
|
+
|
36
|
+
@element_hash = nil
|
37
|
+
@element_background_hash = builder.background_hash
|
38
|
+
@in_background = builder.background?
|
39
|
+
|
53
40
|
@any_step_failed = false
|
54
41
|
end
|
55
42
|
|
56
43
|
def on_test_step_started(event)
|
57
44
|
test_step = event.test_step
|
58
45
|
return if internal_hook?(test_step)
|
46
|
+
|
47
|
+
if @element_hash.nil?
|
48
|
+
@element_hash = create_element_hash(test_step)
|
49
|
+
feature_elements << @element_hash
|
50
|
+
end
|
51
|
+
|
59
52
|
if test_step.hook?
|
60
53
|
@step_or_hook_hash = {}
|
61
54
|
hooks_of_type(test_step) << @step_or_hook_hash
|
@@ -80,6 +73,8 @@ module Cucumber
|
|
80
73
|
end
|
81
74
|
|
82
75
|
def on_test_case_finished(event)
|
76
|
+
feature_elements << @test_case_hash if @in_background
|
77
|
+
|
83
78
|
_test_case, result = *event.attributes
|
84
79
|
result = result.with_filtered_backtrace(Cucumber::Formatter::BacktraceFilter)
|
85
80
|
add_failed_around_hook(result) if result.failed? && !@any_step_failed
|
@@ -94,10 +89,7 @@ module Cucumber
|
|
94
89
|
test_step_output << src
|
95
90
|
return
|
96
91
|
end
|
97
|
-
if
|
98
|
-
content = File.open(src, 'rb', &:read)
|
99
|
-
data = encode64(content)
|
100
|
-
elsif mime_type =~ /;base64$/
|
92
|
+
if mime_type =~ /;base64$/
|
101
93
|
mime_type = mime_type[0..-8]
|
102
94
|
data = src
|
103
95
|
else
|
@@ -169,6 +161,13 @@ module Cucumber
|
|
169
161
|
@step_or_hook_hash[:embeddings] ||= []
|
170
162
|
end
|
171
163
|
|
164
|
+
def create_element_hash(test_step)
|
165
|
+
return @element_background_hash if @in_background && !first_step_after_background?(test_step)
|
166
|
+
|
167
|
+
@in_background = false
|
168
|
+
@test_case_hash
|
169
|
+
end
|
170
|
+
|
172
171
|
def create_step_hash(test_step)
|
173
172
|
step_source = @ast_lookup.step_source(test_step).step
|
174
173
|
step_hash = {
|
@@ -269,7 +268,8 @@ module Cucumber
|
|
269
268
|
name: background.name,
|
270
269
|
description: value_or_empty_string(background.description),
|
271
270
|
line: background.location.line,
|
272
|
-
type: 'background'
|
271
|
+
type: 'background',
|
272
|
+
steps: []
|
273
273
|
}
|
274
274
|
end
|
275
275
|
|
@@ -281,7 +281,8 @@ module Cucumber
|
|
281
281
|
name: test_case.name,
|
282
282
|
description: value_or_empty_string(scenario.description),
|
283
283
|
line: test_case.location.lines.max,
|
284
|
-
type: 'scenario'
|
284
|
+
type: 'scenario',
|
285
|
+
steps: []
|
285
286
|
}
|
286
287
|
@test_case_hash[:tags] = create_tags_array_from_tags_array(test_case.tags) unless test_case.tags.empty?
|
287
288
|
end
|
@@ -132,9 +132,12 @@ module Cucumber
|
|
132
132
|
duration = ResultBuilder.new(result).test_case_duration
|
133
133
|
@current_feature_data[:time] += duration
|
134
134
|
classname = @current_feature_data[:feature].name
|
135
|
+
filename = @current_feature_data[:uri]
|
135
136
|
name = scenario_designation
|
136
137
|
|
137
|
-
|
138
|
+
testcase_attributes = get_testcase_attributes(classname, name, duration, filename)
|
139
|
+
|
140
|
+
@current_feature_data[:builder].testcase(testcase_attributes) do
|
138
141
|
if !result.passed? && result.ok?(@config.strict)
|
139
142
|
@current_feature_data[:builder].skipped
|
140
143
|
@current_feature_data[:skipped] += 1
|
@@ -157,6 +160,20 @@ module Cucumber
|
|
157
160
|
@current_feature_data[:tests] += 1
|
158
161
|
end
|
159
162
|
|
163
|
+
def get_testcase_attributes(classname, name, duration, filename)
|
164
|
+
{ classname: classname, name: name, time: format('%<duration>.6f', duration: duration) }.tap do |attributes|
|
165
|
+
attributes[:file] = filename if add_fileattribute?
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
def add_fileattribute?
|
170
|
+
return false if @config.formats.nil? || @config.formats.empty?
|
171
|
+
|
172
|
+
!!@config.formats.find do |format|
|
173
|
+
format.first == 'junit' && format.dig(1, 'fileattribute') == 'true'
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
160
177
|
def get_backtrace_object(result)
|
161
178
|
if result.failed?
|
162
179
|
result.exception
|
@@ -48,12 +48,12 @@ module Cucumber
|
|
48
48
|
}
|
49
49
|
|
50
50
|
if media_type.start_with?('text/')
|
51
|
-
attachment_data[:content_encoding] = Cucumber::Messages::
|
51
|
+
attachment_data[:content_encoding] = Cucumber::Messages::AttachmentContentEncoding::IDENTITY
|
52
52
|
attachment_data[:body] = src
|
53
53
|
else
|
54
54
|
body = src.respond_to?(:read) ? src.read : src
|
55
55
|
|
56
|
-
attachment_data[:content_encoding] = Cucumber::Messages::
|
56
|
+
attachment_data[:content_encoding] = Cucumber::Messages::AttachmentContentEncoding::BASE64
|
57
57
|
attachment_data[:body] = Base64.strict_encode64(body)
|
58
58
|
end
|
59
59
|
|
@@ -101,7 +101,7 @@ module Cucumber
|
|
101
101
|
def test_step_to_message(step)
|
102
102
|
return hook_step_to_message(step) if step.hook?
|
103
103
|
|
104
|
-
Cucumber::Messages::
|
104
|
+
Cucumber::Messages::TestStep.new(
|
105
105
|
id: step.id,
|
106
106
|
pickle_step_id: @pickle_step_by_test_step.pickle_step_id(step),
|
107
107
|
step_definition_ids: @step_definitions_by_test_step.step_definition_ids(step),
|
@@ -110,7 +110,7 @@ module Cucumber
|
|
110
110
|
end
|
111
111
|
|
112
112
|
def hook_step_to_message(step)
|
113
|
-
Cucumber::Messages::
|
113
|
+
Cucumber::Messages::TestStep.new(
|
114
114
|
id: step.id,
|
115
115
|
hook_id: @hook_by_test_step.hook_id(step)
|
116
116
|
)
|
@@ -118,7 +118,7 @@ module Cucumber
|
|
118
118
|
|
119
119
|
def step_match_arguments_lists(step)
|
120
120
|
match_arguments = step_match_arguments(step)
|
121
|
-
[Cucumber::Messages::
|
121
|
+
[Cucumber::Messages::StepMatchArgumentsList.new(
|
122
122
|
step_match_arguments: match_arguments
|
123
123
|
)]
|
124
124
|
rescue Cucumber::Formatter::TestStepUnknownError
|
@@ -127,7 +127,7 @@ module Cucumber
|
|
127
127
|
|
128
128
|
def step_match_arguments(step)
|
129
129
|
@step_definitions_by_test_step.step_match_arguments(step).map do |argument|
|
130
|
-
Cucumber::Messages::
|
130
|
+
Cucumber::Messages::StepMatchArgument.new(
|
131
131
|
group: argument_group_to_message(argument.group),
|
132
132
|
parameter_type_name: argument.parameter_type.name
|
133
133
|
)
|
@@ -135,7 +135,7 @@ module Cucumber
|
|
135
135
|
end
|
136
136
|
|
137
137
|
def argument_group_to_message(group)
|
138
|
-
Cucumber::Messages::
|
138
|
+
Cucumber::Messages::Group.new(
|
139
139
|
start: group.start,
|
140
140
|
value: group.value,
|
141
141
|
children: group.children.map { |child| argument_group_to_message(child) }
|
@@ -190,7 +190,7 @@ module Cucumber
|
|
190
190
|
|
191
191
|
result_message = result.to_message
|
192
192
|
if result.failed? || result.pending?
|
193
|
-
result_message = Cucumber::Messages::
|
193
|
+
result_message = Cucumber::Messages::TestStepResult.new(
|
194
194
|
status: result_message.status,
|
195
195
|
duration: result_message.duration,
|
196
196
|
message: create_error_message(result)
|
@@ -181,7 +181,7 @@ module Cucumber
|
|
181
181
|
end
|
182
182
|
|
183
183
|
def print_step_output
|
184
|
-
@test_step_output.each { |message| @io.puts(format_string(message, :tag)
|
184
|
+
@test_step_output.each { |message| @io.puts(indent(format_string(message, :tag), 6)) }
|
185
185
|
@test_step_output = []
|
186
186
|
end
|
187
187
|
|
@@ -259,33 +259,34 @@ module Cucumber
|
|
259
259
|
end
|
260
260
|
end
|
261
261
|
|
262
|
-
def print_comments(up_to_line,
|
262
|
+
def print_comments(up_to_line, indent_amount)
|
263
263
|
comments = gherkin_document.comments
|
264
264
|
return if comments.empty? || comments.length <= @next_comment_to_be_printed
|
265
265
|
comments[@next_comment_to_be_printed..-1].each do |comment|
|
266
266
|
if comment.location.line <= up_to_line
|
267
|
-
@io.puts(format_string(comment.text.strip, :comment)
|
267
|
+
@io.puts(indent(format_string(comment.text.strip, :comment), indent_amount))
|
268
268
|
@next_comment_to_be_printed += 1
|
269
269
|
end
|
270
270
|
break if @next_comment_to_be_printed >= comments.length
|
271
271
|
end
|
272
272
|
end
|
273
273
|
|
274
|
-
def print_tags(tags,
|
274
|
+
def print_tags(tags, indent_amount)
|
275
275
|
return if !tags || tags.empty?
|
276
|
-
|
276
|
+
|
277
|
+
@io.puts(indent(tags.map { |tag| format_string(tag.name, :tag) }.join(' '), indent_amount))
|
277
278
|
end
|
278
279
|
|
279
280
|
def print_feature_line(feature)
|
280
281
|
print_keyword_name(feature.keyword, feature.name, 0)
|
281
282
|
end
|
282
283
|
|
283
|
-
def print_keyword_name(keyword, name,
|
284
|
+
def print_keyword_name(keyword, name, indent_amount, location = nil)
|
284
285
|
line = "#{keyword}:"
|
285
286
|
line += " #{name}"
|
286
|
-
@io.print(
|
287
|
+
@io.print(indent(line, indent_amount))
|
287
288
|
if location && options[:source]
|
288
|
-
line_comment = format_string("# #{location}", :comment)
|
289
|
+
line_comment = indent(format_string("# #{location}", :comment), @source_indent - line.length - indent_amount)
|
289
290
|
@io.print(line_comment)
|
290
291
|
end
|
291
292
|
@io.puts
|
@@ -339,7 +340,7 @@ module Cucumber
|
|
339
340
|
indent = options[:source] ? @source_indent - step_keyword.length - test_step.text.length - base_indent : nil
|
340
341
|
print_comments(test_step.location.lines.max, base_indent)
|
341
342
|
name_to_report = format_step(step_keyword, @step_matches.fetch(test_step.to_s) { NoStepMatch.new(test_step, test_step.text) }, result.to_sym, indent)
|
342
|
-
@io.puts(
|
343
|
+
@io.puts(indent(name_to_report, base_indent))
|
343
344
|
print_multiline_argument(test_step, result, base_indent + 2) unless options[:no_multiline]
|
344
345
|
@io.flush
|
345
346
|
end
|
@@ -374,10 +375,10 @@ module Cucumber
|
|
374
375
|
end
|
375
376
|
end
|
376
377
|
|
377
|
-
def print_data_table(data_table, status,
|
378
|
+
def print_data_table(data_table, status, indent_amount)
|
378
379
|
data_table.rows.each do |row|
|
379
|
-
print_comments(row.location.line,
|
380
|
-
@io.puts format_string(gherkin_source.split("\n")[row.location.line - 1].strip, status)
|
380
|
+
print_comments(row.location.line, indent_amount)
|
381
|
+
@io.puts indent(format_string(gherkin_source.split("\n")[row.location.line - 1].strip, status), indent_amount)
|
381
382
|
end
|
382
383
|
end
|
383
384
|
|
@@ -393,7 +394,7 @@ module Cucumber
|
|
393
394
|
@io.print(format_string(step_line, :skipped))
|
394
395
|
if options[:source]
|
395
396
|
comment_line = format_string("# #{current_feature_uri}:#{step.location.line}", :comment)
|
396
|
-
@io.print(
|
397
|
+
@io.print(indent(comment_line, @source_indent - step_line.length))
|
397
398
|
end
|
398
399
|
@io.puts
|
399
400
|
next if options[:no_multiline]
|
@@ -403,8 +404,8 @@ module Cucumber
|
|
403
404
|
@io.flush
|
404
405
|
end
|
405
406
|
|
406
|
-
def print_doc_string(content, status,
|
407
|
-
s = %("""\n#{content}\n""")
|
407
|
+
def print_doc_string(content, status, indent_amount)
|
408
|
+
s = indent(%("""\n#{content}\n"""), indent_amount)
|
408
409
|
s = s.split("\n").map { |l| l =~ /^\s+$/ ? '' : l }.join("\n")
|
409
410
|
@io.puts(format_string(s, status))
|
410
411
|
end
|
@@ -416,15 +417,15 @@ module Cucumber
|
|
416
417
|
print_description(examples.description)
|
417
418
|
unless options[:expand]
|
418
419
|
print_comments(examples.table_header.location.line, 6)
|
419
|
-
@io.puts(gherkin_source.split("\n")[examples.table_header.location.line - 1].strip
|
420
|
+
@io.puts(indent(gherkin_source.split("\n")[examples.table_header.location.line - 1].strip, 6))
|
420
421
|
end
|
421
422
|
@io.flush
|
422
423
|
end
|
423
424
|
|
424
425
|
def print_row_data(test_case, result)
|
425
426
|
print_comments(test_case.location.lines.max, 6)
|
426
|
-
@io.print(format_string(gherkin_source.split("\n")[test_case.location.lines.max - 1].strip, result.to_sym)
|
427
|
-
@io.print(format_string(@test_step_output.join(', '), :tag)
|
427
|
+
@io.print(indent(format_string(gherkin_source.split("\n")[test_case.location.lines.max - 1].strip, result.to_sym), 6))
|
428
|
+
@io.print(indent(format_string(@test_step_output.join(', '), :tag), 2)) unless @test_step_output.empty?
|
428
429
|
@test_step_output = []
|
429
430
|
@io.puts
|
430
431
|
if result.failed? || result.pending?
|