cucumber 11.0.0 → 11.1.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.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +15 -6
  3. data/VERSION +1 -1
  4. data/lib/cucumber/cli/main.rb +22 -0
  5. data/lib/cucumber/configuration.rb +4 -0
  6. data/lib/cucumber/events/base.rb +25 -0
  7. data/lib/cucumber/events/envelope.rb +11 -2
  8. data/lib/cucumber/events/gherkin_source_parsed.rb +12 -3
  9. data/lib/cucumber/events/gherkin_source_read.rb +11 -3
  10. data/lib/cucumber/events/hook_test_step_created.rb +12 -2
  11. data/lib/cucumber/events/step_activated.rb +13 -7
  12. data/lib/cucumber/events/step_definition_registered.rb +12 -4
  13. data/lib/cucumber/events/test_case_created.rb +11 -3
  14. data/lib/cucumber/events/test_case_finished.rb +12 -4
  15. data/lib/cucumber/events/test_case_ready.rb +10 -4
  16. data/lib/cucumber/events/test_case_started.rb +11 -2
  17. data/lib/cucumber/events/test_run_finished.rb +10 -3
  18. data/lib/cucumber/events/test_run_hook_finished.rb +11 -3
  19. data/lib/cucumber/events/test_run_hook_started.rb +10 -1
  20. data/lib/cucumber/events/test_run_started.rb +11 -2
  21. data/lib/cucumber/events/test_step_created.rb +12 -2
  22. data/lib/cucumber/events/test_step_finished.rb +12 -2
  23. data/lib/cucumber/events/test_step_started.rb +11 -2
  24. data/lib/cucumber/events/undefined_parameter_type.rb +11 -3
  25. data/lib/cucumber/filters/fire_before_all_hooks.rb +36 -0
  26. data/lib/cucumber/formatter/console.rb +15 -7
  27. data/lib/cucumber/formatter/console_issues.rb +5 -5
  28. data/lib/cucumber/formatter/fail_fast.rb +3 -4
  29. data/lib/cucumber/formatter/global_hooks_summary.rb +36 -0
  30. data/lib/cucumber/formatter/json.rb +5 -3
  31. data/lib/cucumber/formatter/junit.rb +4 -6
  32. data/lib/cucumber/formatter/message.rb +7 -4
  33. data/lib/cucumber/formatter/message_builder.rb +207 -205
  34. data/lib/cucumber/formatter/pretty.rb +2 -5
  35. data/lib/cucumber/formatter/progress.rb +0 -2
  36. data/lib/cucumber/formatter/rerun.rb +10 -4
  37. data/lib/cucumber/formatter/usage.rb +1 -2
  38. data/lib/cucumber/glue/proto_world.rb +6 -4
  39. data/lib/cucumber/glue/registry_and_more.rb +98 -9
  40. data/lib/cucumber/runtime/user_interface.rb +2 -2
  41. data/lib/cucumber/runtime.rb +28 -9
  42. metadata +9 -14
  43. data/lib/cucumber/formatter/errors.rb +0 -9
  44. data/lib/cucumber/formatter/query/hook_by_test_step.rb +0 -34
  45. data/lib/cucumber/formatter/query/pickle_by_test.rb +0 -28
  46. data/lib/cucumber/formatter/query/step_definitions_by_test_step.rb +0 -42
  47. data/lib/cucumber/formatter/query/test_case_started_by_test_case.rb +0 -45
@@ -1,12 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'base64'
4
- require 'cucumber/formatter/backtrace_filter'
5
- require 'cucumber/formatter/query/hook_by_test_step'
6
- require 'cucumber/formatter/query/pickle_by_test'
7
- require 'cucumber/formatter/query/step_definitions_by_test_step'
8
- require 'cucumber/formatter/query/test_case_started_by_test_case'
4
+ require 'json'
9
5
 
6
+ require 'cucumber/formatter/backtrace_filter'
10
7
  require 'cucumber/query'
11
8
 
12
9
  module Cucumber
