cucumber 6.0.0 → 8.0.0.rc.1

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 (82) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +371 -168
  3. data/CONTRIBUTING.md +216 -55
  4. data/README.md +139 -21
  5. data/lib/autotest/cucumber_mixin.rb +5 -2
  6. data/lib/autotest/discover.rb +3 -2
  7. data/lib/cucumber/cli/configuration.rb +4 -1
  8. data/lib/cucumber/cli/main.rb +4 -3
  9. data/lib/cucumber/cli/options.rb +14 -4
  10. data/lib/cucumber/cli/profile_loader.rb +1 -5
  11. data/lib/cucumber/cli/rerun_file.rb +1 -1
  12. data/lib/cucumber/configuration.rb +5 -4
  13. data/lib/cucumber/constantize.rb +1 -1
  14. data/lib/cucumber/deprecate.rb +2 -1
  15. data/lib/cucumber/errors.rb +1 -1
  16. data/lib/cucumber/events/hook_test_step_created.rb +1 -2
  17. data/lib/cucumber/events/step_activated.rb +0 -6
  18. data/lib/cucumber/events/step_definition_registered.rb +0 -5
  19. data/lib/cucumber/events/test_case_created.rb +1 -2
  20. data/lib/cucumber/events/test_run_finished.rb +2 -1
  21. data/lib/cucumber/events/test_step_created.rb +1 -2
  22. data/lib/cucumber/events/undefined_parameter_type.rb +1 -2
  23. data/lib/cucumber/events.rb +2 -2
  24. data/lib/cucumber/file_specs.rb +2 -1
  25. data/lib/cucumber/filters/activate_steps.rb +1 -0
  26. data/lib/cucumber/filters/tag_limits/verifier.rb +1 -3
  27. data/lib/cucumber/filters/tag_limits.rb +1 -3
  28. data/lib/cucumber/formatter/ansicolor.rb +63 -70
  29. data/lib/cucumber/formatter/ast_lookup.rb +2 -2
  30. data/lib/cucumber/formatter/backtrace_filter.rb +1 -1
  31. data/lib/cucumber/formatter/console.rb +20 -4
  32. data/lib/cucumber/formatter/console_issues.rb +6 -1
  33. data/lib/cucumber/formatter/duration_extractor.rb +1 -0
  34. data/lib/cucumber/formatter/errors.rb +1 -0
  35. data/lib/cucumber/formatter/fanout.rb +1 -1
  36. data/lib/cucumber/formatter/http_io.rb +6 -1
  37. data/lib/cucumber/formatter/ignore_missing_messages.rb +1 -1
  38. data/lib/cucumber/formatter/io.rb +3 -1
  39. data/lib/cucumber/formatter/json.rb +32 -26
  40. data/lib/cucumber/formatter/junit.rb +6 -3
  41. data/lib/cucumber/formatter/message.rb +2 -1
  42. data/lib/cucumber/formatter/message_builder.rb +11 -10
  43. data/lib/cucumber/formatter/pretty.rb +34 -23
  44. data/lib/cucumber/formatter/progress.rb +1 -0
  45. data/lib/cucumber/formatter/publish_banner_printer.rb +1 -1
  46. data/lib/cucumber/formatter/query/hook_by_test_step.rb +1 -0
  47. data/lib/cucumber/formatter/query/test_case_started_by_test_case.rb +2 -0
  48. data/lib/cucumber/formatter/rerun.rb +2 -0
  49. data/lib/cucumber/formatter/steps.rb +5 -2
  50. data/lib/cucumber/formatter/summary.rb +1 -0
  51. data/lib/cucumber/formatter/unicode.rb +4 -4
  52. data/lib/cucumber/formatter/usage.rb +9 -7
  53. data/lib/cucumber/gherkin/data_table_parser.rb +2 -1
  54. data/lib/cucumber/gherkin/formatter/ansi_escapes.rb +2 -2
  55. data/lib/cucumber/gherkin/steps_parser.rb +1 -1
  56. data/lib/cucumber/glue/dsl.rb +19 -5
  57. data/lib/cucumber/glue/hook.rb +2 -1
  58. data/lib/cucumber/glue/invoke_in_world.rb +4 -4
  59. data/lib/cucumber/glue/proto_world.rb +12 -9
  60. data/lib/cucumber/glue/registry_and_more.rb +20 -5
  61. data/lib/cucumber/glue/registry_wrapper.rb +31 -0
  62. data/lib/cucumber/glue/step_definition.rb +9 -7
  63. data/lib/cucumber/hooks.rb +1 -0
  64. data/lib/cucumber/multiline_argument/data_table/diff_matrices.rb +2 -1
  65. data/lib/cucumber/multiline_argument/data_table.rb +58 -71
  66. data/lib/cucumber/platform.rb +2 -2
  67. data/lib/cucumber/rake/task.rb +10 -7
  68. data/lib/cucumber/rspec/disable_option_parser.rb +6 -3
  69. data/lib/cucumber/running_test_case.rb +1 -0
  70. data/lib/cucumber/runtime/meta_message_builder.rb +106 -0
  71. data/lib/cucumber/runtime/support_code.rb +3 -0
  72. data/lib/cucumber/runtime/user_interface.rb +5 -4
  73. data/lib/cucumber/runtime.rb +42 -23
  74. data/lib/cucumber/step_match.rb +6 -10
  75. data/lib/cucumber/step_match_search.rb +3 -2
  76. data/lib/cucumber/term/ansicolor.rb +74 -50
  77. data/lib/cucumber/term/banner.rb +1 -0
  78. data/lib/cucumber/version +1 -1
  79. data/lib/cucumber.rb +2 -1
  80. data/lib/simplecov_setup.rb +1 -1
  81. metadata +90 -89
  82. data/lib/cucumber/core_ext/string.rb +0 -11
