cucumber 4.0.0.rc.1 → 4.0.0.rc.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +97 -4
  3. data/CONTRIBUTING.md +1 -18
  4. data/README.md +4 -5
  5. data/lib/autotest/cucumber_mixin.rb +2 -10
  6. data/lib/cucumber.rb +1 -1
  7. data/lib/cucumber/cli/configuration.rb +1 -1
  8. data/lib/cucumber/cli/main.rb +1 -0
  9. data/lib/cucumber/cli/options.rb +18 -13
  10. data/lib/cucumber/cli/profile_loader.rb +23 -12
  11. data/lib/cucumber/configuration.rb +11 -2
  12. data/lib/cucumber/deprecate.rb +29 -5
  13. data/lib/cucumber/errors.rb +5 -2
  14. data/lib/cucumber/events.rb +12 -7
  15. data/lib/cucumber/events/envelope.rb +9 -0
  16. data/lib/cucumber/events/hook_test_step_created.rb +13 -0
  17. data/lib/cucumber/events/test_case_created.rb +13 -0
  18. data/lib/cucumber/events/test_case_ready.rb +12 -0
  19. data/lib/cucumber/events/test_step_created.rb +13 -0
  20. data/lib/cucumber/filters.rb +1 -0
  21. data/lib/cucumber/filters/broadcast_test_case_ready_event.rb +12 -0
  22. data/lib/cucumber/formatter/ast_lookup.rb +43 -38
  23. data/lib/cucumber/formatter/backtrace_filter.rb +4 -1
  24. data/lib/cucumber/formatter/console.rb +4 -9
  25. data/lib/cucumber/formatter/console_issues.rb +1 -1
  26. data/lib/cucumber/formatter/duration.rb +1 -1
  27. data/lib/cucumber/formatter/duration_extractor.rb +2 -0
  28. data/lib/cucumber/formatter/errors.rb +6 -0
  29. data/lib/cucumber/formatter/html.rb +24 -0
  30. data/lib/cucumber/formatter/http_io.rb +146 -0
  31. data/lib/cucumber/formatter/interceptor.rb +3 -21
  32. data/lib/cucumber/formatter/io.rb +14 -8
  33. data/lib/cucumber/formatter/json.rb +46 -36
  34. data/lib/cucumber/formatter/junit.rb +13 -11
  35. data/lib/cucumber/formatter/message.rb +22 -0
  36. data/lib/cucumber/formatter/message_builder.rb +243 -0
  37. data/lib/cucumber/formatter/pretty.rb +65 -60
  38. data/lib/cucumber/formatter/query/hook_by_test_step.rb +31 -0
  39. data/lib/cucumber/formatter/query/pickle_by_test.rb +26 -0
  40. data/lib/cucumber/formatter/query/pickle_step_by_test_step.rb +26 -0
  41. data/lib/cucumber/formatter/query/step_definitions_by_test_step.rb +40 -0
  42. data/lib/cucumber/formatter/query/test_case_started_by_test_case.rb +40 -0
  43. data/lib/cucumber/formatter/summary.rb +1 -1
  44. data/lib/cucumber/formatter/usage.rb +3 -3
  45. data/lib/cucumber/gherkin/data_table_parser.rb +12 -3
  46. data/lib/cucumber/gherkin/steps_parser.rb +13 -3
  47. data/lib/cucumber/glue/hook.rb +18 -2
  48. data/lib/cucumber/glue/proto_world.rb +30 -18
  49. data/lib/cucumber/glue/registry_and_more.rb +40 -3
  50. data/lib/cucumber/glue/snippet.rb +2 -2
  51. data/lib/cucumber/glue/step_definition.rb +28 -4
  52. data/lib/cucumber/hooks.rb +8 -8
  53. data/lib/cucumber/multiline_argument.rb +1 -1
  54. data/lib/cucumber/multiline_argument/data_table.rb +17 -13
  55. data/lib/cucumber/platform.rb +1 -1
  56. data/lib/cucumber/rake/task.rb +3 -0
  57. data/lib/cucumber/runtime.rb +29 -3
  58. data/lib/cucumber/runtime/after_hooks.rb +6 -2
  59. data/lib/cucumber/runtime/before_hooks.rb +6 -2
  60. data/lib/cucumber/runtime/for_programming_languages.rb +1 -0
  61. data/lib/cucumber/runtime/step_hooks.rb +3 -2
  62. data/lib/cucumber/runtime/support_code.rb +3 -3
  63. data/lib/cucumber/runtime/user_interface.rb +2 -10
  64. data/lib/cucumber/step_definitions.rb +2 -2
  65. data/lib/cucumber/version +1 -1
  66. metadata +227 -73