@@ -14,35 +11,32 @@ module Cucumber
14
11
  class MessageBuilder
15
12
  include Cucumber::Messages::Helpers::TimeConversion
16
13
  include Io
14
+ include Console
17
15
 
18
16
  def initialize(config)
19
17
  @config = config
20
-
21
- @hook_by_test_step = Query::HookByTestStep.new(config)
22
- @pickle_by_test = Query::PickleByTest.new(config)
23
- @step_definitions_by_test_step = Query::StepDefinitionsByTestStep.new(config)
24
- @test_case_started_by_test_case = Query::TestCaseStartedByTestCase.new(config)
25
-
18
+ @ast_lookup = AstLookup.new(config)
26
19
  @repository = Cucumber::Repository.new
27
- @query = Cucumber::Query.new(@repository)
28
20
 
29
- @test_run_started_id = config.id_generator.new_id
21
+ @test_run_started_id = config.test_run_started_id
22
+
23
+ # Fake Query objects
30
24
  @test_case_by_step_id = {}
25
+ @pickle_id_by_test_case_id = {}
31
26
  @pickle_id_step_by_test_step_id = {}
27
+ @hook_id_by_test_step_id = {}
28
+ @step_definition_ids_by_test_step_id = {}
29
+ @step_match_arguments_by_test_step_id = {}
32
30
 
33
31
  # Ensure all handlers for events occur after all ivars are instantiated
34
32
 
35
- config.on_event :envelope, &method(:on_envelope)
36
-
37
33
  config.on_event :gherkin_source_parsed, &method(:on_gherkin_source_parsed)
38
- config.on_event :gherkin_source_read, &method(:on_gherkin_source_read)
39
34
 
40
35
  config.on_event :hook_test_step_created, &method(:on_hook_test_step_created)
41
36
 
42
37
  config.on_event :step_activated, &method(:on_step_activated)
43
- config.on_event :step_definition_registered, &method(:on_step_definition_registered)
44
38
 
45
- # TODO: Handle TestCaseCreated
39
+ config.on_event :test_case_created, &method(:on_test_case_created)
46
40
  config.on_event :test_case_ready, &method(:on_test_case_ready)
47
41
  config.on_event :test_case_started, &method(:on_test_case_started)
48
42
  config.on_event :test_case_finished, &method(:on_test_case_finished)
@@ -50,69 +44,72 @@ module Cucumber
50
44
  config.on_event :test_run_started, &method(:on_test_run_started)
51
45
  config.on_event :test_run_finished, &method(:on_test_run_finished)
52
46
 
53
- config.on_event :test_run_hook_started, &method(:on_test_run_hook_started)
54
- config.on_event :test_run_hook_finished, &method(:on_test_run_hook_finished)
55
-
56
47
  config.on_event :test_step_created, &method(:on_test_step_created)
57
48
  config.on_event :test_step_started, &method(:on_test_step_started)
58
49
  config.on_event :test_step_finished, &method(:on_test_step_finished)
59
50
 
60
- config.on_event :undefined_parameter_type, &method(:on_undefined_parameter_type)
51
+ config.on_event :envelope, &method(:on_envelope)
61
52
  end
62
53
 
63
- def attach(src, media_type, filename)
64
- attachment_data = {
65
- test_step_id: @current_test_step_id,
66
- test_case_started_id: @current_test_case_started_id,
67
- media_type: media_type,
68
- file_name: filename,
69
- timestamp: time_to_timestamp(Time.now)
70
- }
54
+ def on_envelope(event)
55
+ @current_test_run_hook_started_id = event.envelope.test_run_hook_started.id if event.envelope.test_run_hook_started
56
+ end
71
57
 