@@ -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)
@@ -1,6 +1,7 @@
1
1
  module Cucumber
2
2
  module Formatter
3
3
  class TestCaseUnknownError < StandardError; end
4
+
4
5
  class TestStepUnknownError < StandardError; end
5
6
  end
6
7
  end
@@ -21,7 +21,7 @@ module Cucumber
21
21
  end
22
22
 
23
23
  def respond_to_missing?(name, include_private = false)
24
- recipients.any? { |recipient| recipient.respond_to?(name, include_private) }
24
+ recipients.any? { |recipient| recipient.respond_to?(name, include_private) } || super(name, include_private)
25
25
  end
26
26
  end
27
27
  end
@@ -35,6 +35,7 @@ module Cucumber
35
35
  headers = headers.merge(parse_header(header_arg))
36
36
  else
37
37
  raise StandardError, "#{options} was not a valid curl command. Can't set url to #{arg} it is already set to #{url}" if url
38
+
38
39
  url = arg
39
40
  end
40
41
  end
@@ -49,12 +50,14 @@ module Cucumber
49
50
 
50
51
  def self.remove_arg_for(args, arg)
51
52
  return args.shift unless args.empty?
53
+
52
54
  raise StandardError, "Missing argument for #{arg}"
53
55
  end
54
56
 
55
57
  def self.parse_header(header_arg)
56
58
  parts = header_arg.split(':', 2)
57
59
  raise StandardError, "#{header_arg} was not a valid header" unless parts.length == 2
60
+
58
61
  { parts[0].strip => parts[1].strip }
59
62
  end
60
63
  end
@@ -76,6 +79,7 @@ module Cucumber
76
79
  @reporter.report(response.body)
77
80
  @write_io.close
78
81
  return if response.is_a?(Net::HTTPSuccess) || response.is_a?(Net::HTTPRedirection)
82
+
79
83
  raise StandardError, "request to #{uri} failed with status #{response.code}"
80
84
  end
81
85
 