@@ -19,7 +19,7 @@ module Cucumber
19
19
  #
20
20
  # If the output is STDOUT (and not a file), there are bright colours to watch too.
21
21
  #
22
- class Pretty
22
+ class Pretty # rubocop:disable Metrics/ClassLength
23
23
  include FileUtils
24
24
  include Console
25
25
  include Io
@@ -101,13 +101,11 @@ module Cucumber
101
101
  print_step_header(current_test_case) if first_step_after_printing_background_steps?(event.test_step)
102
102
  end
103
103
 
104
- def on_test_step_finished(event) # rubocop:disable Metrics/PerceivedComplexity
104
+ def on_test_step_finished(event)
105
105
  collect_snippet_data(event.test_step, @ast_lookup) if event.result.undefined?
106
106
  return if in_scenario_outline && !options[:expand]
107
107
  exception_to_be_printed = find_exception_to_be_printed(event.result)
108
- # rubocop:disable Metrics/LineLength
109
- print_step_data(event.test_step, event.result) if !event.test_step.hook? && (print_background_steps || event.test_step.location.lines.max >= current_test_case.location.lines.max || exception_to_be_printed)
110
- # rubocop:enable Metrics/LineLength
108
+ print_step_data(event.test_step, event.result) if print_step_data?(event, exception_to_be_printed)
111
109
  print_step_output
112
110
  return unless exception_to_be_printed
113
111
  print_exception(exception_to_be_printed, event.result.to_sym, 6)
@@ -133,10 +131,9 @@ module Cucumber
133
131
  print_summary
134
132
  end
135
133
 
136
- def puts(*messages)
137
- messages.each do |message|
138
- @test_step_output.push message
139
- end
134
+ def attach(src, media_type)
135
+ return unless media_type == 'text/x.cucumber.log+plain'
136
+ @test_step_output.push src
140
137
  end
141
138
 
142
139
  private
@@ -155,10 +152,10 @@ module Cucumber
155
152
  end
156
153
 
157
154
  def calculate_source_indent_for_ast_node(ast_node)
158
- indent = 4 + ast_node[:keyword].length
159
- indent += 1 + ast_node[:name].length
160
- ast_node[:steps].each do |step|
161
- step_indent = 5 + step[:keyword].length + step[:text].length
155
+ indent = 4 + ast_node.keyword.length
156
+ indent += 1 + ast_node.name.length
157
+ ast_node.steps.each do |step|
158
+ step_indent = 5 + step.keyword.length + step.text.length
162
159
  indent = step_indent if step_indent > indent
163
160
  end
164
161
  indent
@@ -190,9 +187,9 @@ module Cucumber
190
187
  end
191
188
 
192
189
  def feature_has_background?
193
- feature_children = gherkin_document[:feature][:children]
190
+ feature_children = gherkin_document.feature.children
194
191
  return false if feature_children.empty?
195
- !feature_children.first[:background].nil?
192
+ !feature_children.first.background.nil?
196
193
  end
197
194
 
198
195
  def print_step_header(test_case)
@@ -240,12 +237,12 @@ module Cucumber
240
237
  end
241
238
 
242
239
  def print_feature_data
243
- feature = gherkin_document[:feature]
244
- print_language_comment(feature[:location][:line])
245
- print_comments(feature[:location][:line], 0)
246
- print_tags(feature[:tags], 0)
240
+ feature = gherkin_document.feature
241
+ print_language_comment(feature.location.line)
242
+ print_comments(feature.location.line, 0)
243
+ print_tags(feature.tags, 0)
247
244
  print_feature_line(feature)
248
- print_description(feature[:description])
245
+ print_description(feature.description)
249
246
  @io.flush
250
247
  end
251
248
 
@@ -256,11 +253,11 @@ module Cucumber
256
253
  end
257
254
 
258
255
  def print_comments(up_to_line, indent)
259
- comments = gherkin_document[:comments]
256
+ comments = gherkin_document.comments
260
257
  return if comments.empty? || comments.length <= @next_comment_to_be_printed