72
- if media_type&.start_with?('text/')
73
- attachment_data[:content_encoding] = Cucumber::Messages::AttachmentContentEncoding::IDENTITY
74
- attachment_data[:body] = src
75
- else
76
- body = src.respond_to?(:read) ? src.read : src
58
+ def attach(src, media_type, filename, streamed_file)
59
+ attachment_data =
60
+ if @current_test_run_hook_started_id.nil?
61
+ {
62
+ test_step_id: @current_test_step_id,
63
+ test_case_started_id: @current_test_case_started_id,
64
+ media_type: media_type,
65
+ file_name: filename,
66
+ timestamp: time_to_timestamp(Time.now)
67
+ }
68
+ else
69
+ {
70
+ test_run_hook_started_id: @current_test_run_hook_started_id,
71
+ media_type: media_type,
72
+ file_name: filename,
73
+ timestamp: time_to_timestamp(Time.now)
74
+ }
75
+ end
76
+
77
+ if streamed_file
77
78
  attachment_data[:content_encoding] = Cucumber::Messages::AttachmentContentEncoding::BASE64
78
- attachment_data[:body] = Base64.strict_encode64(body)
79
+ attachment_data[:body] = Base64.strict_encode64(src)
80
+ else
81
+ attachment_data[:content_encoding] = Cucumber::Messages::AttachmentContentEncoding::IDENTITY
82
+ attachment_data[:body] = src.is_a?(Hash) ? src.to_json : src
79
83
  end
80
84
 
81
85
  message = Cucumber::Messages::Envelope.new(attachment: Cucumber::Messages::Attachment.new(**attachment_data))
82
- output_envelope(message)
86
+ @config.event_bus.envelope(message)
83
87
  end
84
88
 
85
89
  private
86
90
 
87
- def on_envelope(event)
88
- output_envelope(event.envelope)
89
- end
90
-
91
91
  def on_gherkin_source_parsed(_event)
92
92
  # TODO: Handle GherkinSourceParsed
93
93
  end
94
94
 
95
- def on_gherkin_source_read(event)
96
- message = Cucumber::Messages::Envelope.new(
97
- source: Cucumber::Messages::Source.new(
98
- uri: event.path,
99
- data: event.body,
100
- media_type: 'text/x.cucumber.gherkin+plain'
101
- )
102
- )
95
+ def on_hook_test_step_created(event)
96
+ @hook_id_by_test_step_id[event.test_step.id] = event.hook.id
97
+ end
103
98
 
104
- output_envelope(message)
99
+ def on_step_activated(event)
100
+ @step_definition_ids_by_test_step_id[event.test_step.id] << event.step_match.step_definition.id
101
+ @step_match_arguments_by_test_step_id[event.test_step.id] = event.step_match.step_arguments
105
102
  end
106
103
 
107
- def on_hook_test_step_created(_event)
108
- # TODO: Handle HookTestStepCreated
104
+ def on_test_case_created(event)
105
+ @pickle_id_by_test_case_id[event.test_case.id] = event.pickle.id
109
106
  end
110
107
 
111
108
  def on_test_case_ready(event)
