cucumber 4.0.0.rc.3 → 4.0.0.rc.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +17 -1
  3. data/lib/cucumber/cli/options.rb +2 -1
  4. data/lib/cucumber/configuration.rb +5 -0
  5. data/lib/cucumber/deprecate.rb +29 -5
  6. data/lib/cucumber/errors.rb +3 -0
  7. data/lib/cucumber/events.rb +12 -7
  8. data/lib/cucumber/events/envelope.rb +9 -0
  9. data/lib/cucumber/events/hook_test_step_created.rb +13 -0
  10. data/lib/cucumber/events/test_case_created.rb +13 -0
  11. data/lib/cucumber/events/test_case_ready.rb +12 -0
  12. data/lib/cucumber/events/test_step_created.rb +13 -0
  13. data/lib/cucumber/filters.rb +1 -0
  14. data/lib/cucumber/filters/broadcast_test_case_ready_event.rb +12 -0
  15. data/lib/cucumber/formatter/console.rb +3 -8
  16. data/lib/cucumber/formatter/duration_extractor.rb +1 -1
  17. data/lib/cucumber/formatter/errors.rb +6 -0
  18. data/lib/cucumber/formatter/json.rb +15 -6
  19. data/lib/cucumber/formatter/junit.rb +1 -1
  20. data/lib/cucumber/formatter/message.rb +246 -0
  21. data/lib/cucumber/formatter/pretty.rb +3 -4
  22. data/lib/cucumber/formatter/query/hook_by_test_step.rb +31 -0
  23. data/lib/cucumber/formatter/query/pickle_by_test.rb +26 -0
  24. data/lib/cucumber/formatter/query/pickle_step_by_test_step.rb +26 -0
  25. data/lib/cucumber/formatter/query/step_definitions_by_test_step.rb +40 -0
  26. data/lib/cucumber/formatter/query/test_case_started_by_test_case.rb +40 -0
  27. data/lib/cucumber/gherkin/data_table_parser.rb +1 -1
  28. data/lib/cucumber/gherkin/steps_parser.rb +1 -1
  29. data/lib/cucumber/glue/hook.rb +18 -2
  30. data/lib/cucumber/glue/proto_world.rb +30 -18
  31. data/lib/cucumber/glue/registry_and_more.rb +31 -2
  32. data/lib/cucumber/glue/step_definition.rb +28 -4
  33. data/lib/cucumber/hooks.rb +8 -8
  34. data/lib/cucumber/multiline_argument.rb +1 -1
  35. data/lib/cucumber/multiline_argument/data_table.rb +17 -13
  36. data/lib/cucumber/runtime.rb +2 -2
  37. data/lib/cucumber/runtime/after_hooks.rb +6 -2
  38. data/lib/cucumber/runtime/before_hooks.rb +6 -2
  39. data/lib/cucumber/runtime/for_programming_languages.rb +1 -0
  40. data/lib/cucumber/runtime/step_hooks.rb +3 -2
  41. data/lib/cucumber/runtime/support_code.rb +3 -3
  42. data/lib/cucumber/runtime/user_interface.rb +2 -10
  43. data/lib/cucumber/version +1 -1
  44. metadata +40 -27
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ee911dfd2e4141ad61af0c67b5c9be6e169fe2d27bd2a9c407a590fe9eb0e72a
4
- data.tar.gz: 28fd680ef1f6f8d60bbcaba4a44c153d94d0a626c873aac9956b7ee8b36e8c7b
3
+ metadata.gz: 3cf95e63d73ffec417fa0dfc1f13e208355e78783a9f092d8e143dc5ca26d636
4
+ data.tar.gz: 869fe72a5dd449be55d00e2e72d8f78c236961141bf1cc85a7919bca426ec299
5
5
  SHA512:
6
- metadata.gz: 75974422135d45e115c32f685e88971eeec3f1c13473a0fc312412c4f73b665e84d439840642c67b93076a7499cf0130e28caddbb6761e5780b8e29b66e767eb
7
- data.tar.gz: d0eebdfd398decebf6fd0982306f31d501794bb8c5866452e0e65354a3af10da9d50c49cd08a137ec87193902cc2934e70340bed5a41b23ee59f84191c66add8
6
+ metadata.gz: 37c240a47d8127723e75c33051ff4e546a7e5a084a22400bb55e6d00d6d578ab7d5d7daf905259cba6625a512986fcacd4076810202e6f63dbffea16b366e9f5
7
+ data.tar.gz: 4556b216164535c0c2b39a1f2116b511f0cb1cccfee41cddb513073d0d887014edb38a632978347d1c127e228f1bd683317fbc62588bd4b497cdd51e10a3c550
@@ -10,7 +10,23 @@ Please visit [cucumber/CONTRIBUTING.md](https://github.com/cucumber/cucumber/blo
10
10
 
11
11
  ----
12
12
 
13
- ## [4.0.0.rc.2](https://github.com/cucumber/cucumber-ruby/compare/v4.0.0.rc.2...v4.0.0.rc.3)
13
+ ## [4.0.0.rc.4](https://github.com/cucumber/cucumber-ruby/compare/v4.0.0.rc.3...4.0.0.rc.4)
14
+
15
+
16
+ ### Added
17
+
18
+ * Add `message`formatter which produces `Cucumber::Messages` ndjson output.
19
+ * Comply with [`cucumber-compatibility-kit](https://github.com/cucumber/cucumber/tree/master/compatibility-kit)
20
+ * Methods `log` and `attach` can be used in step definitions to attach text or images
21
+
22
+ ### Deprecated
23
+
24
+ * `--format=json` in favor of the `message` formatter and the stand-alone JSON formatter
25
+ * `puts` in step definitions in favor of `log` ([cucumber#897](https://github.com/cucumber/cucumber/issues/897))
26
+ * `embed` in step definitions in favor of `attach` ([cucumber#897](https://github.com/cucumber/cucumber/issues/897))
27
+
28
+
29
+ ## [4.0.0.rc.3](https://github.com/cucumber/cucumber-ruby/compare/v4.0.0.rc.2...v4.0.0.rc.3)
14
30
 
15
31
  ### Changed
16
32
 
@@ -22,7 +22,8 @@ module Cucumber
22
22
  'stepdefs' => ['Cucumber::Formatter::Stepdefs', "Prints All step definitions with their locations. Same as\n" \
23
23
  "#{INDENT}the usage formatter, except that steps are not printed."],
24
24
  'junit' => ['Cucumber::Formatter::Junit', 'Generates a report similar to Ant+JUnit.'],
25
- 'json' => ['Cucumber::Formatter::Json', 'Prints the feature as JSON'],
25
+ 'json' => ['Cucumber::Formatter::Json', '[DEPRECATED] Prints the feature as JSON'],
26
+ 'message' => ['Cucumber::Formatter::Message', 'Outputs protobuf messages'],
26
27
  'summary' => ['Cucumber::Formatter::Summary', 'Summary output of feature and scenarios']
27
28
  }.freeze
28
29
  max = BUILTIN_FORMATS.keys.map(&:length).max
@@ -3,6 +3,7 @@
3
3
  require 'cucumber/constantize'
4
4
  require 'cucumber/cli/rerun_file'
5
5
  require 'cucumber/events'
6
+ require 'cucumber/messages'
6
7
  require 'cucumber/core/event_bus'
7
8
  require 'cucumber/core/test/result'
8
9
  require 'forwardable'
@@ -242,6 +243,10 @@ module Cucumber
242
243
  @options[:event_bus]
243
244
  end
244
245
 
246
+ def id_generator
247
+ @id_generator ||= Cucumber::Messages::IdGenerator::UUID.new
248
+ end
249
+
245
250
  private
246
251
 
247
252
  def default_options
@@ -5,13 +5,37 @@ require 'cucumber/gherkin/formatter/ansi_escapes'
5
5
 
6
6
  module Cucumber
7
7
  module Deprecate
8
- module ForUsers
9
- AnsiEscapes = Cucumber::Gherkin::Formatter::AnsiEscapes
8
+ class AnsiString
9
+ include Cucumber::Gherkin::Formatter::AnsiEscapes
10
+
11
+ def self.failure_message(message)
12
+ AnsiString.new.failure_message(message)
13
+ end
14
+
15
+ def failure_message(message)
16
+ failed + message + reset
17
+ end
18
+ end
10
19
 
20
+ class CliOption
21
+ def self.deprecate(stream, option, message, remove_after_version)
22
+ return if stream.nil?
23
+ stream.puts(
24
+ AnsiString.failure_message(
25
+ "\nWARNING: #{option} is deprecated" \
26
+ " and will be removed after version #{remove_after_version}.\n#{message}.\n"
27
+ )
28
+ )
29
+ end
30
+ end
31
+
32
+ module ForUsers
11
33
  def self.call(message, method, remove_after_version)
12
- STDERR.puts AnsiEscapes.failed + "\nWARNING: ##{method} is deprecated" \
13
- " and will be removed after version #{remove_after_version}. #{message}.\n" \
14
- "(Called from #{caller(3..3).first})" + AnsiEscapes.reset
34
+ STDERR.puts AnsiString.failure_message(
35
+ "\nWARNING: ##{method} is deprecated" \
36
+ " and will be removed after version #{remove_after_version}. #{message}.\n" \
37
+ "(Called from #{caller(3..3).first})"
38
+ )
15
39
  end
16
40
  end
17
41
 
@@ -49,4 +49,7 @@ module Cucumber
49
49
  super(messages.join("\n"))
50
50
  end
51
51
  end
52
+
53
+ class LogTypeInvalid < StandardError
54
+ end
52
55
  end
@@ -24,16 +24,21 @@ module Cucumber
24
24
 
25
25
  def self.registry
26
26
  Core::Events.build_registry(
27
- TestCaseStarted,
27
+ GherkinSourceParsed,
28
+ GherkinSourceRead,
29
+ HookTestStepCreated,
30
+ StepActivated,
31
+ StepDefinitionRegistered,
32
+ TestCaseCreated,
28
33
  TestCaseFinished,
34
+ TestCaseStarted,
35
+ TestCaseReady,
36
+ TestRunFinished,
37
+ TestRunStarted,
38
+ TestStepCreated,
29
39
  TestStepFinished,
30
40
  TestStepStarted,
31
- StepDefinitionRegistered,
32
- StepActivated,
33
- TestRunFinished,
34
- GherkinSourceRead,
35
- GherkinSourceParsed,
36
- TestRunStarted
41
+ Envelope
37
42
  )
38
43
  end
39
44
  end
@@ -0,0 +1,9 @@
1
+ require 'cucumber/core/events'
2
+
3
+ module Cucumber
4
+ module Events
5
+ class Envelope < Core::Event.new(:envelope)
6
+ attr_reader :envelope
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'cucumber/core/events'
4
+
5
+ module Cucumber
6
+ module Events
7
+ # Event fired when a step is created from a hook
8
+ class HookTestStepCreated < Core::Event.new(:test_step, :hook)
9
+ attr_reader :test_step
10
+ attr_reader :hook
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'cucumber/core/events'
4
+
5
+ module Cucumber
6
+ module Events
7
+ # Event fired when a Test::Case is created from a Pickle
8
+ class TestCaseCreated < Core::Event.new(:test_case, :pickle)
9
+ attr_reader :test_case
10
+ attr_reader :pickle
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'cucumber/core/events'
4
+
5
+ module Cucumber
6
+ module Events
7
+ # Event fired when a Test::Case is ready to be ran (matching has been done, hooks added etc)
8
+ class TestCaseReady < Core::Event.new(:test_case)
9
+ attr_reader :test_case
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'cucumber/core/events'
4
+
5
+ module Cucumber
6
+ module Events
7
+ # Event fired when a TestStep is created from a PickleStep
8
+ class TestStepCreated < Core::Event.new(:test_step, :pickle_step)
9
+ attr_reader :test_step
10
+ attr_reader :pickle_step
11
+ end
12
+ end
13
+ end
@@ -11,3 +11,4 @@ require 'cucumber/filters/quit'
11
11
  require 'cucumber/filters/randomizer'
12
12
  require 'cucumber/filters/retry'
13
13
  require 'cucumber/filters/tag_limits'
14
+ require 'cucumber/filters/broadcast_test_case_ready_event'
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Cucumber
4
+ module Filters
5
+ class BroadcastTestCaseReadyEvent < Core::Filter.new(:config)
6
+ def test_case(test_case)
7
+ config.notify :test_case_ready, test_case
8
+ test_case.describe_to(receiver)
9
+ end
10
+ end
11
+ end
12
+ end
@@ -158,16 +158,11 @@ module Cucumber
158
158
  end
159
159
  end
160
160
 
161
- def embed(file, mime_type, label)
162
- # no-op
163
- end
164
-
165
- def puts(*messages)
161
+ def attach(src, media_type)
162
+ return unless media_type == 'text/x.cucumber.log+plain'
166
163
  return unless @io
167
164
  @io.puts
168
- messages.each do |message|
169
- @io.puts(format_string(message, :tag))
170
- end
165
+ @io.puts(format_string(src, :tag))
171
166
  @io.flush
172
167
  end
173
168
 
@@ -25,7 +25,7 @@ module Cucumber
25
25
  duration.tap { |dur| @result_duration = dur.nanoseconds / 10**9.0 }
26
26
  end
27
27
 
28
- def embed(*) end
28
+ def attach(*) end
29
29
  end
30
30
  end
31
31
  end
@@ -0,0 +1,6 @@
1
+ module Cucumber
2
+ module Formatter
3
+ class TestCaseUnknownError < StandardError; end
4
+ class TestStepUnknownError < StandardError; end
5
+ end
6
+ end
@@ -5,6 +5,7 @@ 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'
8
9
 
9
10
  module Cucumber
10
11
  module Formatter
@@ -13,6 +14,14 @@ module Cucumber
13
14
  include Io
14
15
 
15
16
  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
+ '5.0.0'
23
+ )
24
+
16
25
  @io = ensure_io(config.out_stream)
17
26
  @ast_lookup = AstLookup.new(config)
18
27
  @feature_hashes = []
@@ -80,11 +89,11 @@ module Cucumber
80
89
  @io.write(MultiJson.dump(@feature_hashes, pretty: true))
81
90
  end
82
91
 
83
- def puts(message)
84
- test_step_output << message
85
- end
86
-
87
- def embed(src, mime_type, _label)
92
+ def attach(src, mime_type)
93
+ if mime_type == 'text/x.cucumber.log+plain'
94
+ test_step_output << src
95
+ return
96
+ end
88
97
  if File.file?(src)
89
98
  content = File.open(src, 'rb', &:read)
90
99
  data = encode64(content)
@@ -173,7 +182,7 @@ module Cucumber
173
182
  end
174
183
 
175
184
  def create_doc_string_hash(doc_string)
176
- content_type = doc_string.content_type || ''
185
+ content_type = doc_string.media_type || ''
177
186
  {
178
187
  value: doc_string.content,
179
188
  content_type: content_type,
@@ -239,7 +239,7 @@ module Cucumber
239
239
  duration.tap { |dur| @test_case_duration = dur.nanoseconds / 10**9.0 }
240
240
  end
241
241
 
242
- def embed(*) end
242
+ def attach(*) end
243
243
  end
244
244
  end
245
245
  end
@@ -0,0 +1,246 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'base64'
4
+ require 'cucumber/formatter/io'
5
+ require 'cucumber/formatter/backtrace_filter'
6
+ require 'cucumber/formatter/query/hook_by_test_step'
7
+ require 'cucumber/formatter/query/pickle_by_test'
8
+ require 'cucumber/formatter/query/pickle_step_by_test_step'
9
+ require 'cucumber/formatter/query/step_definitions_by_test_step'
10
+ require 'cucumber/formatter/query/test_case_started_by_test_case'
11
+
12
+ module Cucumber
13
+ module Formatter
14
+ # The formatter used for <tt>--format message</tt>
15
+ class Message
16
+ include Io
17
+ include Cucumber::Messages::TimeConversion
18
+
19
+ def initialize(config)
20
+ @config = config
21
+ @hook_by_test_step = Query::HookByTestStep.new(config)
22
+ @pickle_by_test = Query::PickleByTest.new(config)
23
+ @pickle_step_by_test_step = Query::PickleStepByTestStep.new(config)
24
+ @step_definitions_by_test_step = Query::StepDefinitionsByTestStep.new(config)
25
+ @test_case_started_by_test_case = Query::TestCaseStartedByTestCase.new(config)
26
+
27
+ @io = ensure_io(config.out_stream)
28
+ config.on_event :envelope, &method(:on_envelope)
29
+ config.on_event :gherkin_source_read, &method(:on_gherkin_source_read)
30
+ config.on_event :test_case_ready, &method(:on_test_case_ready)
31
+ config.on_event :test_run_started, &method(:on_test_run_started)
32
+ config.on_event :test_case_started, &method(:on_test_case_started)
33
+ config.on_event :test_step_started, &method(:on_test_step_started)
34
+ config.on_event :test_step_finished, &method(:on_test_step_finished)
35
+ config.on_event :test_case_finished, &method(:on_test_case_finished)
36
+ config.on_event :test_run_finished, &method(:on_test_run_finished)
37
+
38
+ @test_case_by_step_id = {}
39
+ @current_test_case_started_id = nil
40
+ @current_test_step_id = nil
41
+ end
42
+
43
+ def attach(src, media_type)
44
+ attachment_data = {
45
+ test_step_id: @current_test_step_id,
46
+ test_case_started_id: @current_test_case_started_id,
47
+ media_type: media_type
48
+ }
49
+
50
+ if media_type.start_with?('text/')
51
+ attachment_data[:text] = src
52
+ elsif src.respond_to? :read
53
+ attachment_data[:binary] = Base64.encode64(src.read)
54
+ else
55
+ attachment_data[:binary] = Base64.encode64(src)
56
+ end
57
+
58
+ message = Cucumber::Messages::Envelope.new(
59
+ attachment: Cucumber::Messages::Attachment.new(**attachment_data)
60
+ )
61
+
62
+ output_envelope(message)
63
+ end
64
+
65
+ private
66
+
67
+ def output_envelope(envelope)
68
+ envelope.write_ndjson_to(@io)
69
+ end
70
+
71
+ def on_envelope(event)
72
+ output_envelope(event.envelope)
73
+ end
74
+
75
+ def on_gherkin_source_read(event)
76
+ message = Cucumber::Messages::Envelope.new(
77
+ source: Cucumber::Messages::Source.new(
78
+ uri: event.path,
79
+ data: event.body,
80
+ media_type: 'text/x.cucumber.gherkin+plain'
81
+ )
82
+ )
83
+
84
+ output_envelope(message)
85
+ end
86
+
87
+ def on_test_case_ready(event)
88
+ event.test_case.test_steps.each do |step|
89
+ @test_case_by_step_id[step.id] = event.test_case
90
+ end
91
+
92
+ message = Cucumber::Messages::Envelope.new(
93
+ test_case: Cucumber::Messages::TestCase.new(
94
+ id: event.test_case.id,
95
+ pickle_id: @pickle_by_test.pickle_id(event.test_case),
96
+ test_steps: event.test_case.test_steps.map { |step| test_step_to_message(step) }
97
+ )
98
+ )
99
+
100
+ output_envelope(message)
101
+ end
102
+
103
+ def test_step_to_message(step)
104
+ return hook_step_to_message(step) if step.hook?
105
+
106
+ Cucumber::Messages::TestCase::TestStep.new(
107
+ id: step.id,
108
+ pickle_step_id: @pickle_step_by_test_step.pickle_step_id(step),
109
+ step_definition_ids: @step_definitions_by_test_step.step_definition_ids(step),
110
+ step_match_arguments_lists: step_match_arguments_lists(step)
111
+ )
112
+ end
113
+
114
+ def hook_step_to_message(step)
115
+ Cucumber::Messages::TestCase::TestStep.new(
116
+ id: step.id,
117
+ hook_id: @hook_by_test_step.hook_id(step)
118
+ )
119
+ end
120
+
121
+ def step_match_arguments_lists(step)
122
+ match_arguments = step_match_arguments(step)
123
+ [Cucumber::Messages::TestCase::TestStep::StepMatchArgumentsList.new(
124
+ step_match_arguments: match_arguments
125
+ )]
126
+ rescue Cucumber::Formatter::TestStepUnknownError
127
+ []
128
+ end
129
+
130
+ def step_match_arguments(step)
131
+ @step_definitions_by_test_step.step_match_arguments(step).map do |argument|
132
+ Cucumber::Messages::StepMatchArgument.new(
133
+ group: argument_group_to_message(argument.group),
134
+ parameter_type_name: argument.parameter_type.name
135
+ )
136
+ end
137
+ end
138
+
139
+ def argument_group_to_message(group)
140
+ Cucumber::Messages::StepMatchArgument::Group.new(
141
+ start: group.start,
142
+ value: group.value,
143
+ children: group.children.map { |child| argument_group_to_message(child) }
144
+ )
145
+ end
146
+
147
+ def on_test_run_started(*)
148
+ message = Cucumber::Messages::Envelope.new(
149
+ test_run_started: Cucumber::Messages::TestRunStarted.new(
150
+ timestamp: time_to_timestamp(Time.now)
151
+ )
152
+ )
153
+
154
+ output_envelope(message)
155
+ end
156
+
157
+ def on_test_case_started(event)
158
+ @current_test_case_started_id = test_case_started_id(event.test_case)
159
+
160
+ message = Cucumber::Messages::Envelope.new(
161
+ test_case_started: Cucumber::Messages::TestCaseStarted.new(
162
+ id: test_case_started_id(event.test_case),
163
+ test_case_id: event.test_case.id,
164
+ timestamp: time_to_timestamp(Time.now),
165
+ attempt: @test_case_started_by_test_case.attempt_by_test_case(event.test_case)
166
+ )
167
+ )
168
+
169
+ output_envelope(message)
170
+ end
171
+
172
+ def on_test_step_started(event)
173
+ @current_test_step_id = event.test_step.id
174
+ test_case = @test_case_by_step_id[event.test_step.id]
175
+
176
+ message = Cucumber::Messages::Envelope.new(
177
+ test_step_started: Cucumber::Messages::TestStepStarted.new(
178
+ test_step_id: event.test_step.id,
179
+ test_case_started_id: test_case_started_id(test_case),
180
+ timestamp: time_to_timestamp(Time.now)
181
+ )
182
+ )
183
+
184
+ output_envelope(message)
185
+ end
186
+
187
+ def on_test_step_finished(event)
188
+ test_case = @test_case_by_step_id[event.test_step.id]
189
+ result = event
190
+ .result
191
+ .with_filtered_backtrace(Cucumber::Formatter::BacktraceFilter)
192
+
193
+ result_message = result.to_message
194
+ if result.failed? || result.pending?
195
+ result_message = Cucumber::Messages::TestStepResult.new(
196
+ status: result_message.status,
197
+ duration: result_message.duration,
198
+ message: create_error_message(result)
199
+ )
200
+ end
201
+
202
+ message = Cucumber::Messages::Envelope.new(
203
+ test_step_finished: Cucumber::Messages::TestStepFinished.new(
204
+ test_step_id: event.test_step.id,
205
+ test_case_started_id: test_case_started_id(test_case),
206
+ test_step_result: result_message,
207
+ timestamp: time_to_timestamp(Time.now)
208
+ )
209
+ )
210
+
211
+ output_envelope(message)
212
+ end
213
+
214
+ def create_error_message(result)
215
+ message_element = result.failed? ? result.exception : result
216
+ message = "#{message_element.message} (#{message_element.class})"
217
+ ([message] + message_element.backtrace).join("\n")
218
+ end
219
+
220
+ def on_test_case_finished(event)
221
+ message = Cucumber::Messages::Envelope.new(
222
+ test_case_finished: Cucumber::Messages::TestCaseFinished.new(
223
+ test_case_started_id: test_case_started_id(event.test_case),
224
+ timestamp: time_to_timestamp(Time.now)
225
+ )
226
+ )
227
+
228
+ output_envelope(message)
229
+ end
230
+
231
+ def on_test_run_finished(*)
232
+ message = Cucumber::Messages::Envelope.new(
233
+ test_run_finished: Cucumber::Messages::TestRunFinished.new(
234
+ timestamp: time_to_timestamp(Time.now)
235
+ )
236
+ )
237
+
238
+ output_envelope(message)
239
+ end
240
+
241
+ def test_case_started_id(test_case)
242
+ @test_case_started_by_test_case.test_case_started_id_by_test_case(test_case)
243
+ end
244
+ end
245
+ end
246
+ end