261
258
  comments[@next_comment_to_be_printed..-1].each do |comment|
262
- if comment[:location][:line] <= up_to_line
263
- @io.puts(format_string(comment[:text].strip, :comment).indent(indent))
259
+ if comment.location.line <= up_to_line
260
+ @io.puts(format_string(comment.text.strip, :comment).indent(indent))
264
261
  @next_comment_to_be_printed += 1
265
262
  end
266
263
  break if @next_comment_to_be_printed >= comments.length
@@ -269,11 +266,11 @@ module Cucumber
269
266
 
270
267
  def print_tags(tags, indent)
271
268
  return if !tags || tags.empty?
272
- @io.puts(tags.map { |tag| format_string(tag[:name], :tag) }.join(' ').indent(indent))
269
+ @io.puts(tags.map { |tag| format_string(tag.name, :tag) }.join(' ').indent(indent))
273
270
  end
274
271
 
275
272
  def print_feature_line(feature)
276
- print_keyword_name(feature[:keyword], feature[:name], 0)
273
+ print_keyword_name(feature.keyword, feature.name, 0)
277
274
  end
278
275
 
279
276
  def print_keyword_name(keyword, name, indent, location = nil)
@@ -296,29 +293,37 @@ module Cucumber
296
293
 
297
294
  def print_background_data
298
295
  @io.puts
299
- background = gherkin_document[:feature][:children].first[:background]
296
+ background = gherkin_document.feature.children.first.background
300
297
  @source_indent = calculate_source_indent_for_ast_node(background) if options[:source]
301
- print_comments(background[:location][:line], 2)
298
+ print_comments(background.location.line, 2)
302
299
  print_background_line(background)
303
- print_description(background[:description])
300
+ print_description(background.description)
304
301
  @io.flush
305
302
  end
306
303
 
307
304
  def print_background_line(background)
308
- print_keyword_name(background[:keyword], background[:name], 2, "#{current_feature_uri}:#{background[:location][:line]}")
305
+ print_keyword_name(background.keyword, background.name, 2, "#{current_feature_uri}:#{background.location.line}")
309
306
  end
310
307
 
311
308
  def print_scenario_data(test_case)
312
309
  scenario = scenario_source(test_case).scenario
313
- print_comments(scenario[:location][:line], 2)
314
- print_tags(scenario[:tags], 2)
310
+ print_comments(scenario.location.line, 2)
311
+ print_tags(scenario.tags, 2)
315
312
  print_scenario_line(scenario, test_case.location)
316
- print_description(scenario[:description])
313
+ print_description(scenario.description)
317
314
  @io.flush
318
315
  end
319
316
 
320
317
  def print_scenario_line(scenario, location = nil)
321
- print_keyword_name(scenario[:keyword], scenario[:name], 2, location)
318
+ print_keyword_name(scenario.keyword, scenario.name, 2, location)
319
+ end
320
+
321
+ def print_step_data?(event, exception_to_be_printed)
322
+ !event.test_step.hook? && (
323
+ print_background_steps ||
324
+ event.test_step.location.lines.max >= current_test_case.location.lines.max ||
325
+ exception_to_be_printed
326
+ )
322
327
  end
323
328
 
324
329
  def print_step_data(test_step, result)
@@ -334,7 +339,7 @@ module Cucumber
334
339
 
335
340
  def test_step_keyword(test_step)
336
341
  step = step_source(test_step).step
337
- step[:keyword]
342
+ step.keyword
338
343
  end
339
344
 
340
345
  def step_source(test_step)
@@ -355,38 +360,38 @@ module Cucumber
355
360
 
356
361
  def print_multiline_argument(test_step, result, indent)
357
362
  step = step_source(test_step).step
358
- if !step[:doc_string].nil?
359
- print_doc_string(step[:doc_string][:content], result.to_sym, indent)
360
- elsif !step[:data_table].nil?
361
- print_data_table(step[:data_table], result.to_sym, indent)
363
+ if !step.doc_string.nil?
364
+ print_doc_string(step.doc_string.content, result.to_sym, indent)
365
+ elsif !step.data_table.nil?
366
+ print_data_table(step.data_table, result.to_sym, indent)
362
367
  end
363
368
  end
364
369
 
365
370
  def print_data_table(data_table, status, indent)