@@ -98,6 +102,7 @@ module Cucumber
98
102
  http = build_client(uri, @https_verify_mode)
99
103
 
100
104
  raise StandardError, "request to #{uri} failed (too many redirections)" if attempt <= 0
105
+
101
106
  req = build_request(
102
107
  uri,
103
108
  method,
@@ -126,7 +131,7 @@ module Cucumber
126
131
  end
127
132
 
128
133
  def build_request(uri, method, headers)
129
- method_class_name = "#{method[0].upcase}#{method[1..-1].downcase}"
134
+ method_class_name = "#{method[0].upcase}#{method[1..].downcase}"
130
135
  req = Net::HTTP.const_get(method_class_name).new(uri)
131
136
  headers.each do |header, value|
132
137
  req[header] = value
@@ -12,7 +12,7 @@ module Cucumber
12
12
  end
13
13
 
14
14
  def respond_to_missing?(name, include_private = false)
15
- @receiver.respond_to?(name, include_private)
15
+ @receiver.respond_to?(name, include_private) || super(name, include_private)
16
16
  end
17
17
  end
18
18
  end
@@ -57,19 +57,21 @@ module Cucumber
57
57
  end
58
58
 
59
59
  def url?(path_or_url_or_io)
60
- path_or_url_or_io.match(%r{^https?://})
60
+ path_or_url_or_io.match(/^https?:\/\//)
61
61
  end
62
62
 
63
63
  def ensure_file(path, name)
64
64
  raise "You *must* specify --out FILE for the #{name} formatter" unless String == path.class
65
65
  raise "I can't write #{name} to a directory - it has to be a file" if File.directory?(path)
66
66
  raise "I can't write #{name} to a file in the non-existing directory #{File.dirname(path)}" unless File.directory?(File.dirname(path))
67
+
67
68
  ensure_io(path, nil)
68
69
  end
69
70
 
70
71
  def ensure_dir(path, name)
71
72
  raise "You *must* specify --out DIR for the #{name} formatter" unless String == path.class
72
73
  raise "I can't write #{name} reports to a file - it has to be a directory" if File.file?(path)
74
+
73
75
  FileUtils.mkdir_p(path) unless File.directory?(path)
74
76
  File.absolute_path path
75
77
  end
@@ -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
- if builder.background?
45
- @in_background = true
46
- feature_elements << builder.background_hash
47
- @element_hash = builder.background_hash
48
- else
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
@@ -75,18 +68,21 @@ module Cucumber
75
68
  test_step, result = *event.attributes
76
69
  result = result.with_filtered_backtrace(Cucumber::Formatter::BacktraceFilter)
77
70
  return if internal_hook?(test_step)
71
+
78
72
  add_match_and_result(test_step, result)
79
73
  @any_step_failed = true if result.failed?
80
74
  end
81
75
 
82
76
  def on_test_case_finished(event)
77
+ feature_elements << @test_case_hash if @in_background
78
+
83
79
  _test_case, result = *event.attributes
84
80
  result = result.with_filtered_backtrace(Cucumber::Formatter::BacktraceFilter)
85
81
  add_failed_around_hook(result) if result.failed? && !@any_step_failed
86
82
  end
87
83
 
88
84
  def on_test_run_finished(_event)
89
- @io.write(JSON.generate(@feature_hashes, pretty: true))
85
+ @io.write(JSON.pretty_generate(@feature_hashes))
90
86
  end
91
87
 
92
88
  def attach(src, mime_type)
@@ -110,7 +106,7 @@ module Cucumber
110
106
  end
111
107
 
112
108
  def first_step_after_background?(test_step)
113
- @in_background && test_step.location.lines.max >= @test_case_hash[:line]
109
+ @in_background && test_step.location.file == @feature_hash[:uri] && test_step.location.lines.max >= @test_case_hash[:line]
114
110
  end
115
111
 
116
112
  def internal_hook?(test_step)
@@ -138,7 +134,7 @@ module Cucumber
138
134
  when 'AfterStep hook'
139
135
  after_step_hooks
140
136
  else
141
- raise 'Unknown hook type ' + hook_step.to_s
137
+ raise "Unknown hook type #{hook_step}"
142
138
  end
143
139
  end
144
140
 
@@ -166,6 +162,13 @@ module Cucumber
166
162
  @step_or_hook_hash[:embeddings] ||= []
167
163
  end
168
164
 
165
+ def create_element_hash(test_step)
166
+ return @element_background_hash if @in_background && !first_step_after_background?(test_step)
167
+
168
+ @in_background = false
169
+ @test_case_hash
170
+ end
171
+
169
172
  def create_step_hash(test_step)
170
173
  step_source = @ast_lookup.step_source(test_step).step
171
174
  step_hash = {
@@ -173,15 +176,15 @@ module Cucumber
173
176
  name: test_step.text,
174
177
  line: test_step.location.lines.min
175
178
  }
176
- step_hash[:doc_string] = create_doc_string_hash(step_source.doc_string) unless step_source.doc_string.nil?
179
+ step_hash[:doc_string] = create_doc_string_hash(step_source.doc_string, test_step.multiline_arg.content) unless step_source.doc_string.nil?
177
180
  step_hash[:rows] = create_data_table_value(step_source.data_table) unless step_source.data_table.nil?
178
181
  step_hash
179
182
  end
180
183
 
181
- def create_doc_string_hash(doc_string)
184
+ def create_doc_string_hash(doc_string, doc_string_content)
182
185
  content_type = doc_string.media_type || ''
183
186
  {
184
- value: doc_string.content,
187
+ value: doc_string_content,
185
188
  content_type: content_type,
186
189
  line: doc_string.location.line
187
190
  }
@@ -257,6 +260,7 @@ module Cucumber
257
260
  line: feature.location.line
258
261
  }
259
262
  return if feature.tags.empty?
263
+
260
264
  @feature_hash[:tags] = create_tags_array_from_hash_array(feature.tags)
261
265
  end
262
266
 
@@ -266,7 +270,8 @@ module Cucumber
266
270
  name: background.name,
267
271
  description: value_or_empty_string(background.description),
268
272
  line: background.location.line,
269
- type: 'background'
273
+ type: 'background',
274
+ steps: []
270
275
  }
271
276
  end
272
277
 
@@ -278,7 +283,8 @@ module Cucumber
278
283
  name: test_case.name,
279
284
  description: value_or_empty_string(scenario.description),
280
285
  line: test_case.location.lines.max,
281
- type: 'scenario'
286
+ type: 'scenario',
287
+ steps: []
282
288
  }
283
289
  @test_case_hash[:tags] = create_tags_array_from_tags_array(test_case.tags) unless test_case.tags.empty?
284
290
  end
@@ -84,6 +84,7 @@ module Cucumber
84
84
  uri = test_case.location.file
85
85
  feature = @ast_lookup.gherkin_document(uri).feature
86
86
  raise UnNamedFeatureError, uri if feature.name.empty?
87
+
87
88
  @current_feature_data = @features_data[uri]
88
89
  @current_feature_data[:uri] = uri unless @current_feature_data[:uri]
89
90
  @current_feature_data[:feature] = feature unless @current_feature_data[:feature]
@@ -111,6 +112,7 @@ module Cucumber
111
112
  keyword = scenario_source.type == :Scenario ? scenario_source.scenario.keyword : scenario_source.scenario_outline.keyword
112
113
  output = "#{keyword}: #{scenario}\n\n"
113
114
  return output if result.ok?(@config.strict)
115
+
114
116
  if scenario_source.type == :Scenario
115
117
  if @failing_test_step
116
118
  if @failing_test_step.hook?
@@ -125,7 +127,7 @@ module Cucumber
125
127
  else
126
128
  output += "Example row: #{row_name}\n"
127
129
  end
128
- output + "\nMessage:\n"
130
+ "#{output}\nMessage:\n"
129
131
  end
130
132
 
131
133
  def build_testcase(result, scenario_designation, output)
@@ -191,7 +193,7 @@ module Cucumber
191
193
  end
192
194
 
193
195
  def basename(feature_file)
194
- File.basename(feature_file.gsub(/[\\\/]/, '-'), '.feature') # rubocop:disable Style/RegexpLiteral
196
+ File.basename(feature_file.gsub(/[\\\/]/, '-'), '.feature')
195
197
  end
196
198
 
197
199
  def write_file(feature_filename, data)
@@ -228,13 +230,14 @@ module Cucumber
228
230
  end
229
231
 
230
232
  def examples_table_row(row)
231
- @row_name = '| ' + row.cells.map(&:value).join(' | ') + ' |'
233
+ @row_name = "| #{row.cells.map(&:value).join(' | ')} |"
232
234
  @name_suffix = " (outline example : #{@row_name})"
233
235
  end
234
236
  end
235
237
 
236
238
  class ResultBuilder
237
239
  attr_reader :test_case_duration
240
+
238
241
  def initialize(result)
239
242
  @test_case_duration = 0
240
243
  result.describe_to(self)
@@ -15,7 +15,8 @@ module Cucumber
15
15
  end
16
16
 
17
17
  def output_envelope(envelope)
18
- envelope.write_ndjson_to(@io)
18
+ @io.write(envelope.to_json)
19
+ @io.write("\n")
19
20
  end
20
21
  end
21
22
  end
@@ -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::Attachment::ContentEncoding::IDENTITY
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::Attachment::ContentEncoding::BASE64
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::TestCase::TestStep.new(
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::TestCase::TestStep.new(
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::TestCase::TestStep::StepMatchArgumentsList.new(
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::TestCase::TestStep::StepMatchArgumentsList::StepMatchArgument.new(
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::TestCase::TestStep::StepMatchArgumentsList::StepMatchArgument::Group.new(
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::TestStepFinished::TestStepResult.new(
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)
@@ -226,10 +226,11 @@ module Cucumber
226
226
  output_envelope(message)
227
227
  end
228
228
 
229
- def on_test_run_finished(*)
229
+ def on_test_run_finished(event)
230
230
  message = Cucumber::Messages::Envelope.new(
231
231
  test_run_finished: Cucumber::Messages::TestRunFinished.new(
232
- timestamp: time_to_timestamp(Time.now)
232
+ timestamp: time_to_timestamp(Time.now),
233
+ success: event.success
233
234
  )
234
235
  )
235
236
 
@@ -24,11 +24,9 @@ module Cucumber
24
24
  include Console
25
25
  include Io
26
26
  include Cucumber::Gherkin::Formatter::Escaping
27
- attr_reader :config, :options
27
+ attr_reader :config, :options, :current_feature_uri, :current_scenario_outline, :current_examples, :current_test_case, :in_scenario_outline, :print_background_steps
28
28
  private :config, :options
29
- attr_reader :current_feature_uri, :current_scenario_outline, :current_examples, :current_test_case
30
29
  private :current_feature_uri, :current_scenario_outline, :current_examples, :current_test_case
31
- attr_reader :in_scenario_outline, :print_background_steps
32
30
  private :in_scenario_outline, :print_background_steps
33
31
 
34
32
  def initialize(config)
@@ -105,16 +103,19 @@ module Cucumber
105
103
 
106
104
  def on_test_step_started(event)
107
105
  return if event.test_step.hook?
106
+
108
107
  print_step_header(current_test_case) if first_step_after_printing_background_steps?(event.test_step)
109
108
  end
110
109
 
111
110
  def on_test_step_finished(event)
112
111
  collect_snippet_data(event.test_step, @ast_lookup) if event.result.undefined?
113
112
  return if in_scenario_outline && !options[:expand]
113
+
114
114
  exception_to_be_printed = find_exception_to_be_printed(event.result)
115
115
  print_step_data(event.test_step, event.result) if print_step_data?(event, exception_to_be_printed)
116
116
  print_step_output
117
117
  return unless exception_to_be_printed
118
+
118
119
  print_exception(exception_to_be_printed, event.result.to_sym, 6)
119
120
  @exceptions << exception_to_be_printed
120
121
  end
@@ -127,6 +128,7 @@ module Cucumber
127
128
  else
128
129
  exception_to_be_printed = find_exception_to_be_printed(event.result)
129
130
  return unless exception_to_be_printed
131
+
130
132
  print_exception(exception_to_be_printed, event.result.to_sym, 6)
131
133
  @exceptions << exception_to_be_printed
132
134
  end
@@ -140,6 +142,7 @@ module Cucumber
140
142
 
141
143
  def attach(src, media_type)
142
144
  return unless media_type == 'text/x.cucumber.log+plain'
145
+
143
146
  @test_step_output.push src
144
147
  end
145
148
 
@@ -147,9 +150,11 @@ module Cucumber
147
150
 
148
151
  def find_exception_to_be_printed(result)
149
152
  return nil if result.ok?(options[:strict])
153
+
150
154
  result = result.with_filtered_backtrace(Cucumber::Formatter::BacktraceFilter)
151
155
  exception = result.failed? ? result.exception : result
152
156
  return nil if @exceptions.include?(exception)
157
+
153
158
  exception
154
159
  end
155
160
 
@@ -181,7 +186,7 @@ module Cucumber
181
186
  end
182
187
 
183
188
  def print_step_output
184
- @test_step_output.each { |message| @io.puts(format_string(message, :tag).indent(6)) }
189
+ @test_step_output.each { |message| @io.puts(indent(format_string(message, :tag), 6)) }
185
190
  @test_step_output = []
186
191
  end
187
192
 
@@ -196,6 +201,7 @@ module Cucumber
196
201
  def feature_has_background?
197
202
  feature_children = gherkin_document.feature.children
198
203
  return false if feature_children.empty?
204
+
199
205
  !feature_children.first.background.nil?
200
206
  end
201
207
 
@@ -239,6 +245,7 @@ module Cucumber
239
245
  def first_step_after_printing_background_steps?(test_step)
240
246
  return false unless print_background_steps
241
247
  return false unless test_step.location.lines.max >= current_test_case.location.lines.max
248
+
242
249
  @print_background_steps = false
243
250
  true
244
251
  end
@@ -259,33 +266,35 @@ module Cucumber
259
266
  end
260
267
  end
261
268
 
262
- def print_comments(up_to_line, indent)
269
+ def print_comments(up_to_line, indent_amount)
263
270
  comments = gherkin_document.comments
264
271
  return if comments.empty? || comments.length <= @next_comment_to_be_printed
265
- comments[@next_comment_to_be_printed..-1].each do |comment|
272
+
273
+ comments[@next_comment_to_be_printed..].each do |comment|
266
274
  if comment.location.line <= up_to_line
267
- @io.puts(format_string(comment.text.strip, :comment).indent(indent))
275
+ @io.puts(indent(format_string(comment.text.strip, :comment), indent_amount))
268
276
  @next_comment_to_be_printed += 1
269
277
  end
270
278
  break if @next_comment_to_be_printed >= comments.length
271
279
  end
272
280
  end
273
281
 
274
- def print_tags(tags, indent)
282
+ def print_tags(tags, indent_amount)
275
283
  return if !tags || tags.empty?
276
- @io.puts(tags.map { |tag| format_string(tag.name, :tag) }.join(' ').indent(indent))
284
+
285
+ @io.puts(indent(tags.map { |tag| format_string(tag.name, :tag) }.join(' '), indent_amount))
277
286
  end
278
287
 
279
288
  def print_feature_line(feature)
280
289
  print_keyword_name(feature.keyword, feature.name, 0)
281
290
  end
282
291
 
283
- def print_keyword_name(keyword, name, indent, location = nil)
292
+ def print_keyword_name(keyword, name, indent_amount, location = nil)
284
293
  line = "#{keyword}:"
285
294
  line += " #{name}"
286
- @io.print(line.indent(indent))
295
+ @io.print(indent(line, indent_amount))
287
296
  if location && options[:source]
288
- line_comment = format_string("# #{location}", :comment).indent(@source_indent - line.length - indent)
297
+ line_comment = indent(format_string("# #{location}", :comment), @source_indent - line.length - indent_amount)
289
298
  @io.print(line_comment)
290
299
  end
291
300
  @io.puts
@@ -293,6 +302,7 @@ module Cucumber
293
302
 
294
303
  def print_description(description)
295
304
  return unless description
305
+
296
306
  description.split("\n").each do |line|
297
307
  @io.puts(line)
298
308
  end
@@ -339,7 +349,7 @@ module Cucumber
339
349
  indent = options[:source] ? @source_indent - step_keyword.length - test_step.text.length - base_indent : nil
340
350
  print_comments(test_step.location.lines.max, base_indent)
341
351
  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(name_to_report.indent(base_indent))
352
+ @io.puts(indent(name_to_report, base_indent))
343
353
  print_multiline_argument(test_step, result, base_indent + 2) unless options[:no_multiline]
344
354
  @io.flush
345
355
  end
@@ -374,10 +384,10 @@ module Cucumber
374
384
  end
375
385
  end
376
386
 
377
- def print_data_table(data_table, status, indent)
387
+ def print_data_table(data_table, status, indent_amount)
378
388
  data_table.rows.each do |row|
379
- print_comments(row.location.line, indent)
380
- @io.puts format_string(gherkin_source.split("\n")[row.location.line - 1].strip, status).indent(indent)
389
+ print_comments(row.location.line, indent_amount)
390
+ @io.puts indent(format_string(gherkin_source.split("\n")[row.location.line - 1].strip, status), indent_amount)
381
391
  end
382
392
  end
383
393
 
@@ -393,18 +403,19 @@ module Cucumber
393
403
  @io.print(format_string(step_line, :skipped))
394
404
  if options[:source]
395
405
  comment_line = format_string("# #{current_feature_uri}:#{step.location.line}", :comment)
396
- @io.print(comment_line.indent(@source_indent - step_line.length))
406
+ @io.print(indent(comment_line, @source_indent - step_line.length))
397
407
  end
398
408
  @io.puts
399
409
  next if options[:no_multiline]
410
+
400
411
  print_doc_string(step.doc_string.content, :skipped, 6) unless step.doc_string.nil?
401
412
  print_data_table(step.data_table, :skipped, 6) unless step.data_table.nil?
402
413
  end
403
414
  @io.flush
404
415
  end
405
416
 
406
- def print_doc_string(content, status, indent)
407
- s = %("""\n#{content}\n""").indent(indent)
417
+ def print_doc_string(content, status, indent_amount)
418
+ s = indent(%("""\n#{content}\n"""), indent_amount)
408
419
  s = s.split("\n").map { |l| l =~ /^\s+$/ ? '' : l }.join("\n")
409
420
  @io.puts(format_string(s, status))
410
421
  end
@@ -416,15 +427,15 @@ module Cucumber
416
427
  print_description(examples.description)
417
428
  unless options[:expand]
418
429
  print_comments(examples.table_header.location.line, 6)
419
- @io.puts(gherkin_source.split("\n")[examples.table_header.location.line - 1].strip.indent(6))
430
+ @io.puts(indent(gherkin_source.split("\n")[examples.table_header.location.line - 1].strip, 6))
420
431
  end
421
432
  @io.flush
422
433
  end
423
434
 
424
435
  def print_row_data(test_case, result)
425
436
  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).indent(6))
427
- @io.print(format_string(@test_step_output.join(', '), :tag).indent(2)) unless @test_step_output.empty?
437
+ @io.print(indent(format_string(gherkin_source.split("\n")[test_case.location.lines.max - 1].strip, result.to_sym), 6))
438
+ @io.print(indent(format_string(@test_step_output.join(', '), :tag), 2)) unless @test_step_output.empty?
428
439
  @test_step_output = []
429
440
  @io.puts
430
441
  if result.failed? || result.pending?
@@ -444,7 +455,7 @@ module Cucumber
444
455
  language = ::Gherkin::Dialect.for(language_code)
445
456
  scenario_keyword = language.scenario_keywords[0]
446
457
  row = scenario_source(test_case).row
447
- expanded_name = '| ' + row.cells.map(&:value).join(' | ') + ' |'
458
+ expanded_name = "| #{row.cells.map(&:value).join(' | ')} |"
448
459
  @source_indent = calculate_source_indent_for_expanded_test_case(test_case, scenario_keyword, expanded_name)
449
460
  @io.puts
450
461
  print_keyword_name(scenario_keyword, expanded_name, 6, test_case.location)
@@ -58,6 +58,7 @@ module Cucumber
58
58
  progress(result.to_sym) if !test_step.hook? || result.failed?
59
59
 
60
60
  return if test_step.hook?
61
+
61
62
  collect_snippet_data(test_step, @ast_lookup) if result.undefined?
62
63
  @pending_step_matches << @matches[test_step.to_s] if result.pending?
63
64
  @failed_results << result if result.failed?
@@ -41,7 +41,7 @@ module Cucumber
41
41
  '',
42
42
  [
43
43
  'More information at ',
44
- link('https://reports.cucumber.io/docs/cucumber-ruby')
44
+ link('https://cucumber.io/docs/cucumber/environment-variables/')
45
45
  ],
46
46
  '',
47
47
  [
@@ -13,6 +13,7 @@ module Cucumber
13
13
 
14
14
  def hook_id(test_step)
15
15
  return @hook_id_by_test_step_id[test_step.id] if @hook_id_by_test_step_id.key?(test_step.id)
16
+
16
17
  raise TestStepUnknownError, "No hook found for #{test_step.id} }. Known: #{@hook_id_by_test_step_id.keys}"
17
18
  end
18
19
 
@@ -15,11 +15,13 @@ module Cucumber
15
15
 
16
16
  def attempt_by_test_case(test_case)
17
17
  raise TestCaseUnknownError, "No test case found for #{test_case.id} }. Known: #{@attempts_by_test_case_id.keys}" unless @attempts_by_test_case_id.key?(test_case.id)
18
+
18
19
  @attempts_by_test_case_id[test_case.id]
19
20
  end
20
21
 
21
22
  def test_case_started_id_by_test_case(test_case)
22
23
  raise TestCaseUnknownError, "No test case found for #{test_case.id} }. Known: #{@test_case_started_id_by_test_case_id.keys}" unless @test_case_started_id_by_test_case_id.key?(test_case.id)
24
+
23
25
  @test_case_started_id_by_test_case_id[test_case.id]
24
26
  end
25
27
 
@@ -15,6 +15,7 @@ module Cucumber
15
15
  test_case, result = *event.attributes
16
16
  if @config.strict.strict?(:flaky)
17
17
  next if result.ok?(@config.strict)
18
+
18
19
  add_to_failures(test_case)
19
20
  else
20
21
  unless @latest_failed_test_case.nil?
@@ -31,6 +32,7 @@ module Cucumber
31
32
  config.on_event :test_run_finished do
32
33
  add_to_failures(@latest_failed_test_case) unless @latest_failed_test_case.nil?
33
34
  next if @failures.empty?
35
+
34
36
  @io.print file_failures.join("\n")
35
37
  end
36
38
  end