cucumber 2.0.0.beta.3 → 2.0.0.beta.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/History.md +20 -3
- data/cucumber.gemspec +2 -1
- data/examples/tcl/features/step_definitions/fib_steps.rb +1 -1
- data/features/docs/extending_cucumber/custom_formatter.feature +65 -7
- data/features/docs/formatters/debug_formatter.feature +24 -17
- data/features/docs/formatters/pretty_formatter.feature +42 -0
- data/features/docs/formatters/rerun_formatter.feature +3 -2
- data/lib/cucumber/cli/configuration.rb +3 -7
- data/lib/cucumber/cli/main.rb +1 -1
- data/lib/cucumber/{runtime → filters}/gated_receiver.rb +5 -1
- data/lib/cucumber/filters/quit.rb +24 -0
- data/lib/cucumber/filters/randomizer.rb +36 -0
- data/lib/cucumber/filters/tag_limits.rb +40 -0
- data/lib/cucumber/{runtime → filters}/tag_limits/test_case_index.rb +4 -2
- data/lib/cucumber/{runtime → filters}/tag_limits/verifier.rb +4 -2
- data/lib/cucumber/formatter/console.rb +2 -2
- data/lib/cucumber/formatter/debug.rb +1 -8
- data/lib/cucumber/formatter/fanout.rb +27 -0
- data/lib/cucumber/formatter/gherkin_formatter_adapter.rb +1 -3
- data/lib/cucumber/formatter/html.rb +12 -4
- data/lib/cucumber/formatter/ignore_missing_messages.rb +20 -0
- data/lib/cucumber/formatter/junit.rb +2 -2
- data/lib/cucumber/formatter/legacy_api/adapter.rb +1008 -0
- data/lib/cucumber/formatter/legacy_api/ast.rb +374 -0
- data/lib/cucumber/formatter/legacy_api/results.rb +51 -0
- data/lib/cucumber/formatter/legacy_api/runtime_facade.rb +30 -0
- data/lib/cucumber/formatter/pretty.rb +4 -0
- data/lib/cucumber/formatter/rerun.rb +14 -88
- data/lib/cucumber/language_support/language_methods.rb +0 -54
- data/lib/cucumber/multiline_argument/data_table.rb +3 -4
- data/lib/cucumber/platform.rb +1 -1
- data/lib/cucumber/runtime.rb +41 -107
- data/spec/cucumber/{runtime → filters}/gated_receiver_spec.rb +3 -3
- data/spec/cucumber/{runtime → filters}/tag_limits/test_case_index_spec.rb +3 -3
- data/spec/cucumber/{runtime → filters}/tag_limits/verifier_spec.rb +4 -4
- data/spec/cucumber/{runtime/tag_limits/filter_spec.rb → filters/tag_limits_spec.rb} +6 -6
- data/spec/cucumber/formatter/debug_spec.rb +39 -530
- data/spec/cucumber/formatter/html_spec.rb +56 -0
- data/spec/cucumber/formatter/legacy_api/adapter_spec.rb +1902 -0
- data/spec/cucumber/formatter/pretty_spec.rb +128 -0
- data/spec/cucumber/formatter/rerun_spec.rb +106 -0
- data/spec/cucumber/formatter/spec_helper.rb +6 -2
- data/spec/cucumber/rb_support/rb_language_spec.rb +2 -2
- data/spec/cucumber/rb_support/rb_step_definition_spec.rb +1 -1
- data/spec/cucumber/runtime_spec.rb +1 -5
- data/spec/spec_helper.rb +2 -0
- metadata +44 -29
- data/features/docs/extending_cucumber/formatter_callbacks.feature +0 -370
- data/features/docs/output_from_hooks.feature +0 -128
- data/lib/cucumber/reports/legacy_formatter.rb +0 -1349
- data/lib/cucumber/runtime/results.rb +0 -64
- data/lib/cucumber/runtime/tag_limits.rb +0 -15
- data/lib/cucumber/runtime/tag_limits/filter.rb +0 -31
- data/spec/cucumber/reports/legacy_formatter_spec.rb +0 -1860
- data/spec/cucumber/runtime/results_spec.rb +0 -88
@@ -1,1349 +0,0 @@
|
|
1
|
-
require 'forwardable'
|
2
|
-
require 'delegate'
|
3
|
-
require 'cucumber/errors'
|
4
|
-
require 'cucumber/multiline_argument'
|
5
|
-
|
6
|
-
module Cucumber
|
7
|
-
module Reports
|
8
|
-
|
9
|
-
class FormatterWrapper < BasicObject
|
10
|
-
attr_reader :formatters
|
11
|
-
private :formatters
|
12
|
-
|
13
|
-
def initialize(formatters)
|
14
|
-
@formatters = formatters
|
15
|
-
end
|
16
|
-
|
17
|
-
def method_missing(message, *args)
|
18
|
-
formatters.each do |formatter|
|
19
|
-
formatter.send(message, *args) if formatter.respond_to?(message)
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
def respond_to_missing?(name, include_private = false)
|
24
|
-
formatters.any? { |formatter| formatter.respond_to?(name, include_private) }
|
25
|
-
end
|
26
|
-
|
27
|
-
end
|
28
|
-
|
29
|
-
LegacyFormatter = Struct.new(:runtime, :formatter) do
|
30
|
-
|
31
|
-
def initialize(runtime, formatters)
|
32
|
-
super runtime, FormatterWrapper.new(formatters)
|
33
|
-
end
|
34
|
-
|
35
|
-
extend Forwardable
|
36
|
-
|
37
|
-
def_delegators :formatter,
|
38
|
-
:ask
|
39
|
-
|
40
|
-
def_delegators :printer,
|
41
|
-
:before_test_case,
|
42
|
-
:before_test_step,
|
43
|
-
:after_test_step
|
44
|
-
|
45
|
-
def after_test_case(test_case, result)
|
46
|
-
record_test_case_result(test_case, result)
|
47
|
-
printer.after_test_case(test_case, result)
|
48
|
-
end
|
49
|
-
|
50
|
-
def puts(*messages)
|
51
|
-
printer.puts(messages)
|
52
|
-
end
|
53
|
-
|
54
|
-
def embed(src, mime_type, label)
|
55
|
-
printer.embed(src, mime_type, label)
|
56
|
-
end
|
57
|
-
|
58
|
-
def done
|
59
|
-
printer.after
|
60
|
-
end
|
61
|
-
|
62
|
-
private
|
63
|
-
|
64
|
-
def printer
|
65
|
-
@printer ||= FeaturesPrinter.new(formatter, runtime).before
|
66
|
-
end
|
67
|
-
|
68
|
-
def record_test_case_result(test_case, result)
|
69
|
-
scenario = LegacyResultBuilder.new(result).scenario(test_case.name, test_case.location)
|
70
|
-
runtime.record_result(scenario)
|
71
|
-
end
|
72
|
-
|
73
|
-
require 'cucumber/core/test/timer'
|
74
|
-
FeaturesPrinter = Struct.new(:formatter, :runtime) do
|
75
|
-
extend Forwardable
|
76
|
-
|
77
|
-
def before
|
78
|
-
timer.start
|
79
|
-
formatter.before_features(nil)
|
80
|
-
self
|
81
|
-
end
|
82
|
-
|
83
|
-
def before_test_case(test_case)
|
84
|
-
test_case.describe_source_to(self)
|
85
|
-
@child.before_test_case(test_case)
|
86
|
-
end
|
87
|
-
|
88
|
-
def before_test_step(*args)
|
89
|
-
@child.before_test_step(*args)
|
90
|
-
end
|
91
|
-
|
92
|
-
def after_test_step(test_step, result)
|
93
|
-
@child.after_test_step(test_step, result)
|
94
|
-
end
|
95
|
-
|
96
|
-
def after_test_case(*args)
|
97
|
-
@child.after_test_case(*args)
|
98
|
-
end
|
99
|
-
|
100
|
-
def feature(node, *)
|
101
|
-
if node != @current_feature
|
102
|
-
@child.after if @child
|
103
|
-
@child = FeaturePrinter.new(formatter, runtime, node).before
|
104
|
-
@current_feature = node
|
105
|
-
end
|
106
|
-
end
|
107
|
-
|
108
|
-
def scenario(node, *)
|
109
|
-
end
|
110
|
-
|
111
|
-
def scenario_outline(node, *)
|
112
|
-
end
|
113
|
-
|
114
|
-
def examples_table(node, *)
|
115
|
-
end
|
116
|
-
|
117
|
-
def examples_table_row(node, *)
|
118
|
-
end
|
119
|
-
|
120
|
-
def after
|
121
|
-
@child.after if @child
|
122
|
-
formatter.after_features Legacy::Ast::Features.new(timer.sec)
|
123
|
-
self
|
124
|
-
end
|
125
|
-
|
126
|
-
def puts(messages)
|
127
|
-
@child.puts(messages)
|
128
|
-
end
|
129
|
-
|
130
|
-
def embed(src, mime_type, label)
|
131
|
-
@child.embed(src, mime_type, label)
|
132
|
-
end
|
133
|
-
|
134
|
-
private
|
135
|
-
|
136
|
-
def timer
|
137
|
-
@timer ||= Cucumber::Core::Test::Timer.new
|
138
|
-
end
|
139
|
-
end
|
140
|
-
|
141
|
-
module TestStepSource
|
142
|
-
def self.for(test_step, result)
|
143
|
-
collector = Collector.new
|
144
|
-
test_step.describe_source_to collector, result
|
145
|
-
collector.result.freeze
|
146
|
-
end
|
147
|
-
|
148
|
-
class Collector
|
149
|
-
attr_reader :result
|
150
|
-
|
151
|
-
def initialize
|
152
|
-
@result = StepSource.new
|
153
|
-
end
|
154
|
-
|
155
|
-
def method_missing(name, node, step_result, *args)
|
156
|
-
result.send "#{name}=", node
|
157
|
-
result.send "#{name}_result=", LegacyResultBuilder.new(step_result)
|
158
|
-
end
|
159
|
-
end
|
160
|
-
|
161
|
-
require 'ostruct'
|
162
|
-
class StepSource < OpenStruct
|
163
|
-
def build_step_invocation(indent, runtime, messages, embeddings)
|
164
|
-
step_result.step_invocation(
|
165
|
-
step_match(runtime),
|
166
|
-
step,
|
167
|
-
indent,
|
168
|
-
background,
|
169
|
-
runtime.configuration,
|
170
|
-
messages,
|
171
|
-
embeddings
|
172
|
-
)
|
173
|
-
end
|
174
|
-
|
175
|
-
private
|
176
|
-
|
177
|
-
def step_match(runtime)
|
178
|
-
runtime.step_match(step.name)
|
179
|
-
rescue Cucumber::Undefined
|
180
|
-
NoStepMatch.new(step, step.name)
|
181
|
-
end
|
182
|
-
end
|
183
|
-
|
184
|
-
end
|
185
|
-
|
186
|
-
Embedding = Struct.new(:src, :mime_type, :label) do
|
187
|
-
|
188
|
-
def send_to_formatter(formatter)
|
189
|
-
formatter.embed(src, mime_type, label)
|
190
|
-
end
|
191
|
-
end
|
192
|
-
|
193
|
-
FeaturePrinter = Struct.new(:formatter, :runtime, :node) do
|
194
|
-
|
195
|
-
def before
|
196
|
-
formatter.before_feature(node)
|
197
|
-
Legacy::Ast::Comments.new(node.comments).accept(formatter)
|
198
|
-
Legacy::Ast::Tags.new(node.tags).accept(formatter)
|
199
|
-
formatter.feature_name node.keyword, indented(node.legacy_conflated_name_and_description)
|
200
|
-
@delayed_messages = []
|
201
|
-
@delayed_embeddings = []
|
202
|
-
self
|
203
|
-
end
|
204
|
-
|
205
|
-
attr_reader :current_test_step_source
|
206
|
-
|
207
|
-
def before_test_case(test_case)
|
208
|
-
@before_hook_results = Legacy::Ast::NodeCollection.new
|
209
|
-
end
|
210
|
-
|
211
|
-
def before_test_step(test_step)
|
212
|
-
end
|
213
|
-
|
214
|
-
def after_test_step(test_step, result)
|
215
|
-
@current_test_step_source = TestStepSource.for(test_step, result)
|
216
|
-
# TODO: stop calling self, and describe source to another object
|
217
|
-
test_step.describe_source_to(self, result)
|
218
|
-
print_step
|
219
|
-
end
|
220
|
-
|
221
|
-
def after_test_case(*args)
|
222
|
-
if current_test_step_source.step_result.nil?
|
223
|
-
switch_step_container
|
224
|
-
end
|
225
|
-
|
226
|
-
# messages and embedding should already have been handled, but just in case...
|
227
|
-
@delayed_messages.each { |message| formatter.puts(message) }
|
228
|
-
@delayed_embeddings.each { |embedding| embedding.send_to_formatter(formatter) }
|
229
|
-
@delayed_messages = []
|
230
|
-
@delayed_embeddings = []
|
231
|
-
|
232
|
-
@child.after_test_case
|
233
|
-
@previous_test_case_background = @current_test_case_background
|
234
|
-
@previous_test_case_scenario_outline = current_test_step_source.scenario_outline
|
235
|
-
end
|
236
|
-
|
237
|
-
def before_hook(location, result)
|
238
|
-
@before_hook_results << Legacy::Ast::HookResult.new(LegacyResultBuilder.new(result), @delayed_messages, @delayed_embeddings)
|
239
|
-
@delayed_messages = []
|
240
|
-
@delayed_embeddings = []
|
241
|
-
end
|
242
|
-
|
243
|
-
def after_hook(location, result)
|
244
|
-
# if the scenario has no steps, we can hit this before we've created the scenario printer
|
245
|
-
# ideally we should call switch_step_container in before_step_step
|
246
|
-
switch_step_container if !@child
|
247
|
-
@child.after_hook Legacy::Ast::HookResult.new(LegacyResultBuilder.new(result), @delayed_messages, @delayed_embeddings)
|
248
|
-
@delayed_messages = []
|
249
|
-
@delayed_embeddings = []
|
250
|
-
end
|
251
|
-
|
252
|
-
def after_step_hook(hook, result)
|
253
|
-
line = StepBacktraceLine.new(current_test_step_source.step)
|
254
|
-
@child.after_step_hook Legacy::Ast::HookResult.new(LegacyResultBuilder.new(result).
|
255
|
-
append_to_exception_backtrace(line), @delayed_messages, @delayed_embeddings)
|
256
|
-
@delayed_messages = []
|
257
|
-
@delayed_embeddings = []
|
258
|
-
|
259
|
-
end
|
260
|
-
|
261
|
-
def background(node, *)
|
262
|
-
@current_test_case_background = node
|
263
|
-
end
|
264
|
-
|
265
|
-
def puts(messages)
|
266
|
-
@delayed_messages.push *messages
|
267
|
-
end
|
268
|
-
|
269
|
-
def embed(src, mime_type, label)
|
270
|
-
@delayed_embeddings.push Embedding.new(src, mime_type, label)
|
271
|
-
end
|
272
|
-
|
273
|
-
def step(*);end
|
274
|
-
def scenario(*);end
|
275
|
-
def scenario_outline(*);end
|
276
|
-
def examples_table(*);end
|
277
|
-
def examples_table_row(*);end
|
278
|
-
def feature(*);end
|
279
|
-
|
280
|
-
def after
|
281
|
-
@child.after
|
282
|
-
formatter.after_feature(node)
|
283
|
-
self
|
284
|
-
end
|
285
|
-
|
286
|
-
private
|
287
|
-
|
288
|
-
attr_reader :before_hook_results
|
289
|
-
private :before_hook_results
|
290
|
-
|
291
|
-
def switch_step_container
|
292
|
-
switch_to_child select_step_container(current_test_step_source), current_test_step_source
|
293
|
-
end
|
294
|
-
|
295
|
-
def select_step_container(source)
|
296
|
-
if source.background
|
297
|
-
if same_background_as_previous_test_case?(source)
|
298
|
-
HiddenBackgroundPrinter.new(formatter, source.background)
|
299
|
-
else
|
300
|
-
BackgroundPrinter.new(formatter, source.background, before_hook_results)
|
301
|
-
end
|
302
|
-
elsif source.scenario
|
303
|
-
ScenarioPrinter.new(formatter, source.scenario, before_hook_results)
|
304
|
-
elsif source.scenario_outline
|
305
|
-
if same_scenario_outline_as_previous_test_case?(source) and @previous_outline_child
|
306
|
-
@previous_outline_child
|
307
|
-
else
|
308
|
-
ScenarioOutlinePrinter.new(formatter, runtime.configuration, source.scenario_outline)
|
309
|
-
end
|
310
|
-
else
|
311
|
-
raise 'unknown step container'
|
312
|
-
end
|
313
|
-
end
|
314
|
-
|
315
|
-
def same_background_as_previous_test_case?(source)
|
316
|
-
source.background == @previous_test_case_background
|
317
|
-
end
|
318
|
-
|
319
|
-
def same_scenario_outline_as_previous_test_case?(source)
|
320
|
-
source.scenario_outline == @previous_test_case_scenario_outline
|
321
|
-
end
|
322
|
-
|
323
|
-
def print_step
|
324
|
-
return unless current_test_step_source.step_result
|
325
|
-
switch_step_container
|
326
|
-
|
327
|
-
if current_test_step_source.scenario_outline
|
328
|
-
@child.examples_table(current_test_step_source.examples_table)
|
329
|
-
@child.examples_table_row(current_test_step_source.examples_table_row, before_hook_results)
|
330
|
-
end
|
331
|
-
|
332
|
-
if @failed_hidden_background_step
|
333
|
-
indent = Indent.new(@child.node)
|
334
|
-
step_invocation = @failed_hidden_background_step.build_step_invocation(indent, runtime, messages = [], embeddings = [])
|
335
|
-
@child.step_invocation(step_invocation, @failed_hidden_background_step)
|
336
|
-
@failed_hidden_background_step = nil
|
337
|
-
end
|
338
|
-
|
339
|
-
unless @last_step == current_test_step_source.step
|
340
|
-
indent ||= Indent.new(@child.node)
|
341
|
-
step_invocation = current_test_step_source.build_step_invocation(indent, runtime, @delayed_messages, @delayed_embeddings)
|
342
|
-
runtime.step_visited step_invocation
|
343
|
-
@child.step_invocation(step_invocation, current_test_step_source)
|
344
|
-
@last_step = current_test_step_source.step
|
345
|
-
end
|
346
|
-
@delayed_messages = []
|
347
|
-
@delayed_embeddings = []
|
348
|
-
end
|
349
|
-
|
350
|
-
def switch_to_child(child, source)
|
351
|
-
return if @child == child
|
352
|
-
if @child
|
353
|
-
if from_first_background(@child)
|
354
|
-
@first_background_failed = @child.failed?
|
355
|
-
elsif from_hidden_background(@child)
|
356
|
-
if not @first_background_failed
|
357
|
-
@failed_hidden_background_step = @child.get_failed_step_source
|
358
|
-
end
|
359
|
-
if @previous_outline_child
|
360
|
-
@previous_outline_child.after unless same_scenario_outline_as_previous_test_case?(source)
|
361
|
-
end
|
362
|
-
end
|
363
|
-
unless from_scenario_outline_to_hidden_backgroud(@child, child)
|
364
|
-
@child.after
|
365
|
-
@previous_outline_child = nil
|
366
|
-
else
|
367
|
-
@previous_outline_child = @child
|
368
|
-
end
|
369
|
-
end
|
370
|
-
child.before unless to_scenario_outline(child) and same_scenario_outline_as_previous_test_case?(source)
|
371
|
-
@child = child
|
372
|
-
end
|
373
|
-
|
374
|
-
def from_scenario_outline_to_hidden_backgroud(from, to)
|
375
|
-
from.class.name == "Cucumber::Reports::ScenarioOutlinePrinter" and
|
376
|
-
to.class.name == "Cucumber::Reports::HiddenBackgroundPrinter"
|
377
|
-
end
|
378
|
-
|
379
|
-
def from_first_background(from)
|
380
|
-
from.class.name == "Cucumber::Reports::BackgroundPrinter"
|
381
|
-
end
|
382
|
-
|
383
|
-
def from_hidden_background(from)
|
384
|
-
from.class.name == "Cucumber::Reports::HiddenBackgroundPrinter"
|
385
|
-
end
|
386
|
-
|
387
|
-
def to_scenario_outline(to)
|
388
|
-
to.class.name == "Cucumber::Reports::ScenarioOutlinePrinter"
|
389
|
-
end
|
390
|
-
|
391
|
-
def indented(nasty_old_conflation_of_name_and_description)
|
392
|
-
indent = ""
|
393
|
-
nasty_old_conflation_of_name_and_description.split("\n").map do |l|
|
394
|
-
s = "#{indent}#{l}"
|
395
|
-
indent = " "
|
396
|
-
s
|
397
|
-
end.join("\n")
|
398
|
-
end
|
399
|
-
|
400
|
-
end
|
401
|
-
|
402
|
-
module PrintsAfterHooks
|
403
|
-
def after_hook_results
|
404
|
-
@after_hook_results ||= Legacy::Ast::NodeCollection.new
|
405
|
-
end
|
406
|
-
|
407
|
-
def after_hook(result)
|
408
|
-
after_hook_results << result
|
409
|
-
end
|
410
|
-
end
|
411
|
-
|
412
|
-
# Basic printer used by default
|
413
|
-
class AfterHookPrinter
|
414
|
-
include Cucumber.initializer(:formatter)
|
415
|
-
|
416
|
-
include PrintsAfterHooks
|
417
|
-
|
418
|
-
def after
|
419
|
-
after_hook_results.accept(formatter)
|
420
|
-
end
|
421
|
-
end
|
422
|
-
|
423
|
-
BackgroundPrinter = Struct.new(:formatter, :node, :before_hook_results) do
|
424
|
-
|
425
|
-
def before
|
426
|
-
formatter.before_background node
|
427
|
-
formatter.background_name node.keyword, node.legacy_conflated_name_and_description, node.location.to_s, indent.of(node)
|
428
|
-
before_hook_results.accept(formatter)
|
429
|
-
self
|
430
|
-
end
|
431
|
-
|
432
|
-
def after_step_hook(result)
|
433
|
-
result.accept formatter
|
434
|
-
end
|
435
|
-
|
436
|
-
def step_invocation(step_invocation, source)
|
437
|
-
@child ||= StepsPrinter.new(formatter).before
|
438
|
-
@child.step_invocation step_invocation
|
439
|
-
if source.step_result.status == :failed
|
440
|
-
@failed = true
|
441
|
-
end
|
442
|
-
end
|
443
|
-
|
444
|
-
def after
|
445
|
-
@child.after if @child
|
446
|
-
formatter.after_background(node)
|
447
|
-
self
|
448
|
-
end
|
449
|
-
|
450
|
-
def failed?
|
451
|
-
@failed
|
452
|
-
end
|
453
|
-
|
454
|
-
private
|
455
|
-
|
456
|
-
def indent
|
457
|
-
@indent ||= Indent.new(node)
|
458
|
-
end
|
459
|
-
end
|
460
|
-
|
461
|
-
# Printer to handle background steps for anything but the first scenario in a
|
462
|
-
# feature. These steps should not be printed.
|
463
|
-
class HiddenBackgroundPrinter < Struct.new(:formatter, :node)
|
464
|
-
def get_failed_step_source
|
465
|
-
return @source_of_failed_step
|
466
|
-
end
|
467
|
-
|
468
|
-
def step_invocation(step_invocation, source)
|
469
|
-
if source.step_result.status == :failed
|
470
|
-
@source_of_failed_step = source
|
471
|
-
end
|
472
|
-
end
|
473
|
-
|
474
|
-
def before;self;end
|
475
|
-
def after;self;end
|
476
|
-
def before_hook(*);end
|
477
|
-
def after_hook(*);end
|
478
|
-
def after_step_hook(*);end
|
479
|
-
def examples_table(*);end
|
480
|
-
def after_test_case(*);end
|
481
|
-
end
|
482
|
-
|
483
|
-
ScenarioPrinter = Struct.new(:formatter, :node, :before_hook_results) do
|
484
|
-
include PrintsAfterHooks
|
485
|
-
|
486
|
-
def before
|
487
|
-
formatter.before_feature_element(node)
|
488
|
-
Legacy::Ast::Tags.new(node.tags).accept(formatter)
|
489
|
-
formatter.scenario_name node.keyword, node.legacy_conflated_name_and_description, node.location.to_s, indent.of(node)
|
490
|
-
before_hook_results.accept(formatter)
|
491
|
-
self
|
492
|
-
end
|
493
|
-
|
494
|
-
def step_invocation(step_invocation, source)
|
495
|
-
@child ||= StepsPrinter.new(formatter).before
|
496
|
-
@child.step_invocation step_invocation
|
497
|
-
@last_step_result = source.step_result
|
498
|
-
end
|
499
|
-
|
500
|
-
def after_step_hook(result)
|
501
|
-
result.accept formatter
|
502
|
-
end
|
503
|
-
|
504
|
-
def after_test_case(*args)
|
505
|
-
after
|
506
|
-
end
|
507
|
-
|
508
|
-
def after
|
509
|
-
return if @done
|
510
|
-
@child.after if @child
|
511
|
-
# TODO - the last step result might not accurately reflect the
|
512
|
-
# overall scenario result.
|
513
|
-
scenario = last_step_result.scenario(node.name, node.location)
|
514
|
-
after_hook_results.accept(formatter)
|
515
|
-
formatter.after_feature_element(scenario)
|
516
|
-
@done = true
|
517
|
-
self
|
518
|
-
end
|
519
|
-
|
520
|
-
private
|
521
|
-
|
522
|
-
def last_step_result
|
523
|
-
@last_step_result || LegacyResultBuilder.new(Core::Test::Result::Unknown.new)
|
524
|
-
end
|
525
|
-
|
526
|
-
def indent
|
527
|
-
@indent ||= Indent.new(node)
|
528
|
-
end
|
529
|
-
end
|
530
|
-
|
531
|
-
StepsPrinter = Struct.new(:formatter) do
|
532
|
-
def before
|
533
|
-
formatter.before_steps(nil)
|
534
|
-
self
|
535
|
-
end
|
536
|
-
|
537
|
-
def step_invocation(step_invocation)
|
538
|
-
steps << step_invocation
|
539
|
-
step_invocation.accept(formatter)
|
540
|
-
self
|
541
|
-
end
|
542
|
-
|
543
|
-
def after
|
544
|
-
formatter.after_steps(steps)
|
545
|
-
self
|
546
|
-
end
|
547
|
-
|
548
|
-
private
|
549
|
-
|
550
|
-
def steps
|
551
|
-
@steps ||= Legacy::Ast::StepInvocations.new
|
552
|
-
end
|
553
|
-
|
554
|
-
end
|
555
|
-
|
556
|
-
ScenarioOutlinePrinter = Struct.new(:formatter, :configuration, :node) do
|
557
|
-
extend Forwardable
|
558
|
-
def_delegators :@child, :after_hook, :after_step_hook
|
559
|
-
|
560
|
-
def before
|
561
|
-
formatter.before_feature_element(node)
|
562
|
-
Legacy::Ast::Tags.new(node.tags).accept(formatter)
|
563
|
-
formatter.scenario_name node.keyword, node.legacy_conflated_name_and_description, node.location.to_s, indent.of(node)
|
564
|
-
OutlineStepsPrinter.new(formatter, configuration, indent).print(node)
|
565
|
-
self
|
566
|
-
end
|
567
|
-
|
568
|
-
def step_invocation(step_invocation, source)
|
569
|
-
node, result = source.step, source.step_result
|
570
|
-
@last_step_result = result
|
571
|
-
@child.step_invocation(step_invocation, source)
|
572
|
-
end
|
573
|
-
|
574
|
-
def examples_table(examples_table)
|
575
|
-
@child ||= ExamplesArrayPrinter.new(formatter, configuration).before
|
576
|
-
@child.examples_table(examples_table)
|
577
|
-
end
|
578
|
-
|
579
|
-
def examples_table_row(node, before_hook_results)
|
580
|
-
@child.examples_table_row(node, before_hook_results)
|
581
|
-
end
|
582
|
-
|
583
|
-
def after_test_case
|
584
|
-
@child.after_test_case
|
585
|
-
end
|
586
|
-
|
587
|
-
def after
|
588
|
-
@child.after if @child
|
589
|
-
# TODO - the last step result might not accurately reflect the
|
590
|
-
# overall scenario result.
|
591
|
-
scenario_outline = last_step_result.scenario_outline(node.name, node.location)
|
592
|
-
formatter.after_feature_element(scenario_outline)
|
593
|
-
self
|
594
|
-
end
|
595
|
-
|
596
|
-
private
|
597
|
-
|
598
|
-
def last_step_result
|
599
|
-
@last_step_result || Core::Test::Result::Unknown.new
|
600
|
-
end
|
601
|
-
|
602
|
-
def indent
|
603
|
-
@indent ||= Indent.new(node)
|
604
|
-
end
|
605
|
-
end
|
606
|
-
|
607
|
-
OutlineStepsPrinter = Struct.new(:formatter, :configuration, :indent, :outline) do
|
608
|
-
def print(node)
|
609
|
-
node.describe_to self
|
610
|
-
steps_printer.after
|
611
|
-
end
|
612
|
-
|
613
|
-
def scenario_outline(node, &descend)
|
614
|
-
descend.call(self)
|
615
|
-
end
|
616
|
-
|
617
|
-
def outline_step(step)
|
618
|
-
step_match = NoStepMatch.new(step, step.name)
|
619
|
-
step_invocation = LegacyResultBuilder.new(Core::Test::Result::Skipped.new).
|
620
|
-
step_invocation(step_match, step, indent, background = nil, configuration, messages = [], embeddings = [])
|
621
|
-
steps_printer.step_invocation step_invocation
|
622
|
-
end
|
623
|
-
|
624
|
-
def examples_table(*);end
|
625
|
-
|
626
|
-
private
|
627
|
-
|
628
|
-
def steps_printer
|
629
|
-
@steps_printer ||= StepsPrinter.new(formatter).before
|
630
|
-
end
|
631
|
-
end
|
632
|
-
|
633
|
-
ExamplesArrayPrinter = Struct.new(:formatter, :configuration) do
|
634
|
-
extend Forwardable
|
635
|
-
def_delegators :@child, :step_invocation, :after_hook, :after_step_hook, :after_test_case, :examples_table_row
|
636
|
-
|
637
|
-
def before
|
638
|
-
formatter.before_examples_array(:examples_array)
|
639
|
-
self
|
640
|
-
end
|
641
|
-
|
642
|
-
def examples_table(examples_table)
|
643
|
-
return if examples_table == @current
|
644
|
-
@child.after if @child
|
645
|
-
@child = ExamplesTablePrinter.new(formatter, configuration, examples_table).before
|
646
|
-
@current = examples_table
|
647
|
-
end
|
648
|
-
|
649
|
-
def after
|
650
|
-
@child.after if @child
|
651
|
-
formatter.after_examples_array
|
652
|
-
self
|
653
|
-
end
|
654
|
-
end
|
655
|
-
|
656
|
-
ExamplesTablePrinter = Struct.new(:formatter, :configuration, :node) do
|
657
|
-
extend Forwardable
|
658
|
-
def_delegators :@child, :step_invocation, :after_hook, :after_step_hook, :after_test_case
|
659
|
-
|
660
|
-
def before
|
661
|
-
formatter.before_examples(node)
|
662
|
-
formatter.examples_name(node.keyword, node.legacy_conflated_name_and_description)
|
663
|
-
formatter.before_outline_table(legacy_table)
|
664
|
-
if !configuration.expand?
|
665
|
-
HeaderTableRowPrinter.new(formatter, ExampleTableRow.new(node.header), Legacy::Ast::Node.new).before.after
|
666
|
-
end
|
667
|
-
self
|
668
|
-
end
|
669
|
-
|
670
|
-
def examples_table_row(examples_table_row, before_hook_results)
|
671
|
-
return if examples_table_row == @current
|
672
|
-
@child.after if @child
|
673
|
-
row = ExampleTableRow.new(examples_table_row)
|
674
|
-
if !configuration.expand?
|
675
|
-
@child = TableRowPrinter.new(formatter, row, before_hook_results).before
|
676
|
-
else
|
677
|
-
@child = ExpandTableRowPrinter.new(formatter, row, before_hook_results).before
|
678
|
-
end
|
679
|
-
@current = examples_table_row
|
680
|
-
end
|
681
|
-
|
682
|
-
def after_test_case(*args)
|
683
|
-
@child.after_test_case
|
684
|
-
end
|
685
|
-
|
686
|
-
def after
|
687
|
-
@child.after if @child
|
688
|
-
formatter.after_outline_table(node)
|
689
|
-
formatter.after_examples(node)
|
690
|
-
self
|
691
|
-
end
|
692
|
-
|
693
|
-
private
|
694
|
-
|
695
|
-
def legacy_table
|
696
|
-
LegacyTable.new(node)
|
697
|
-
end
|
698
|
-
|
699
|
-
class ExampleTableRow < SimpleDelegator
|
700
|
-
def dom_id
|
701
|
-
file_colon_line.gsub(/[\/\.:]/, '_')
|
702
|
-
end
|
703
|
-
end
|
704
|
-
|
705
|
-
LegacyTable = Struct.new(:node) do
|
706
|
-
def col_width(index)
|
707
|
-
max_width = FindMaxWidth.new(index)
|
708
|
-
node.describe_to max_width
|
709
|
-
max_width.result
|
710
|
-
end
|
711
|
-
|
712
|
-
require 'gherkin/formatter/escaping'
|
713
|
-
FindMaxWidth = Struct.new(:index) do
|
714
|
-
include ::Gherkin::Formatter::Escaping
|
715
|
-
|
716
|
-
def examples_table(table, &descend)
|
717
|
-
@result = char_length_of(table.header.values[index])
|
718
|
-
descend.call(self)
|
719
|
-
end
|
720
|
-
|
721
|
-
def examples_table_row(row, &descend)
|
722
|
-
width = char_length_of(row.values[index])
|
723
|
-
@result = width if width > result
|
724
|
-
end
|
725
|
-
|
726
|
-
def result
|
727
|
-
@result ||= 0
|
728
|
-
end
|
729
|
-
|
730
|
-
private
|
731
|
-
def char_length_of(cell)
|
732
|
-
escape_cell(cell).unpack('U*').length
|
733
|
-
end
|
734
|
-
end
|
735
|
-
end
|
736
|
-
end
|
737
|
-
|
738
|
-
class TableRowPrinterBase < Struct.new(:formatter, :node, :before_hook_results)
|
739
|
-
include PrintsAfterHooks
|
740
|
-
|
741
|
-
def after_step_hook(result)
|
742
|
-
@after_step_hook_result ||= []
|
743
|
-
@after_step_hook_result.push result
|
744
|
-
end
|
745
|
-
|
746
|
-
def after_test_case(*args)
|
747
|
-
after
|
748
|
-
end
|
749
|
-
|
750
|
-
private
|
751
|
-
|
752
|
-
def indent
|
753
|
-
:not_needed
|
754
|
-
end
|
755
|
-
|
756
|
-
def legacy_table_row
|
757
|
-
LegacyExampleTableRow.new(exception, @status, node.values, node.location)
|
758
|
-
end
|
759
|
-
|
760
|
-
def exception
|
761
|
-
return nil unless @failed_step
|
762
|
-
@failed_step.exception
|
763
|
-
end
|
764
|
-
end
|
765
|
-
|
766
|
-
class HeaderTableRowPrinter < TableRowPrinterBase
|
767
|
-
def before
|
768
|
-
formatter.before_table_row(node)
|
769
|
-
self
|
770
|
-
end
|
771
|
-
|
772
|
-
def after
|
773
|
-
node.values.each do |value|
|
774
|
-
formatter.before_table_cell(value)
|
775
|
-
formatter.table_cell_value(value, :skipped_param)
|
776
|
-
formatter.after_table_cell(value)
|
777
|
-
end
|
778
|
-
formatter.after_table_row(legacy_table_row)
|
779
|
-
self
|
780
|
-
end
|
781
|
-
end
|
782
|
-
|
783
|
-
|
784
|
-
class TableRowPrinter < TableRowPrinterBase
|
785
|
-
def before
|
786
|
-
before_hook_results.accept(formatter)
|
787
|
-
formatter.before_table_row(node)
|
788
|
-
self
|
789
|
-
end
|
790
|
-
|
791
|
-
def step_invocation(step_invocation, source)
|
792
|
-
result = source.step_result
|
793
|
-
step_invocation.messages.each { |message| formatter.puts(message) }
|
794
|
-
step_invocation.embeddings.each { |embedding| embedding.send_to_formatter(formatter) }
|
795
|
-
@failed_step = step_invocation if result.status == :failed
|
796
|
-
@status = step_invocation.status unless already_failed?
|
797
|
-
end
|
798
|
-
|
799
|
-
def after
|
800
|
-
return if @done
|
801
|
-
@child.after if @child
|
802
|
-
node.values.each do |value|
|
803
|
-
formatter.before_table_cell(value)
|
804
|
-
formatter.table_cell_value(value, @status || :skipped)
|
805
|
-
formatter.after_table_cell(value)
|
806
|
-
end
|
807
|
-
formatter.after_table_row(legacy_table_row)
|
808
|
-
@after_step_hook_result.each { |result| result.accept formatter } if @after_step_hook_result
|
809
|
-
after_hook_results.accept(formatter)
|
810
|
-
@done = true
|
811
|
-
self
|
812
|
-
end
|
813
|
-
|
814
|
-
private
|
815
|
-
|
816
|
-
def already_failed?
|
817
|
-
@status == :failed || @status == :undefined || @status == :pending
|
818
|
-
end
|
819
|
-
end
|
820
|
-
|
821
|
-
class ExpandTableRowPrinter < TableRowPrinterBase
|
822
|
-
def before
|
823
|
-
before_hook_results.accept(formatter)
|
824
|
-
self
|
825
|
-
end
|
826
|
-
|
827
|
-
def step_invocation(step_invocation, source)
|
828
|
-
result = source.step_result
|
829
|
-
@table_row ||= legacy_table_row
|
830
|
-
step_invocation.indent.record_width_of(@table_row)
|
831
|
-
if !@scenario_name_printed
|
832
|
-
print_scenario_name(step_invocation, @table_row)
|
833
|
-
@scenario_name_printed = true
|
834
|
-
end
|
835
|
-
step_invocation.accept(formatter)
|
836
|
-
@failed_step = step_invocation if result.status == :failed
|
837
|
-
@status = step_invocation.status unless @status == :failed
|
838
|
-
end
|
839
|
-
|
840
|
-
def after
|
841
|
-
return if @done
|
842
|
-
@child.after if @child
|
843
|
-
@after_step_hook_result.each { |result| result.accept formatter } if @after_step_hook_result
|
844
|
-
after_hook_results.accept(formatter)
|
845
|
-
@done = true
|
846
|
-
self
|
847
|
-
end
|
848
|
-
|
849
|
-
private
|
850
|
-
|
851
|
-
def print_scenario_name(step_invocation, table_row)
|
852
|
-
formatter.scenario_name table_row.keyword, table_row.name, node.location.to_s, step_invocation.indent.of(table_row)
|
853
|
-
end
|
854
|
-
end
|
855
|
-
|
856
|
-
LegacyExampleTableRow = Struct.new(:exception, :status, :cells, :location) do
|
857
|
-
def name
|
858
|
-
'| ' + cells.join(' | ') + ' |'
|
859
|
-
end
|
860
|
-
|
861
|
-
def failed?
|
862
|
-
status == :failed
|
863
|
-
end
|
864
|
-
|
865
|
-
def line
|
866
|
-
location.line
|
867
|
-
end
|
868
|
-
|
869
|
-
def keyword
|
870
|
-
# This method is only called when used for the scenario name line with
|
871
|
-
# the expand option, and on that line the keyword is "Scenario"
|
872
|
-
"Scenario"
|
873
|
-
end
|
874
|
-
end
|
875
|
-
|
876
|
-
class Indent
|
877
|
-
def initialize(node)
|
878
|
-
@widths = []
|
879
|
-
node.describe_to(self)
|
880
|
-
end
|
881
|
-
|
882
|
-
[:background, :scenario, :scenario_outline].each do |node_name|
|
883
|
-
define_method(node_name) do |node, &descend|
|
884
|
-
record_width_of node
|
885
|
-
descend.call(self)
|
886
|
-
end
|
887
|
-
end
|
888
|
-
|
889
|
-
[:step, :outline_step].each do |node_name|
|
890
|
-
define_method(node_name) do |node|
|
891
|
-
record_width_of node
|
892
|
-
end
|
893
|
-
end
|
894
|
-
|
895
|
-
def examples_table(*); end
|
896
|
-
def examples_table_row(*); end
|
897
|
-
|
898
|
-
def of(node)
|
899
|
-
# The length of the instantiated steps in --expand mode are currently
|
900
|
-
# not included in the calculation of max => make sure to return >= 1
|
901
|
-
[1, max - node.name.length - node.keyword.length].max
|
902
|
-
end
|
903
|
-
|
904
|
-
def record_width_of(node)
|
905
|
-
@widths << node.keyword.length + node.name.length + 1
|
906
|
-
end
|
907
|
-
|
908
|
-
private
|
909
|
-
|
910
|
-
def max
|
911
|
-
@widths.max
|
912
|
-
end
|
913
|
-
end
|
914
|
-
|
915
|
-
class LegacyResultBuilder
|
916
|
-
attr_reader :status
|
917
|
-
def initialize(result)
|
918
|
-
@result = result
|
919
|
-
@result.describe_to(self)
|
920
|
-
end
|
921
|
-
|
922
|
-
def passed
|
923
|
-
@status = :passed
|
924
|
-
end
|
925
|
-
|
926
|
-
def failed
|
927
|
-
@status = :failed
|
928
|
-
end
|
929
|
-
|
930
|
-
def undefined
|
931
|
-
@status = :undefined
|
932
|
-
end
|
933
|
-
|
934
|
-
def skipped
|
935
|
-
@status = :skipped
|
936
|
-
end
|
937
|
-
|
938
|
-
def pending(exception, *)
|
939
|
-
@exception = exception
|
940
|
-
@status = :pending
|
941
|
-
end
|
942
|
-
|
943
|
-
def exception(exception, *)
|
944
|
-
@exception = exception
|
945
|
-
end
|
946
|
-
|
947
|
-
def append_to_exception_backtrace(line)
|
948
|
-
@exception.set_backtrace(@exception.backtrace + [line.to_s]) if @exception
|
949
|
-
return self
|
950
|
-
end
|
951
|
-
|
952
|
-
def duration(*); end
|
953
|
-
|
954
|
-
def step_invocation(step_match, step, indent, background, configuration, messages, embeddings)
|
955
|
-
Legacy::Ast::StepInvocation.new(step_match, @status, step_exception(step, configuration), indent, background, step, messages, embeddings)
|
956
|
-
end
|
957
|
-
|
958
|
-
def scenario(name, location)
|
959
|
-
Legacy::Ast::Scenario.new(@status, name, location)
|
960
|
-
end
|
961
|
-
|
962
|
-
def scenario_outline(name, location)
|
963
|
-
Legacy::Ast::ScenarioOutline.new(@status, name, location)
|
964
|
-
end
|
965
|
-
|
966
|
-
def describe_exception_to(formatter)
|
967
|
-
formatter.exception(filtered_exception, @status) if @exception
|
968
|
-
end
|
969
|
-
|
970
|
-
private
|
971
|
-
|
972
|
-
def step_exception(step, configuration)
|
973
|
-
return filtered_step_exception(step) if @exception
|
974
|
-
return nil unless @status == :undefined && configuration.strict?
|
975
|
-
@exception = Cucumber::Undefined.from(@result, step.name)
|
976
|
-
filtered_step_exception(step)
|
977
|
-
end
|
978
|
-
|
979
|
-
def filtered_exception
|
980
|
-
BacktraceFilter.new(@exception.dup).exception
|
981
|
-
end
|
982
|
-
|
983
|
-
def filtered_step_exception(step)
|
984
|
-
exception = filtered_exception
|
985
|
-
exception.backtrace << StepBacktraceLine.new(step).to_s
|
986
|
-
return exception
|
987
|
-
end
|
988
|
-
end
|
989
|
-
|
990
|
-
end
|
991
|
-
|
992
|
-
class StepBacktraceLine < Struct.new(:step)
|
993
|
-
def to_s
|
994
|
-
step.backtrace_line
|
995
|
-
end
|
996
|
-
end
|
997
|
-
|
998
|
-
class BacktraceFilter
|
999
|
-
BACKTRACE_FILTER_PATTERNS = \
|
1000
|
-
[/vendor\/rails|lib\/cucumber|bin\/cucumber:|lib\/rspec|gems\/|minitest|test\/unit|.gem\/ruby|lib\/ruby/]
|
1001
|
-
if(::Cucumber::JRUBY)
|
1002
|
-
BACKTRACE_FILTER_PATTERNS << /org\/jruby/
|
1003
|
-
end
|
1004
|
-
PWD_PATTERN = /#{::Regexp.escape(::Dir.pwd)}\//m
|
1005
|
-
|
1006
|
-
def initialize(exception)
|
1007
|
-
@exception = exception
|
1008
|
-
end
|
1009
|
-
|
1010
|
-
def exception
|
1011
|
-
return @exception if ::Cucumber.use_full_backtrace
|
1012
|
-
@exception.backtrace.each{|line| line.gsub!(PWD_PATTERN, "./")}
|
1013
|
-
|
1014
|
-
filtered = (@exception.backtrace || []).reject do |line|
|
1015
|
-
BACKTRACE_FILTER_PATTERNS.detect { |p| line =~ p }
|
1016
|
-
end
|
1017
|
-
|
1018
|
-
if ::ENV['CUCUMBER_TRUNCATE_OUTPUT']
|
1019
|
-
# Strip off file locations
|
1020
|
-
filtered = filtered.map do |line|
|
1021
|
-
line =~ /(.*):in `/ ? $1 : line
|
1022
|
-
end
|
1023
|
-
end
|
1024
|
-
|
1025
|
-
@exception.set_backtrace(filtered)
|
1026
|
-
@exception
|
1027
|
-
end
|
1028
|
-
end
|
1029
|
-
|
1030
|
-
|
1031
|
-
# Adapters to pass to the legacy API formatters that provide the interface
|
1032
|
-
# of the old AST classes
|
1033
|
-
module Legacy
|
1034
|
-
module Ast
|
1035
|
-
|
1036
|
-
# Acts as a null object, or a base class
|
1037
|
-
class Node
|
1038
|
-
def initialize(node = nil)
|
1039
|
-
@node = node
|
1040
|
-
end
|
1041
|
-
|
1042
|
-
def accept(formatter)
|
1043
|
-
end
|
1044
|
-
|
1045
|
-
attr_reader :node
|
1046
|
-
private :node
|
1047
|
-
end
|
1048
|
-
|
1049
|
-
class NodeCollection
|
1050
|
-
def initialize
|
1051
|
-
@children = []
|
1052
|
-
end
|
1053
|
-
|
1054
|
-
def accept(formatter)
|
1055
|
-
@children.each { |child| child.accept(formatter) }
|
1056
|
-
end
|
1057
|
-
|
1058
|
-
def <<(child)
|
1059
|
-
@children << child
|
1060
|
-
end
|
1061
|
-
end
|
1062
|
-
|
1063
|
-
Comments = Struct.new(:comments) do
|
1064
|
-
def accept(formatter)
|
1065
|
-
return if comments.empty?
|
1066
|
-
formatter.before_comment comments
|
1067
|
-
comments.each do |comment|
|
1068
|
-
formatter.comment_line comment.to_s.strip
|
1069
|
-
end
|
1070
|
-
end
|
1071
|
-
end
|
1072
|
-
|
1073
|
-
class HookResult
|
1074
|
-
def initialize(result, messages, embeddings)
|
1075
|
-
@result, @messages, @embeddings = result, messages, embeddings
|
1076
|
-
@already_accepted = false
|
1077
|
-
end
|
1078
|
-
|
1079
|
-
def accept(formatter)
|
1080
|
-
unless @already_accepted
|
1081
|
-
@messages.each { |message| formatter.puts(message) }
|
1082
|
-
@embeddings.each { |embedding| embedding.send_to_formatter(formatter) }
|
1083
|
-
@result.describe_exception_to(formatter)
|
1084
|
-
@already_accepted = true
|
1085
|
-
end
|
1086
|
-
self
|
1087
|
-
end
|
1088
|
-
end
|
1089
|
-
|
1090
|
-
StepInvocation = Struct.new(:step_match,
|
1091
|
-
:status,
|
1092
|
-
:exception,
|
1093
|
-
:indent,
|
1094
|
-
:background,
|
1095
|
-
:step,
|
1096
|
-
:messages,
|
1097
|
-
:embeddings) do
|
1098
|
-
extend Forwardable
|
1099
|
-
|
1100
|
-
def_delegators :step, :keyword, :name, :multiline_arg, :location, :gherkin_statement
|
1101
|
-
|
1102
|
-
def accept(formatter)
|
1103
|
-
formatter.before_step(self)
|
1104
|
-
messages.each { |message| formatter.puts(message) }
|
1105
|
-
embeddings.each { |embedding| embedding.send_to_formatter(formatter) }
|
1106
|
-
formatter.before_step_result *step_result_attributes
|
1107
|
-
print_step_name(formatter)
|
1108
|
-
Legacy::Ast::MultilineArg.for(multiline_arg).accept(formatter)
|
1109
|
-
print_exception(formatter)
|
1110
|
-
formatter.after_step_result *step_result_attributes
|
1111
|
-
formatter.after_step(self)
|
1112
|
-
end
|
1113
|
-
|
1114
|
-
def step_result_attributes
|
1115
|
-
[keyword, step_match, multiline_arg, status, exception, source_indent, background, file_colon_line]
|
1116
|
-
end
|
1117
|
-
|
1118
|
-
def failed?
|
1119
|
-
status != :passed
|
1120
|
-
end
|
1121
|
-
|
1122
|
-
def passed?
|
1123
|
-
status == :passed
|
1124
|
-
end
|
1125
|
-
|
1126
|
-
def dom_id
|
1127
|
-
|
1128
|
-
end
|
1129
|
-
|
1130
|
-
def actual_keyword
|
1131
|
-
# TODO: This should return the keyword for the snippet
|
1132
|
-
# `actual_keyword` translates 'And', 'But', etc. to 'Given', 'When',
|
1133
|
-
# 'Then' as appropriate
|
1134
|
-
"Given"
|
1135
|
-
end
|
1136
|
-
|
1137
|
-
def file_colon_line
|
1138
|
-
location.to_s
|
1139
|
-
end
|
1140
|
-
|
1141
|
-
def backtrace_line
|
1142
|
-
step_match.backtrace_line
|
1143
|
-
end
|
1144
|
-
|
1145
|
-
def step_invocation
|
1146
|
-
self
|
1147
|
-
end
|
1148
|
-
|
1149
|
-
private
|
1150
|
-
|
1151
|
-
def source_indent
|
1152
|
-
indent.of(self)
|
1153
|
-
end
|
1154
|
-
|
1155
|
-
def print_step_name(formatter)
|
1156
|
-
formatter.step_name(
|
1157
|
-
keyword,
|
1158
|
-
step_match,
|
1159
|
-
status,
|
1160
|
-
source_indent,
|
1161
|
-
background,
|
1162
|
-
location.to_s)
|
1163
|
-
end
|
1164
|
-
|
1165
|
-
def print_exception(formatter)
|
1166
|
-
return unless exception
|
1167
|
-
raise exception if ENV['FAIL_FAST']
|
1168
|
-
formatter.exception(exception, status)
|
1169
|
-
end
|
1170
|
-
end
|
1171
|
-
|
1172
|
-
class StepInvocations < Array
|
1173
|
-
def failed?
|
1174
|
-
any?(&:failed?)
|
1175
|
-
end
|
1176
|
-
|
1177
|
-
def passed?
|
1178
|
-
all?(&:passed?)
|
1179
|
-
end
|
1180
|
-
|
1181
|
-
def status
|
1182
|
-
return :passed if passed?
|
1183
|
-
failed_step.status
|
1184
|
-
end
|
1185
|
-
|
1186
|
-
def exception
|
1187
|
-
failed_step.exception if failed_step
|
1188
|
-
end
|
1189
|
-
|
1190
|
-
private
|
1191
|
-
|
1192
|
-
def failed_step
|
1193
|
-
detect(&:failed?)
|
1194
|
-
end
|
1195
|
-
end
|
1196
|
-
|
1197
|
-
class DataTableRow
|
1198
|
-
def initialize(row, line)
|
1199
|
-
@values = row
|
1200
|
-
@line = line
|
1201
|
-
end
|
1202
|
-
|
1203
|
-
def dom_id
|
1204
|
-
"row_#{line}"
|
1205
|
-
end
|
1206
|
-
|
1207
|
-
def accept(formatter)
|
1208
|
-
formatter.before_table_row(self)
|
1209
|
-
values.each do |value|
|
1210
|
-
formatter.before_table_cell(value)
|
1211
|
-
formatter.table_cell_value(value, status)
|
1212
|
-
formatter.after_table_cell(value)
|
1213
|
-
end
|
1214
|
-
formatter.after_table_row(self)
|
1215
|
-
end
|
1216
|
-
|
1217
|
-
def status
|
1218
|
-
:skipped
|
1219
|
-
end
|
1220
|
-
|
1221
|
-
def exception
|
1222
|
-
nil
|
1223
|
-
end
|
1224
|
-
|
1225
|
-
attr_reader :values, :line
|
1226
|
-
private :values, :line
|
1227
|
-
end
|
1228
|
-
|
1229
|
-
class LegacyTableRow < DataTableRow
|
1230
|
-
def accept(formatter)
|
1231
|
-
formatter.before_table_row(self)
|
1232
|
-
values.each do |value|
|
1233
|
-
formatter.before_table_cell(value.value)
|
1234
|
-
formatter.table_cell_value(value.value, value.status)
|
1235
|
-
formatter.after_table_cell(value.value)
|
1236
|
-
end
|
1237
|
-
formatter.after_table_row(self)
|
1238
|
-
end
|
1239
|
-
end
|
1240
|
-
|
1241
|
-
Tags = Struct.new(:tags) do
|
1242
|
-
def accept(formatter)
|
1243
|
-
formatter.before_tags tags
|
1244
|
-
tags.each do |tag|
|
1245
|
-
formatter.tag_name tag.name
|
1246
|
-
end
|
1247
|
-
formatter.after_tags tags
|
1248
|
-
end
|
1249
|
-
end
|
1250
|
-
|
1251
|
-
Scenario = Struct.new(:status, :name, :location) do
|
1252
|
-
def backtrace_line(step_name = "#{name}", line = self.location.line)
|
1253
|
-
"#{location.on_line(line)}:in `#{step_name}'"
|
1254
|
-
end
|
1255
|
-
|
1256
|
-
def failed?
|
1257
|
-
:failed == status
|
1258
|
-
end
|
1259
|
-
|
1260
|
-
def line
|
1261
|
-
location.line
|
1262
|
-
end
|
1263
|
-
end
|
1264
|
-
|
1265
|
-
ScenarioOutline = Struct.new(:status, :name, :location) do
|
1266
|
-
def backtrace_line(step_name = "#{name}", line = self.location.line)
|
1267
|
-
"#{location.on_line(line)}:in `#{step_name}'"
|
1268
|
-
end
|
1269
|
-
|
1270
|
-
def failed?
|
1271
|
-
:failed == status
|
1272
|
-
end
|
1273
|
-
|
1274
|
-
def line
|
1275
|
-
location.line
|
1276
|
-
end
|
1277
|
-
end
|
1278
|
-
|
1279
|
-
module MultilineArg
|
1280
|
-
class << self
|
1281
|
-
def for(node)
|
1282
|
-
Builder.new(node).result
|
1283
|
-
end
|
1284
|
-
end
|
1285
|
-
|
1286
|
-
class Builder
|
1287
|
-
def initialize(node)
|
1288
|
-
node.describe_to(self)
|
1289
|
-
end
|
1290
|
-
|
1291
|
-
def doc_string(node)
|
1292
|
-
@result = DocString.new(node)
|
1293
|
-
end
|
1294
|
-
|
1295
|
-
def data_table(node)
|
1296
|
-
@result = DataTable.new(node)
|
1297
|
-
end
|
1298
|
-
|
1299
|
-
def legacy_table(node)
|
1300
|
-
@result = LegacyTable.new(node)
|
1301
|
-
end
|
1302
|
-
|
1303
|
-
def result
|
1304
|
-
@result || Node.new(nil)
|
1305
|
-
end
|
1306
|
-
end
|
1307
|
-
|
1308
|
-
class DocString < Node
|
1309
|
-
def accept(formatter)
|
1310
|
-
formatter.before_multiline_arg node
|
1311
|
-
formatter.doc_string(node)
|
1312
|
-
formatter.after_multiline_arg node
|
1313
|
-
end
|
1314
|
-
end
|
1315
|
-
|
1316
|
-
class DataTable < Cucumber::MultilineArgument::DataTable
|
1317
|
-
def node
|
1318
|
-
@ast_table
|
1319
|
-
end
|
1320
|
-
|
1321
|
-
def accept(formatter)
|
1322
|
-
formatter.before_multiline_arg self
|
1323
|
-
node.raw.each_with_index do |row, index|
|
1324
|
-
line = node.location.line + index
|
1325
|
-
Legacy::Ast::DataTableRow.new(row, line).accept(formatter)
|
1326
|
-
end
|
1327
|
-
formatter.after_multiline_arg self
|
1328
|
-
end
|
1329
|
-
end
|
1330
|
-
end
|
1331
|
-
|
1332
|
-
class LegacyTable < SimpleDelegator
|
1333
|
-
def accept(formatter)
|
1334
|
-
formatter.before_multiline_arg self
|
1335
|
-
cells_rows.each_with_index do |row, index|
|
1336
|
-
line = location.line + index
|
1337
|
-
Legacy::Ast::LegacyTableRow.new(row, line).accept(formatter)
|
1338
|
-
end
|
1339
|
-
formatter.after_multiline_arg self
|
1340
|
-
end
|
1341
|
-
end
|
1342
|
-
|
1343
|
-
Features = Struct.new(:duration)
|
1344
|
-
|
1345
|
-
end
|
1346
|
-
|
1347
|
-
end
|
1348
|
-
end
|
1349
|
-
end
|