366
- data_table[:rows].each do |row|
367
- print_comments(row[:location][:line], indent)
368
- @io.puts format_string(gherkin_source.split("\n")[row[:location][:line] - 1].strip, status).indent(indent)
371
+ data_table.rows.each do |row|
372
+ print_comments(row.location.line, indent)
373
+ @io.puts format_string(gherkin_source.split("\n")[row.location.line - 1].strip, status).indent(indent)
369
374
  end
370
375
  end
371
376
 
372
377
  def print_outline_data(scenario_outline) # rubocop:disable Metrics/AbcSize
373
- print_comments(scenario_outline[:location][:line], 2)
374
- print_tags(scenario_outline[:tags], 2)
378
+ print_comments(scenario_outline.location.line, 2)
379
+ print_tags(scenario_outline.tags, 2)
375
380
  @source_indent = calculate_source_indent_for_ast_node(scenario_outline) if options[:source]
376
- print_scenario_line(scenario_outline, "#{current_feature_uri}:#{scenario_outline[:location][:line]}")
377
- print_description(scenario_outline[:description])
378
- scenario_outline[:steps].each do |step|
379
- print_comments(step[:location][:line], 4)
380
- step_line = " #{step[:keyword]}#{step[:text]}"
381
+ print_scenario_line(scenario_outline, "#{current_feature_uri}:#{scenario_outline.location.line}")
382
+ print_description(scenario_outline.description)
383
+ scenario_outline.steps.each do |step|
384
+ print_comments(step.location.line, 4)
385
+ step_line = " #{step.keyword}#{step.text}"
381
386
  @io.print(format_string(step_line, :skipped))
382
387
  if options[:source]
383
- comment_line = format_string("# #{current_feature_uri}:#{step[:location][:line]}", :comment)
388
+ comment_line = format_string("# #{current_feature_uri}:#{step.location.line}", :comment)
384
389
  @io.print(comment_line.indent(@source_indent - step_line.length))
385
390
  end
386
391
  @io.puts
387
392
  next if options[:no_multiline]
388
- print_doc_string(step[:doc_string][:content], :skipped, 6) unless step[:doc_string].nil?
389
- print_data_table(step[:data_table], :skipped, 6) unless step[:data_table].nil?
393
+ print_doc_string(step.doc_string.content, :skipped, 6) unless step.doc_string.nil?
394
+ print_data_table(step.data_table, :skipped, 6) unless step.data_table.nil?
390
395
  end
391
396
  @io.flush
392
397
  end
@@ -398,13 +403,13 @@ module Cucumber
398
403
  end
399
404
 
400
405
  def print_examples_data(examples)
401
- print_comments(examples[:location][:line], 4)
402
- print_tags(examples[:tags], 4)
403
- print_keyword_name(examples[:keyword], examples[:name], 4)
404
- print_description(examples[:description])
406
+ print_comments(examples.location.line, 4)
407
+ print_tags(examples.tags, 4)
408
+ print_keyword_name(examples.keyword, examples.name, 4)
409
+ print_description(examples.description)
405
410
  unless options[:expand]
406
- print_comments(examples[:table_header][:location][:line], 6)
407
- @io.puts(gherkin_source.split("\n")[examples[:table_header][:location][:line] - 1].strip.indent(6))
411
+ print_comments(examples.table_header.location.line, 6)
412
+ @io.puts(gherkin_source.split("\n")[examples.table_header.location.line - 1].strip.indent(6))
408
413
  end
409
414
  @io.flush
410
415
  end
@@ -427,12 +432,12 @@ module Cucumber
427
432
  end
428
433
 
429
434
  def print_expanded_row_data(test_case)
430
- feature = gherkin_document[:feature]
431
- language_code = feature[:language] || 'en'
435
+ feature = gherkin_document.feature
436
+ language_code = feature.language || 'en'
432
437
  language = ::Gherkin::Dialect.for(language_code)
433
438
  scenario_keyword = language.scenario_keywords[0]
434
439
  row = scenario_source(test_case).row
435
- expanded_name = '| ' + row[:cells].map { |cell| cell[:value] }.join(' | ') + ' |'
440
+ expanded_name = '| ' + row.cells.map(&:value).join(' | ') + ' |'
436
441
  @source_indent = calculate_source_indent_for_expanded_test_case(test_case, scenario_keyword, expanded_name)
437
442
  @io.puts
438
443
  print_keyword_name(scenario_keyword, expanded_name, 6, test_case.location)