112
109
  message = Cucumber::Messages::Envelope.new(
113
110
  test_case: Cucumber::Messages::TestCase.new(
114
111
  id: event.test_case.id,
115
- pickle_id: @pickle_by_test.pickle_id(event.test_case),
112
+ pickle_id: fake_query_pickle_id(event.test_case),
116
113
  test_steps: event.test_case.test_steps.map { |step| test_step_to_message(step) },
117
114
  test_run_started_id: @test_run_started_id
118
115
  )
@@ -121,63 +118,56 @@ module Cucumber
121
118
  # TODO: This may be a redundant update. But for now we're leaving this in whilst we're in the transitory phase
122
119
  @repository.update(message)
123
120
 
124
- # TODO: Switch this over to using the Repo Query object -> `test_step_by_id`
125
- # TODO: The finder in query is `find_test_step_by` (Using +TestStepStarted+ message)
126
- event.test_case.test_steps.each do |step|
127
- @test_case_by_step_id[step.id] = event.test_case
128
- end
129
-
130
- output_envelope(message)
121
+ @config.event_bus.envelope(message)
131
122
  end
132
123
 
133
- def test_step_to_message(step)
134
- return hook_step_to_message(step) if step.hook?
124
+ def on_test_case_started(event)
125
+ # For any new test_case_started events, we must ALWAYS generate a new id for a new run
126
+ @current_test_case_started_id = @config.id_generator.new_id
127
+ @current_test_run_hook_started_id = nil
135
128
 
136
- Cucumber::Messages::TestStep.new(
137
- id: step.id,
138
- # TODO: This "fake query" is only used once. It can likely be replace by `find_pickle_step_by` which
139
- # takes a +TestStep+ message from the repo directly.
140
- pickle_step_id: @pickle_id_step_by_test_step_id[step.id],
141
- step_definition_ids: @step_definitions_by_test_step.step_definition_ids(step),
142
- step_match_arguments_lists: step_match_arguments_lists(step)
143
- )
144
- end
129
+ find_all_test_case_started_by_test_case_id =
130
+ @repository.test_case_started_by_id
131
+ .values
132
+ .select { |test_case_started| test_case_started.test_case_id == event.test_case.id }
145
133
 
146
- def hook_step_to_message(step)
147
- Cucumber::Messages::TestStep.new(
148
- id: step.id,
149
- hook_id: @hook_by_test_step.hook_id(step)
134
+ # If no TestCaseStarted messages exist. We must be on attempt 1 (Hence the .to_i casting for a `nil` value)
135
+ attempts_previously_made = find_all_test_case_started_by_test_case_id.map(&:attempt).max.to_i
136
+
137
+ message = Cucumber::Messages::Envelope.new(
138
+ test_case_started: Cucumber::Messages::TestCaseStarted.new(
139
+ id: @current_test_case_started_id,
140
+ test_case_id: event.test_case.id,
141
+ timestamp: time_to_timestamp(Time.now),
142
+ attempt: attempts_previously_made + 1
143
+ )
150
144
  )
151
- end
152
145
 
153
- def step_match_arguments_lists(step)
154
- match_arguments = step_match_arguments(step)
155
- [Cucumber::Messages::StepMatchArgumentsList.new(
156
- step_match_arguments: match_arguments
157
- )]
158
- rescue Cucumber::Formatter::TestStepUnknownError
159
- []
146
+ @config.event_bus.envelope(message)
147
+ @repository.update(message)
160
148
  end
161
149
 
162
- def step_match_arguments(step)
163
- @step_definitions_by_test_step.step_match_arguments(step).map do |argument|
164
- Cucumber::Messages::StepMatchArgument.new(
165
- group: argument_group_to_message(argument.group),
166
- parameter_type_name: parameter_type_name(argument)
167
- )
168
- end
169
- end
150
+ def on_test_case_finished(event)
151
+ test_case_started_id =
152
+ @repository.test_case_started_by_id
153
+ .values
154
+ .detect { |test_case_started_message| test_case_started_message.test_case_id == event.test_case.id }
155
+ .id
170
156
 
171
- def argument_group_to_message(group)
172
- Cucumber::Messages::Group.new(
173
- start: group.start,
174
- value: group.value,
175
- children: group.children&.map { |child| argument_group_to_message(child) }
157
+ test_case_started_message = @repository.test_case_started_by_id[test_case_started_id]
158
+ max_attempts = @config.retry_attempts
159
+ retries_attempted = test_case_started_message.attempt - 1
160
+ will_be_retried = event.result.failed? && (retries_attempted < max_attempts)
161
+
162
+ message = Cucumber::Messages::Envelope.new(
163
+ test_case_finished: Cucumber::Messages::TestCaseFinished.new(
164
+ test_case_started_id: test_case_started_id,
165
+ timestamp: time_to_timestamp(Time.now),
166
+ will_be_retried: will_be_retried
167
+ )
176
168
  )
177
- end
178
169
 
179
- def parameter_type_name(step_match_argument)
180
- step_match_argument.parameter_type&.name if step_match_argument.respond_to?(:parameter_type)
170
+ @config.event_bus.envelope(message)
181
171
  end
182
172
 
183
173
  def on_test_run_started(*)
@@ -188,63 +178,63 @@ module Cucumber
188
178
  )
189
179
  )
190
180
 
191
- output_envelope(message)
181
+ @config.event_bus.envelope(message)
192
182
  end
193
183
 
194
- def on_test_case_started(event)
195
- @current_test_case_started_id = test_case_started_id(event.test_case)
196
-
184
+ def on_test_run_finished(event)
197
185
  message = Cucumber::Messages::Envelope.new(
198
- test_case_started: Cucumber::Messages::TestCaseStarted.new(
199
- id: test_case_started_id(event.test_case),
200
- test_case_id: event.test_case.id,
186
+ test_run_finished: Cucumber::Messages::TestRunFinished.new(
201
187
  timestamp: time_to_timestamp(Time.now),
202
- attempt: @test_case_started_by_test_case.attempt_by_test_case(event.test_case)
188
+ success: event.success,
189
+ test_run_started_id: @test_run_started_id
203
190
  )
204
191
  )
205
192
 
206
- output_envelope(message)
193
+ @config.event_bus.envelope(message)
207
194
  end
208
195
 
209
196
  def on_test_step_created(event)
210
197
  @pickle_id_step_by_test_step_id[event.test_step.id] = event.pickle_step.id
211
- test_step_to_message(event.test_step)
212
- # TODO: We need to determine what message to output here (Unsure - Placeholder added)
213
- # message = Cucumber::Messages::Envelope.new(
214
- # pickle: {
215
- # id: '',
216
- # uri: '',
217
- # location: nil,
218
- # name: '',
219
- # language: '',
220
- # steps: test_step_to_message(event.test_step),
221
- # tags: [],
222
- # ast_node_ids: []
223
- # }
224
- # )
225
- #
226
- # output_envelope(message)
198
+ @step_definition_ids_by_test_step_id[event.test_step.id] = []
227
199
  end
228
200
 
229
201
  def on_test_step_started(event)
230
202
  @current_test_step_id = event.test_step.id
231
- test_case = @test_case_by_step_id[event.test_step.id]
203
+ find_test_case_by_step_id =
204
+ @repository.test_case_by_id
205
+ .values
206
+ .detect { |test_case_message| test_case_message.test_steps.any? { |step_message| step_message.id == event.test_step.id } }
207
+
208
+ find_test_case_started_by_test_case =
209
+ @repository.test_case_started_by_id
210
+ .values
211
+ .select { |test_case_started_message| test_case_started_message.test_case_id == find_test_case_by_step_id.id }
212
+ .max_by(&:attempt)
232
213
 
233
214
  message = Cucumber::Messages::Envelope.new(
234
215
  test_step_started: Cucumber::Messages::TestStepStarted.new(
235
216
  test_step_id: event.test_step.id,
236
- test_case_started_id: test_case_started_id(test_case),
217
+ test_case_started_id: find_test_case_started_by_test_case.id,
237
218
  timestamp: time_to_timestamp(Time.now)
238
219
  )
239
220
  )
240
221
 
241
- output_envelope(message)
222
+ @config.event_bus.envelope(message)
242
223
  end
243
224
 
244
225
  def on_test_step_finished(event)
245
- test_case = @test_case_by_step_id[event.test_step.id]
246
- result = event.result.with_filtered_backtrace(Cucumber::Formatter::BacktraceFilter)
226
+ find_test_case_by_step_id =
227
+ @repository.test_case_by_id
228
+ .values
229
+ .detect { |test_case_message| test_case_message.test_steps.any? { |step_message| step_message.id == event.test_step.id } }
230
+
231
+ find_test_case_started_by_test_case =
232
+ @repository.test_case_started_by_id
233
+ .values
234
+ .select { |test_case_started_message| test_case_started_message.test_case_id == find_test_case_by_step_id.id }
235
+ .max_by(&:attempt)
247
236
 
237
+ result = event.result.with_filtered_backtrace(Cucumber::Formatter::BacktraceFilter)
248
238
  result_message = result.to_message
249
239
  if result.failed? || result.pending?
250
240
  message_element = result.failed? ? result.exception : result
@@ -257,126 +247,138 @@ module Cucumber
257
247
  )
258
248
  end
259
249
 
250
+ output_snippet_envelope(event)
251
+
260
252
  message = Cucumber::Messages::Envelope.new(
261
253
  test_step_finished: Cucumber::Messages::TestStepFinished.new(
262
254
  test_step_id: event.test_step.id,
263
- test_case_started_id: test_case_started_id(test_case),
255
+ test_case_started_id: find_test_case_started_by_test_case.id,
264
256
  test_step_result: result_message,
265
257
  timestamp: time_to_timestamp(Time.now)
266
258
  )
267
259
  )
268
260
 
269
- output_envelope(message)
261
+ @config.event_bus.envelope(message)
270
262
  end
271
263
 
272
- def create_error_message(message_element)
273
- <<~ERROR_MESSAGE
274
- #{message_element.message} (#{message_element.class})
275
- #{message_element.backtrace}
276
- ERROR_MESSAGE
277
- end
264
+ def output_snippet_envelope(event)
265
+ return unless event.result.undefined?
278
266
 
279
- def create_exception_object(result, message_element)
280
- return unless result.failed?
267
+ collect_snippet_data(event.test_step, @ast_lookup)
268
+ snippet_text_proc = lambda do |step_keyword, step_name, multiline_arg|
269
+ snippet_text(step_keyword, step_name, multiline_arg)
270
+ end
281
271
 
282
- Cucumber::Messages::Exception.new(
283
- type: message_element.class,
284
- message: message_element.message,
285
- stack_trace: message_element.backtrace.join("\n")
286
- )
272
+ message = generate_snippet_envelope(snippet_text_proc, event)
273
+ @config.event_bus.envelope(message)
274
+ # To ensure we don't redistribute the "same" snippets over and over again
275
+ snippets_input.clear
287
276
  end
288
277
 
289
- def on_test_case_finished(event)
290
- test_case_started_id = test_case_started_id(event.test_case)
291
- test_case_started_message = @repository.test_case_started_by_id[test_case_started_id]
292
- max_attempts = @config.retry_attempts
293
- # See "fake query" for reason this is index shifted
294
- retries_attempted = test_case_started_message.attempt - 1
295
- will_be_retried = event.result.failed? && (retries_attempted < max_attempts)
278
+ def generate_snippet_envelope(snippet_text_proc, event)
279
+ snippets_array = snippets_input.map do |data|
280
+ snippet_text_proc.call(data.actual_keyword, data.step.text, data.step.multiline_arg)
281
+ end.uniq
296
282
 
297
- message = Cucumber::Messages::Envelope.new(
298
- test_case_finished: Cucumber::Messages::TestCaseFinished.new(
299
- test_case_started_id: test_case_started_id,
300
- timestamp: time_to_timestamp(Time.now),
301
- will_be_retried: will_be_retried
283
+ Cucumber::Messages::Envelope.new(
284
+ suggestion: Cucumber::Messages::Suggestion.new(
285
+ id: @config.id_generator.new_id,
286
+ pickle_step_id: @repository.test_step_by_id[event.test_step.id].pickle_step_id,
287
+ snippets: snippets_array.map { |code_snippet| Cucumber::Messages::Snippet.new(language: 'ruby', code: code_snippet) }
302
288
  )
303
289
  )
304
-
305
- output_envelope(message)
306
290
  end
307
291
 
308
- def on_test_run_finished(event)
292
+ def on_undefined_parameter_type(event)
309
293
  message = Cucumber::Messages::Envelope.new(
310
- test_run_finished: Cucumber::Messages::TestRunFinished.new(
311
- timestamp: time_to_timestamp(Time.now),
312
- success: event.success,
313
- test_run_started_id: @test_run_started_id
294
+ undefined_parameter_type: Cucumber::Messages::UndefinedParameterType.new(
295
+ name: event.type_name,
296
+ expression: event.expression
314
297
  )
315
298
  )
316
299
 
317
- output_envelope(message)
300
+ @config.event_bus.envelope(message)
318
301
  end
319
302
 
320
- def on_step_activated(event)
321
- # TODO: Handle StepActivated
303
+ def test_step_to_message(step)
304
+ return hook_step_to_message(step) if step.hook?
305
+
306
+ Cucumber::Messages::TestStep.new(
307
+ id: step.id,
308
+ pickle_step_id: @pickle_id_step_by_test_step_id[step.id],
309
+ step_definition_ids: fake_query_step_definition_ids(step),
310
+ step_match_arguments_lists: step_match_arguments_lists(step)
311
+ )
322
312
  end
323
313
 
324
- def on_step_definition_registered(event)
325
- output_envelope(event.step_definition.to_envelope)
314
+ def hook_step_to_message(step)
315
+ Cucumber::Messages::TestStep.new(
316
+ id: step.id,
317
+ hook_id: @hook_id_by_test_step_id[step.id]
318
+ )
326
319
  end
327
320
 
328
- def on_test_run_hook_started(event)
329
- @current_test_run_hook_started_id = @config.id_generator.new_id
321
+ def step_match_arguments_lists(step)
322
+ match_arguments = step_match_arguments(step)
323
+ if match_arguments.nil?
324
+ []
325
+ else
326
+ [Cucumber::Messages::StepMatchArgumentsList.new(step_match_arguments: match_arguments)]
327
+ end
328
+ end
330
329
 
331
- message = Cucumber::Messages::Envelope.new(
332
- test_run_hook_started: Cucumber::Messages::TestRunHookStarted.new(
333
- id: @current_test_run_hook_started_id,
334
- hook_id: event.hook.id,
335
- test_run_started_id: @test_run_started_id,
336
- timestamp: time_to_timestamp(Time.now)
330
+ def step_match_arguments(step)
331
+ fake_query_step_match_arguments(step)&.map do |argument|
332
+ Cucumber::Messages::StepMatchArgument.new(
333
+ group: argument_group_to_message(argument.group),
334
+ parameter_type_name: parameter_type_name(argument)
337
335
  )
336
+ end
337
+ end
338
+
339
+ def argument_group_to_message(group)
340
+ Cucumber::Messages::Group.new(
341
+ start: group.start,
342
+ value: group.value,
343
+ children: group.children&.map { |child| argument_group_to_message(child) }
338
344
  )
345
+ end
339
346
 
340
- output_envelope(message)
347
+ def parameter_type_name(step_match_argument)
348
+ step_match_argument.parameter_type&.name if step_match_argument.respond_to?(:parameter_type)
341
349
  end
342
350
 
343
- def on_test_run_hook_finished(event)
344
- result = event.test_result
345
- result_message = result.to_message
351
+ def create_error_message(message_element)
352
+ <<~ERROR_MESSAGE
353
+ #{message_element.message} (#{message_element.class})
354
+ #{message_element.backtrace}
355
+ ERROR_MESSAGE
356
+ end
346
357
 
347
- if result.failed?
348
- result_message = Cucumber::Messages::TestStepResult.new(
349
- status: result_message.status,
350
- duration: result_message.duration,
351
- message: create_error_message(result.exception),
352
- exception: create_exception_object(result, result.exception)
353
- )
354
- end
358
+ def create_exception_object(result, message_element)
359
+ return unless result.failed?
355
360
 
356
- message = Cucumber::Messages::Envelope.new(
357
- test_run_hook_finished: Cucumber::Messages::TestRunHookFinished.new(
358
- test_run_hook_started_id: @current_test_run_hook_started_id,
359
- timestamp: time_to_timestamp(Time.now),
360
- result: result_message
361
- )
361
+ Cucumber::Messages::Exception.new(
362
+ type: message_element.class,
363
+ message: message_element.message,
364
+ stack_trace: message_element.backtrace.join("\n")
362
365
  )
366
+ end
363
367
 
364
- output_envelope(message)
368
+ def fake_query_hook_id(test_step)
369
+ @hook_id_by_test_step_id.fetch(test_step.id)
365
370
  end
366
371
 
367
- def on_undefined_parameter_type(event)
368
- message = Cucumber::Messages::Envelope.new(
369
- undefined_parameter_type: Cucumber::Messages::UndefinedParameterType.new(
370
- name: event.type_name,
371
- expression: event.expression
372
- )
373
- )
372
+ def fake_query_pickle_id(test_case)
373
+ @pickle_id_by_test_case_id.fetch(test_case.id)
374
+ end
374
375
 
375
- output_envelope(message)
376
+ def fake_query_step_definition_ids(test_step)
377
+ @step_definition_ids_by_test_step_id.fetch(test_step.id)
376
378
  end
377
379
 
378
- def test_case_started_id(test_case)
379
- @test_case_started_by_test_case.test_case_started_id_by_test_case(test_case)
380
+ def fake_query_step_match_arguments(test_step)
381
+ @step_match_arguments_by_test_step_id.fetch(test_step.id, nil)
380
382
  end
381
383
  end
382
384
  end
@@ -33,8 +33,6 @@ module Cucumber
33
33
  @io = ensure_io(config.out_stream, config.error_stream)
34
34
  @config = config
35
35
  @options = config.to_hash
36
- @snippets_input = []
37
- @undefined_parameter_types = []
38
36
  @total_duration = 0
39
37
  @exceptions = []
40
38
  @gherkin_sources = {}
@@ -73,8 +71,7 @@ module Cucumber
73
71
  end
74
72
 
75
73
  def on_step_activated(event)
76
- test_step, step_match = *event.attributes
77
- @step_matches[test_step.to_s] = step_match
74
+ @step_matches[event.test_step.to_s] = event.step_match
78
75
  end
79
76
 
80
77
  def on_test_case_started(event)
@@ -140,7 +137,7 @@ module Cucumber
140
137
  print_summary
141
138
  end
142
139
 
143
- def attach(src, media_type, filename)
140
+ def attach(src, media_type, filename, _streamed_file)
144
141
  return unless media_type == 'text/x.cucumber.log+plain'
145
142
 
146
143
  if filename
@@ -20,8 +20,6 @@ module Cucumber
20
20
  def initialize(config)
21
21
  @config = config
22
22
  @io = ensure_io(config.out_stream, config.error_stream)
23
- @snippets_input = []
24
- @undefined_parameter_types = []
25
23
  @total_duration = 0
26
24
  @matches = {}
27
25
  @pending_step_matches = []
@@ -1,17 +1,23 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'cucumber/formatter/io'
4
- require 'cucumber/formatter/message_builder'
4
+ require 'cucumber/query'
5
5
 
6
6
  module Cucumber
7
7
  module Formatter
8
- class Rerun < MessageBuilder
8
+ class Rerun
9
+ include Io
10
+
9
11
  def initialize(config)
12
+ @config = config
10
13
  @io = ensure_io(config.out_stream, config.error_stream)
11
- super(config)
14
+ @repository = Cucumber::Repository.new
15
+ @query = Cucumber::Query.new(@repository)
16
+ config.on_event :envelope, &method(:output_envelope)
12
17
  end
13
18
 
14
- def output_envelope(envelope)
19
+ def output_envelope(event)
20
+ envelope = event.envelope
15
21
  @repository.update(envelope)
16
22
  finish_report if envelope.test_run_finished
17
23
  end
@@ -32,8 +32,7 @@ module Cucumber
32
32
  @total_duration = 0
33
33
  @matches = {}
34
34
  config.on_event :step_activated do |event|
35
- test_step, step_match = *event.attributes
36
- @matches[test_step.to_s] = step_match
35
+ @matches[event.test_step.to_s] = event.step_match
37
36
  end
38
37
  config.on_event :step_definition_registered, &method(:on_step_definition_registered)
39
38
  end