@@ -0,0 +1,31 @@
1
+ require 'cucumber/formatter/errors'
2
+
3
+ module Cucumber
4
+ module Formatter
5
+ module Query
6
+ class HookByTestStep
7
+ def initialize(config)
8
+ @hook_id_by_test_step_id = {}
9
+
10
+ config.on_event :test_step_created, &method(:on_test_step_created)
11
+ config.on_event :hook_test_step_created, &method(:on_hook_test_step_created)
12
+ end
13
+
14
+ def hook_id(test_step)
15
+ return @hook_id_by_test_step_id[test_step.id] if @hook_id_by_test_step_id.key?(test_step.id)
16
+ raise TestStepUnknownError, "No hook found for #{test_step.id} }. Known: #{@hook_id_by_test_step_id.keys}"
17
+ end
18
+
19
+ private
20
+
21
+ def on_test_step_created(event)
22
+ @hook_id_by_test_step_id[event.test_step.id] = nil
23
+ end
24
+
25
+ def on_hook_test_step_created(event)
26
+ @hook_id_by_test_step_id[event.test_step.id] = event.hook.id
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,26 @@
1
+ require 'cucumber/formatter/errors'
2
+
3
+ module Cucumber
4
+ module Formatter
5
+ module Query
6
+ class PickleByTest
7
+ def initialize(config)
8
+ @pickle_id_by_test_case_id = {}
9
+ config.on_event :test_case_created, &method(:on_test_case_created)
10
+ end
11
+
12
+ def pickle_id(test_case)
13
+ return @pickle_id_by_test_case_id[test_case.id] if @pickle_id_by_test_case_id.key?(test_case.id)
14
+
15
+ raise TestCaseUnknownError, "No pickle found for #{test_case.id} }. Known: #{@pickle_id_by_test_case_id.keys}"
16
+ end
17
+
18
+ private
19
+
20
+ def on_test_case_created(event)
21
+ @pickle_id_by_test_case_id[event.test_case.id] = event.pickle.id
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,26 @@
1
+ require 'cucumber/formatter/errors'
2
+
3
+ module Cucumber
4
+ module Formatter
5
+ module Query
6
+ class PickleStepByTestStep
7
+ def initialize(config)
8
+ @pickle_id_step_by_test_step_id = {}
9
+ config.on_event :test_step_created, &method(:on_test_step_created)
10
+ end
11
+
12
+ def pickle_step_id(test_step)
13
+ return @pickle_id_step_by_test_step_id[test_step.id] if @pickle_id_step_by_test_step_id.key?(test_step.id)
14
+
15
+ raise TestStepUnknownError, "No pickle step found for #{test_step.id} }. Known: #{@pickle_id_step_by_test_step_id.keys}"
16
+ end
17
+
18
+ private
19
+
20
+ def on_test_step_created(event)
21
+ @pickle_id_step_by_test_step_id[event.test_step.id] = event.pickle_step.id
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,40 @@
1
+ require 'cucumber/formatter/errors'
2
+
3
+ module Cucumber
4
+ module Formatter
5
+ module Query
6
+ class StepDefinitionsByTestStep
7
+ def initialize(config)
8
+ @step_definition_ids_by_test_step_id = {}
9
+ @step_match_arguments_by_test_step_id = {}
10
+
11
+ config.on_event :test_step_created, &method(:on_test_step_created)
12
+ config.on_event :step_activated, &method(:on_step_activated)
13
+ end
14
+
15
+ def step_definition_ids(test_step)
16
+ return @step_definition_ids_by_test_step_id[test_step.id] if @step_definition_ids_by_test_step_id.key?(test_step.id)
17
+
18
+ raise TestStepUnknownError, "No step definition found for #{test_step.id} }. Known: #{@step_definition_ids_by_test_step_id.keys}"
19
+ end
20
+
21
+ def step_match_arguments(test_step)
22
+ return @step_match_arguments_by_test_step_id[test_step.id] if @step_match_arguments_by_test_step_id.key?(test_step.id)
23
+
24
+ raise TestStepUnknownError, "No step match arguments found for #{test_step.id} }. Known: #{@step_match_arguments_by_test_step_id.keys}"
25
+ end
26
+
27
+ private
28
+
29
+ def on_test_step_created(event)
30
+ @step_definition_ids_by_test_step_id[event.test_step.id] = []
31
+ end
32
+
33
+ def on_step_activated(event)
34
+ @step_definition_ids_by_test_step_id[event.test_step.id] << event.step_match.step_definition.id
35
+ @step_match_arguments_by_test_step_id[event.test_step.id] = event.step_match.step_arguments
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,40 @@
1
+ require 'cucumber/formatter/errors'
2
+
3
+ module Cucumber
4
+ module Formatter
5
+ module Query
6
+ class TestCaseStartedByTestCase
7
+ def initialize(config)
8
+ @config = config
9
+ config.on_event :test_case_created, &method(:on_test_case_created)
10
+ config.on_event :test_case_started, &method(:on_test_case_started)
11
+
12
+ @attempts_by_test_case_id = {}
13
+ @test_case_started_id_by_test_case_id = {}
14
+ end
15
+
16
+ def attempt_by_test_case(test_case)
17
+ raise TestCaseUnknownError, "No test case found for #{test_case.id} }. Known: #{@attempts_by_test_case_id.keys}" unless @attempts_by_test_case_id.key?(test_case.id)
18
+ @attempts_by_test_case_id[test_case.id]
19
+ end
20
+
21
+ def test_case_started_id_by_test_case(test_case)
22
+ raise TestCaseUnknownError, "No test case found for #{test_case.id} }. Known: #{@test_case_started_id_by_test_case_id.keys}" unless @test_case_started_id_by_test_case_id.key?(test_case.id)
23
+ @test_case_started_id_by_test_case_id[test_case.id]
24
+ end
25
+
26
+ private
27
+
28
+ def on_test_case_created(event)
29
+ @attempts_by_test_case_id[event.test_case.id] = 0
30
+ @test_case_started_id_by_test_case_id[event.test_case.id] = nil
31
+ end
32
+
33
+ def on_test_case_started(event)
34
+ @attempts_by_test_case_id[event.test_case.id] += 1
35
+ @test_case_started_id_by_test_case_id[event.test_case.id] = @config.id_generator.new_id
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -47,7 +47,7 @@ module Cucumber
47
47
  def print_feature(test_case)
48
48
  uri = test_case.location.file
49
49
  return if @current_feature_uri == uri
50
- feature_name = gherkin_document(uri)[:feature][:name]
50
+ feature_name = gherkin_document(uri).feature.name
51
51
  @io.puts unless @current_feature_uri.nil?
52
52
  @io.puts feature_name
53
53
  @current_feature_uri = uri
@@ -44,7 +44,7 @@ module Cucumber
44
44
  stepdef_key = StepDefKey.new(step_definition.expression.to_s, step_definition.location)
45
45
  unless @stepdef_to_match[stepdef_key].map { |key| key[:location] }.include? test_step.location
46
46
  duration = DurationExtractor.new(result).result_duration
47
- keyword = @ast_lookup.step_source(test_step).step[:keyword]
47
+ keyword = @ast_lookup.step_source(test_step).step.keyword
48
48
 
49
49
  @stepdef_to_match[stepdef_key] << {
50
50
  keyword: keyword,
@@ -84,7 +84,7 @@ module Cucumber
84
84
  end
85
85
 
86
86
  def print_step_definition(stepdef_key)
87
- @io.print format_string(format('%.7f', stepdef_key.mean_duration), :skipped) + ' ' unless config.dry_run?
87
+ @io.print format_string(format('%<duration>.7f', duration: stepdef_key.mean_duration), :skipped) + ' ' unless config.dry_run?
88
88
  @io.print format_string(stepdef_key.regexp_source, stepdef_key.status)
89
89
  if config.source?
90
90
  indent = max_length - stepdef_key.regexp_source.unpack('U*').length
@@ -97,7 +97,7 @@ module Cucumber
97
97
  def print_steps(stepdef_key)
98
98
  @stepdef_to_match[stepdef_key].each do |step|
99
99
  @io.print ' '
100
- @io.print format_string(format('%.7f', step[:duration]), :skipped) + ' ' unless config.dry_run?
100
+ @io.print format_string(format('%<duration>.7f', duration: step[:duration]), :skipped) + ' ' unless config.dry_run?
101
101
  @io.print format_step(step[:keyword], step[:step_match], step[:status], nil)
102
102
  if config.source?
103
103
  indent = max_length - (step[:keyword].unpack('U*').length + step[:step_match].format_args.unpack('U*').length)