cucumber 3.1.2 → 4.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (112) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +173 -14
  3. data/CONTRIBUTING.md +2 -18
  4. data/README.md +4 -5
  5. data/bin/cucumber +1 -1
  6. data/lib/autotest/cucumber_mixin.rb +34 -39
  7. data/lib/cucumber.rb +1 -1
  8. data/lib/cucumber/cli/configuration.rb +5 -5
  9. data/lib/cucumber/cli/main.rb +12 -12
  10. data/lib/cucumber/cli/options.rb +69 -74
  11. data/lib/cucumber/cli/profile_loader.rb +49 -26
  12. data/lib/cucumber/configuration.rb +31 -23
  13. data/lib/cucumber/constantize.rb +2 -5
  14. data/lib/cucumber/deprecate.rb +31 -7
  15. data/lib/cucumber/errors.rb +5 -7
  16. data/lib/cucumber/events.rb +13 -6
  17. data/lib/cucumber/events/envelope.rb +9 -0
  18. data/lib/cucumber/events/gherkin_source_parsed.rb +11 -0
  19. data/lib/cucumber/events/hook_test_step_created.rb +13 -0
  20. data/lib/cucumber/events/step_activated.rb +2 -1
  21. data/lib/cucumber/events/test_case_created.rb +13 -0
  22. data/lib/cucumber/events/test_case_ready.rb +12 -0
  23. data/lib/cucumber/events/test_step_created.rb +13 -0
  24. data/lib/cucumber/events/undefined_parameter_type.rb +10 -0
  25. data/lib/cucumber/file_specs.rb +6 -6
  26. data/lib/cucumber/filters.rb +1 -0
  27. data/lib/cucumber/filters/activate_steps.rb +5 -3
  28. data/lib/cucumber/filters/broadcast_test_case_ready_event.rb +12 -0
  29. data/lib/cucumber/filters/prepare_world.rb +5 -9
  30. data/lib/cucumber/filters/quit.rb +1 -3
  31. data/lib/cucumber/filters/tag_limits/verifier.rb +2 -4
  32. data/lib/cucumber/formatter/ansicolor.rb +40 -45
  33. data/lib/cucumber/formatter/ast_lookup.rb +165 -0
  34. data/lib/cucumber/formatter/backtrace_filter.rb +9 -8
  35. data/lib/cucumber/formatter/console.rb +58 -66
  36. data/lib/cucumber/formatter/console_counts.rb +4 -9
  37. data/lib/cucumber/formatter/console_issues.rb +6 -3
  38. data/lib/cucumber/formatter/duration.rb +1 -1
  39. data/lib/cucumber/formatter/duration_extractor.rb +3 -1
  40. data/lib/cucumber/formatter/errors.rb +6 -0
  41. data/lib/cucumber/formatter/fanout.rb +2 -0
  42. data/lib/cucumber/formatter/html.rb +11 -598
  43. data/lib/cucumber/formatter/http_io.rb +146 -0
  44. data/lib/cucumber/formatter/ignore_missing_messages.rb +1 -1
  45. data/lib/cucumber/formatter/interceptor.rb +8 -28
  46. data/lib/cucumber/formatter/io.rb +17 -11
  47. data/lib/cucumber/formatter/json.rb +101 -109
  48. data/lib/cucumber/formatter/junit.rb +56 -56
  49. data/lib/cucumber/formatter/message.rb +22 -0
  50. data/lib/cucumber/formatter/message_builder.rb +255 -0
  51. data/lib/cucumber/formatter/pretty.rb +359 -153
  52. data/lib/cucumber/formatter/progress.rb +30 -32
  53. data/lib/cucumber/formatter/query/hook_by_test_step.rb +31 -0
  54. data/lib/cucumber/formatter/query/pickle_by_test.rb +26 -0
  55. data/lib/cucumber/formatter/query/pickle_step_by_test_step.rb +26 -0
  56. data/lib/cucumber/formatter/query/step_definitions_by_test_step.rb +40 -0
  57. data/lib/cucumber/formatter/query/test_case_started_by_test_case.rb +40 -0
  58. data/lib/cucumber/formatter/rerun.rb +22 -4
  59. data/lib/cucumber/formatter/stepdefs.rb +1 -2
  60. data/lib/cucumber/formatter/steps.rb +2 -3
  61. data/lib/cucumber/formatter/summary.rb +16 -8
  62. data/lib/cucumber/formatter/unicode.rb +15 -17
  63. data/lib/cucumber/formatter/usage.rb +11 -10
  64. data/lib/cucumber/gherkin/data_table_parser.rb +17 -6
  65. data/lib/cucumber/gherkin/formatter/ansi_escapes.rb +13 -17
  66. data/lib/cucumber/gherkin/formatter/escaping.rb +2 -2
  67. data/lib/cucumber/gherkin/steps_parser.rb +17 -8
  68. data/lib/cucumber/glue/dsl.rb +1 -1
  69. data/lib/cucumber/glue/hook.rb +34 -11
  70. data/lib/cucumber/glue/invoke_in_world.rb +13 -18
  71. data/lib/cucumber/glue/proto_world.rb +42 -33
  72. data/lib/cucumber/glue/registry_and_more.rb +42 -12
  73. data/lib/cucumber/glue/snippet.rb +23 -22
  74. data/lib/cucumber/glue/step_definition.rb +42 -19
  75. data/lib/cucumber/glue/world_factory.rb +1 -1
  76. data/lib/cucumber/hooks.rb +11 -11
  77. data/lib/cucumber/multiline_argument.rb +4 -6
  78. data/lib/cucumber/multiline_argument/data_table.rb +97 -64
  79. data/lib/cucumber/multiline_argument/data_table/diff_matrices.rb +1 -1
  80. data/lib/cucumber/multiline_argument/doc_string.rb +1 -1
  81. data/lib/cucumber/platform.rb +3 -3
  82. data/lib/cucumber/rake/task.rb +16 -16
  83. data/lib/cucumber/rspec/disable_option_parser.rb +9 -8
  84. data/lib/cucumber/running_test_case.rb +2 -53
  85. data/lib/cucumber/runtime.rb +54 -58
  86. data/lib/cucumber/runtime/after_hooks.rb +8 -4
  87. data/lib/cucumber/runtime/before_hooks.rb +8 -4
  88. data/lib/cucumber/runtime/for_programming_languages.rb +4 -2
  89. data/lib/cucumber/runtime/step_hooks.rb +3 -2
  90. data/lib/cucumber/runtime/support_code.rb +13 -15
  91. data/lib/cucumber/runtime/user_interface.rb +6 -16
  92. data/lib/cucumber/step_definition_light.rb +4 -3
  93. data/lib/cucumber/step_definitions.rb +2 -2
  94. data/lib/cucumber/step_match.rb +12 -11
  95. data/lib/cucumber/step_match_search.rb +2 -1
  96. data/lib/cucumber/term/ansicolor.rb +9 -9
  97. data/lib/cucumber/version +1 -1
  98. metadata +224 -82
  99. data/lib/cucumber/events/gherkin_source_parsed.rb~ +0 -14
  100. data/lib/cucumber/formatter/ast_lookup.rb~ +0 -9
  101. data/lib/cucumber/formatter/cucumber.css +0 -286
  102. data/lib/cucumber/formatter/cucumber.sass +0 -247
  103. data/lib/cucumber/formatter/hook_query_visitor.rb +0 -42
  104. data/lib/cucumber/formatter/html_builder.rb +0 -121
  105. data/lib/cucumber/formatter/inline-js.js +0 -30
  106. data/lib/cucumber/formatter/jquery-min.js +0 -154
  107. data/lib/cucumber/formatter/json_pretty.rb +0 -11
  108. data/lib/cucumber/formatter/legacy_api/adapter.rb +0 -1028
  109. data/lib/cucumber/formatter/legacy_api/ast.rb +0 -394
  110. data/lib/cucumber/formatter/legacy_api/results.rb +0 -50
  111. data/lib/cucumber/formatter/legacy_api/runtime_facade.rb +0 -32
  112. data/lib/cucumber/step_argument.rb +0 -25
@@ -8,9 +8,7 @@ module Cucumber
8
8
  end
9
9
 
10
10
  def test_case(test_case)
11
- unless Cucumber.wants_to_quit
12
- test_case.describe_to @receiver
13
- end
11
+ test_case.describe_to @receiver unless Cucumber.wants_to_quit
14
12
  self
15
13
  end
16
14
 
@@ -17,10 +17,8 @@ module Cucumber
17
17
 
18
18
  def collect_breaches(test_case_index)
19
19
  tag_limits.reduce([]) do |breaches, (tag_name, limit)|
20
- breaches.tap do |breaches|
21
- if test_case_index.count_by_tag_name(tag_name) > limit
22
- breaches << Breach.new(tag_name, limit, test_case_index.locations_of_tag_name(tag_name))
23
- end
20
+ breaches.tap do |breach|
21
+ breach << Breach.new(tag_name, limit, test_case_index.locations_of_tag_name(tag_name)) if test_case_index.count_by_tag_name(tag_name) > limit
24
22
  end
25
23
  end
26
24
  end
@@ -55,20 +55,18 @@ module Cucumber
55
55
  include Cucumber::Term::ANSIColor
56
56
 
57
57
  ALIASES = Hash.new do |h, k|
58
- if k.to_s =~ /(.*)_param/
59
- h[$1] + ',bold'
60
- end
61
- end.merge({
62
- 'undefined' => 'yellow',
63
- 'pending' => 'yellow',
64
- 'flaky' => 'yellow',
65
- 'failed' => 'red',
66
- 'passed' => 'green',
67
- 'outline' => 'cyan',
68
- 'skipped' => 'cyan',
69
- 'comment' => 'grey',
70
- 'tag' => 'cyan'
71
- })
58
+ h[Regexp.last_match(1)] + ',bold' if k.to_s =~ /(.*)_param/
59
+ end.merge(
60
+ 'undefined' => 'yellow',
61
+ 'pending' => 'yellow',
62
+ 'flaky' => 'yellow',
63
+ 'failed' => 'red',
64
+ 'passed' => 'green',
65
+ 'outline' => 'cyan',
66
+ 'skipped' => 'cyan',
67
+ 'comment' => 'grey',
68
+ 'tag' => 'cyan'
69
+ )
72
70
 
73
71
  if ENV['CUCUMBER_COLORS'] # Example: export CUCUMBER_COLORS="passed=red:failed=yellow"
74
72
  ENV['CUCUMBER_COLORS'].split(':').each do |pair|
@@ -89,45 +87,42 @@ module Cucumber
89
87
  # red(bold(string, &proc)) + red
90
88
  # end
91
89
  ALIASES.each_key do |method_name|
92
- unless method_name =~ /.*_param/
93
- code = <<-EOF
90
+ next if method_name =~ /.*_param/
91
+ code = <<-COLOR
94
92
  def #{method_name}(string=nil, &proc)
95
- #{ALIASES[method_name].split(",").join("(") + "(string, &proc" + ")" * ALIASES[method_name].split(",").length}
93
+ #{ALIASES[method_name].split(',').join('(') + '(string, &proc' + ')' * ALIASES[method_name].split(',').length}
96
94
  end
97
95
  # This resets the colour to the non-param colour
98
96
  def #{method_name}_param(string=nil, &proc)
99
- #{ALIASES[method_name + '_param'].split(",").join("(") + "(string, &proc" + ")" * ALIASES[method_name + '_param'].split(",").length} + #{ALIASES[method_name].split(",").join(' + ')}
97
+ #{ALIASES[method_name + '_param'].split(',').join('(') + '(string, &proc' + ')' * ALIASES[method_name + '_param'].split(',').length} + #{ALIASES[method_name].split(',').join(' + ')}
100
98
  end
101
- EOF
102
- eval(code)
103
- end
99
+ COLOR
100
+ eval(code) # rubocop:disable Security/Eval
104
101
  end
105
102
 
106
103
  def self.define_grey #:nodoc:
107
- begin
108
- gem 'genki-ruby-terminfo'
109
- require 'terminfo'
110
- case TermInfo.default_object.tigetnum('colors')
111
- when 0
112
- raise "Your terminal doesn't support colours."
113
- when 1
114
- ::Cucumber::Term::ANSIColor.coloring = false
115
- alias grey white
116
- when 2..8
117
- alias grey white
118
- else
119
- define_real_grey
120
- end
121
- rescue Exception => e
122
- if e.class.name == 'TermInfo::TermInfoError'
123
- STDERR.puts '*** WARNING ***'
124
- STDERR.puts "You have the genki-ruby-terminfo gem installed, but you haven't set your TERM variable."
125
- STDERR.puts 'Try setting it to TERM=xterm-256color to get grey colour in output.'
126
- STDERR.puts "\n"
127
- alias grey white
128
- else
129
- define_real_grey
130
- end
104
+ gem 'genki-ruby-terminfo'
105
+ require 'terminfo'
106
+ case TermInfo.default_object.tigetnum('colors')
107
+ when 0
108
+ raise "Your terminal doesn't support colours."
109
+ when 1
110
+ ::Cucumber::Term::ANSIColor.coloring = false
111
+ alias_method :grey, :white
112
+ when 2..8
113
+ alias_method :grey, :white # rubocop:disable Lint/DuplicateMethods
114
+ else
115
+ define_real_grey
116
+ end
117
+ rescue Exception => e # rubocop:disable Lint/RescueException
118
+ if e.class.name == 'TermInfo::TermInfoError'
119
+ STDERR.puts '*** WARNING ***'
120
+ STDERR.puts "You have the genki-ruby-terminfo gem installed, but you haven't set your TERM variable."
121
+ STDERR.puts 'Try setting it to TERM=xterm-256color to get grey colour in output.'
122
+ STDERR.puts "\n"
123
+ alias_method :grey, :white
124
+ else
125
+ define_real_grey
131
126
  end
132
127
  end
133
128
 
@@ -0,0 +1,165 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Cucumber
4
+ module Formatter
5
+ class AstLookup
6
+ def initialize(config)
7
+ @gherkin_documents = {}
8
+ @test_case_lookups = {}
9
+ @test_step_lookups = {}
10
+ @step_keyword_lookups = {}
11
+ config.on_event :gherkin_source_parsed, &method(:on_gherkin_source_parsed)
12
+ end
13
+
14
+ def on_gherkin_source_parsed(event)
15
+ @gherkin_documents[event.gherkin_document.uri] = event.gherkin_document
16
+ end
17
+
18
+ def gherkin_document(uri)
19
+ @gherkin_documents[uri]
20
+ end
21
+
22
+ def scenario_source(test_case)
23
+ uri = test_case.location.file
24
+ @test_case_lookups[uri] ||= TestCaseLookupBuilder.new(gherkin_document(uri)).lookup_hash
25
+ @test_case_lookups[uri][test_case.location.lines.max]
26
+ end
27
+
28
+ def step_source(test_step)
29
+ uri = test_step.location.file
30
+ @test_step_lookups[uri] ||= TestStepLookupBuilder.new(gherkin_document(uri)).lookup_hash
31
+ @test_step_lookups[uri][test_step.location.lines.min]
32
+ end
33
+
34
+ def snippet_step_keyword(test_step)
35
+ uri = test_step.location.file
36
+ document = gherkin_document(uri)
37
+ dialect = ::Gherkin::Dialect.for(document.feature.language)
38
+ given_when_then_keywords = [dialect.given_keywords, dialect.when_keywords, dialect.then_keywords].flatten.uniq.reject { |kw| kw == '* ' }
39
+ keyword_lookup = step_keyword_lookup(uri)
40
+ keyword = nil
41
+ node = keyword_lookup[test_step.location.lines.min]
42
+ while keyword.nil?
43
+ if given_when_then_keywords.include?(node.keyword)
44
+ keyword = node.keyword
45
+ break
46
+ end
47
+ break if node.previous_node.nil?
48
+ node = node.previous_node
49
+ end
50
+ keyword = dialect.given_keywords.reject { |kw| kw == '* ' }[0] if keyword.nil?
51
+ keyword = Cucumber::Gherkin::I18n.code_keyword_for(keyword)
52
+ keyword
53
+ end
54
+
55
+ ScenarioSource = Struct.new(:type, :scenario)
56
+
57
+ ScenarioOutlineSource = Struct.new(:type, :scenario_outline, :examples, :row)
58
+
59
+ StepSource = Struct.new(:type, :step)
60
+
61
+ private
62
+
63
+ def step_keyword_lookup(uri)
64
+ @step_keyword_lookups[uri] ||= KeywordLookupBuilder.new(gherkin_document(uri)).lookup_hash
65
+ end
66
+
67
+ class TestCaseLookupBuilder
68
+ attr_reader :lookup_hash
69
+
70
+ def initialize(gherkin_document)
71
+ @lookup_hash = {}
72
+ process_scenario_container(gherkin_document.feature)
73
+ end
74
+
75
+ private
76
+
77
+ def process_scenario_container(container)
78
+ container.children.each do |child|
79
+ if child.respond_to?(:rule) && child.rule
80
+ process_scenario_container(child.rule)
81
+ elsif child.respond_to?(:scenario) && child.scenario
82
+ process_scenario(child)
83
+ end
84
+ end
85
+ end
86
+
87
+ def process_scenario(child)
88
+ if child.scenario.examples.empty?
89
+ @lookup_hash[child.scenario.location.line] = ScenarioSource.new(:Scenario, child.scenario)
90
+ else
91
+ child.scenario.examples.each do |examples|
92
+ examples.table_body.each do |row|
93
+ @lookup_hash[row.location.line] = ScenarioOutlineSource.new(:ScenarioOutline, child.scenario, examples, row)
94
+ end
95
+ end
96
+ end
97
+ end
98
+ end
99
+
100
+ class TestStepLookupBuilder
101
+ attr_reader :lookup_hash
102
+
103
+ def initialize(gherkin_document)
104
+ @lookup_hash = {}
105
+ process_scenario_container(gherkin_document.feature)
106
+ end
107
+
108
+ private
109
+
110
+ def process_scenario_container(container)
111
+ container.children.each do |child|
112
+ if child.respond_to?(:rule) && child.rule
113
+ process_scenario_container(child.rule)
114
+ elsif child.respond_to?(:scenario) && child.scenario
115
+ child.scenario.steps.each do |step|
116
+ @lookup_hash[step.location.line] = StepSource.new(:Step, step)
117
+ end
118
+ elsif !child.background.nil?
119
+ child.background.steps.each do |step|
120
+ @lookup_hash[step.location.line] = StepSource.new(:Step, step)
121
+ end
122
+ end
123
+ end
124
+ end
125
+ end
126
+
127
+ KeywordSearchNode = Struct.new(:keyword, :previous_node)
128
+
129
+ class KeywordLookupBuilder
130
+ attr_reader :lookup_hash
131
+
132
+ def initialize(gherkin_document)
133
+ @lookup_hash = {}
134
+ process_scenario_container(gherkin_document.feature, nil)
135
+ end
136
+
137
+ private
138
+
139
+ # rubocop:disable Metrics/PerceivedComplexity
140
+ def process_scenario_container(container, original_previous_node)
141
+ container.children.each do |child|
142
+ previous_node = original_previous_node
143
+ if child.respond_to?(:rule) && child.rule
144
+ process_scenario_container(child.rule, original_previous_node)
145
+ elsif child.respond_to?(:scenario) && child.scenario
146
+ child.scenario.steps.each do |step|
147
+ node = KeywordSearchNode.new(step.keyword, previous_node)
148
+ @lookup_hash[step.location.line] = node
149
+ previous_node = node
150
+ end
151
+ elsif child.respond_to?(:background) && child.background
152
+ child.background.steps.each do |step|
153
+ node = KeywordSearchNode.new(step.keyword, previous_node)
154
+ @lookup_hash[step.location.line] = node
155
+ previous_node = node
156
+ original_previous_node = previous_node
157
+ end
158
+ end
159
+ end
160
+ end
161
+ # rubocop:enable Metrics/PerceivedComplexity
162
+ end
163
+ end
164
+ end
165
+ end
@@ -4,22 +4,23 @@ require 'cucumber/platform'
4
4
 
5
5
  module Cucumber
6
6
  module Formatter
7
- @backtrace_filters = %w(
7
+ @backtrace_filters = %w[
8
8
  /vendor/rails
9
9
  lib/cucumber
10
10
  bin/cucumber:
11
11
  lib/rspec
12
12
  gems/
13
+ site_ruby/
13
14
  minitest
14
15
  test/unit
15
16
  .gem/ruby
16
- lib/ruby/
17
17
  bin/bundle
18
- )
18
+ ]
19
19
 
20
- if ::Cucumber::JRUBY
21
- @backtrace_filters << 'org/jruby/'
22
- end
20
+ @backtrace_filters << RbConfig::CONFIG['rubyarchdir'] if RbConfig::CONFIG['rubyarchdir']
21
+ @backtrace_filters << RbConfig::CONFIG['rubylibdir'] if RbConfig::CONFIG['rubylibdir']
22
+
23
+ @backtrace_filters << 'org/jruby/' if ::Cucumber::JRUBY
23
24
 
24
25
  BACKTRACE_FILTER_PATTERNS = Regexp.new(@backtrace_filters.join('|'))
25
26
 
@@ -31,7 +32,7 @@ module Cucumber
31
32
  def exception
32
33
  return @exception if ::Cucumber.use_full_backtrace
33
34
 
34
- pwd_pattern = /#{::Regexp.escape(::Dir.pwd)}\//m
35
+ pwd_pattern = /#{::Regexp.escape(::Dir.pwd)}\//m # rubocop:disable Style/RegexpLiteral
35
36
  backtrace = @exception.backtrace.map { |line| line.gsub(pwd_pattern, './') }
36
37
 
37
38
  filtered = (backtrace || []).reject do |line|
@@ -41,7 +42,7 @@ module Cucumber
41
42
  if ::ENV['CUCUMBER_TRUNCATE_OUTPUT']
42
43
  # Strip off file locations
43
44
  filtered = filtered.map do |line|
44
- line =~ /(.*):in `/ ? $1 : line
45
+ line =~ /(.*):in `/ ? Regexp.last_match(1) : line
45
46
  end
46
47
  end
47
48
 
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # rubocop:disable Metrics/ModuleLength
4
+
3
5
  require 'cucumber/formatter/ansicolor'
4
6
  require 'cucumber/formatter/duration'
5
7
  require 'cucumber/gherkin/i18n'
@@ -46,7 +48,7 @@ module Cucumber
46
48
  def format_string(o, status)
47
49
  fmt = format_for(status)
48
50
  o.to_s.split("\n").map do |line|
49
- if Proc === fmt
51
+ if Proc == fmt.class
50
52
  fmt.call(line)
51
53
  else
52
54
  fmt % line
@@ -54,10 +56,6 @@ module Cucumber
54
56
  end.join("\n")
55
57
  end
56
58
 
57
- def print_steps(status)
58
- print_elements(runtime.steps(status), status, 'steps')
59
- end
60
-
61
59
  def print_elements(elements, status, kind)
62
60
  return if elements.empty?
63
61
 
@@ -109,28 +107,32 @@ module Cucumber
109
107
  end
110
108
 
111
109
  # http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/10655
112
- def linebreaks(s, max)
113
- return s unless max && max > 0
114
- s.gsub(/.{1,#{max}}(?:\s|\Z)/) { ($& + 5.chr).gsub(/\n\005/, "\n").gsub(/\005/, "\n") }.rstrip
110
+ def linebreaks(msg, max)
111
+ return msg unless max && max > 0
112
+ msg.gsub(/.{1,#{max}}(?:\s|\Z)/) { ($& + 5.chr).gsub(/\n\005/, "\n").gsub(/\005/, "\n") }.rstrip
115
113
  end
116
114
 
117
- def collect_snippet_data(test_step, result)
115
+ def collect_snippet_data(test_step, ast_lookup)
118
116
  # collect snippet data for undefined steps
119
- return if hook?(test_step)
120
- keyword = test_step.source.last.actual_keyword(@previous_step_keyword)
121
- @previous_step_keyword = keyword
122
- return unless result.undefined?
123
- @snippets_input << Console::SnippetData.new(keyword, test_step.source.last)
117
+ keyword = ast_lookup.snippet_step_keyword(test_step)
118
+ @snippets_input << Console::SnippetData.new(keyword, test_step)
119
+ end
120
+
121
+ def collect_undefined_parameter_type_names(undefined_parameter_type)
122
+ @undefined_parameter_types << undefined_parameter_type.type_name
124
123
  end
125
124
 
126
125
  def print_snippets(options)
127
126
  return unless options[:snippets]
128
- return if runtime.steps(:undefined).empty?
129
127
 
130
128
  snippet_text_proc = lambda do |step_keyword, step_name, multiline_arg|
131
- runtime.snippet_text(step_keyword, step_name, multiline_arg)
129
+ snippet_text(step_keyword, step_name, multiline_arg)
130
+ end
131
+ do_print_snippets(snippet_text_proc) unless @snippets_input.empty?
132
+
133
+ @undefined_parameter_types.map do |type_name|
134
+ do_print_undefined_parameter_type_snippet(type_name)
132
135
  end
133
- do_print_snippets(snippet_text_proc)
134
136
  end
135
137
 
136
138
  def do_print_snippets(snippet_text_proc)
@@ -146,10 +148,14 @@ module Cucumber
146
148
  @io.flush
147
149
  end
148
150
 
149
- def print_passing_wip(options)
150
- return unless options[:wip]
151
- passed_messages = element_messages(runtime.scenarios(:passed), :passed)
152
- do_print_passing_wip(passed_messages)
151
+ def print_passing_wip(config, passed_test_cases, ast_lookup)
152
+ return unless config.wip?
153
+ messages = passed_test_cases.map do |test_case|
154
+ scenario_source = ast_lookup.scenario_source(test_case)
155
+ keyword = scenario_source.type == :Scenario ? scenario_source.scenario.keyword : scenario_source.scenario_outline.keyword
156
+ linebreaks("#{test_case.location.on_line(test_case.location.lines.max)}:in `#{keyword}: #{test_case.name}'", ENV['CUCUMBER_TRUNCATE_OUTPUT'].to_i)
157
+ end
158
+ do_print_passing_wip(messages)
153
159
  end
154
160
 
155
161
  def do_print_passing_wip(passed_messages)
@@ -161,59 +167,47 @@ module Cucumber
161
167
  end
162
168
  end
163
169
 
164
- def embed(file, mime_type, label)
165
- # no-op
166
- end
167
-
168
- # define @delayed_messages = [] in your Formatter if you want to
169
- # activate this feature
170
- def puts(*messages)
171
- if @delayed_messages
172
- @delayed_messages += messages
173
- else
174
- if @io
175
- @io.puts
176
- messages.each do |message|
177
- @io.puts(format_string(message, :tag))
178
- end
179
- @io.flush
180
- end
181
- end
182
- end
183
-
184
- def print_messages
185
- @delayed_messages.each { |message| print_message(message) }
186
- empty_messages
187
- end
188
-
189
- def print_table_row_messages
190
- return if @delayed_messages.empty?
191
- @io.print(format_string(@delayed_messages.join(', '), :tag).indent(2))
192
- @io.flush
193
- empty_messages
194
- end
195
-
196
- def print_message(message)
197
- @io.puts(format_string(message, :tag).indent(@indent))
170
+ def attach(src, media_type)
171
+ return unless media_type == 'text/x.cucumber.log+plain'
172
+ return unless @io
173
+ @io.puts
174
+ @io.puts(format_string(src, :tag))
198
175
  @io.flush
199
176
  end
200
177
 
201
- def empty_messages
202
- @delayed_messages = []
203
- end
204
-
205
178
  def print_profile_information
206
179
  return if @options[:skip_profile_information] || @options[:profiles].nil? || @options[:profiles].empty?
207
180
  do_print_profile_information(@options[:profiles])
208
181
  end
209
182
 
210
183
  def do_print_profile_information(profiles)
211
- profiles_sentence = profiles.size == 1 ? profiles.first :
212
- "#{profiles[0...-1].join(', ')} and #{profiles.last}"
184
+ profiles_sentence = if profiles.size == 1
185
+ profiles.first
186
+ else
187
+ "#{profiles[0...-1].join(', ')} and #{profiles.last}"
188
+ end
213
189
 
214
190
  @io.puts "Using the #{profiles_sentence} profile#{'s' if profiles.size > 1}..."
215
191
  end
216
192
 
193
+ def do_print_undefined_parameter_type_snippet(type_name)
194
+ camelized = type_name.split(/_|-/).collect(&:capitalize).join
195
+
196
+ @io.puts [
197
+ "The parameter #{type_name} is not defined. You can define a new one with:",
198
+ '',
199
+ 'ParameterType(',
200
+ " name: '#{type_name}',",
201
+ ' regexp: /some regexp here/,',
202
+ " type: #{camelized},",
203
+ ' # The transformer takes as many arguments as there are capture groups in the regexp,',
204
+ ' # or just one if there are none.',
205
+ " transformer: ->(s) { #{camelized}.new(s) }",
206
+ ')',
207
+ ''
208
+ ].join("\n")
209
+ end
210
+
217
211
  private
218
212
 
219
213
  FORMATS = Hash.new { |hash, format| hash[format] = method(format).to_proc }
@@ -225,10 +219,6 @@ module Cucumber
225
219
  fmt
226
220
  end
227
221
 
228
- def hook?(test_step)
229
- not test_step.source.last.respond_to?(:actual_keyword)
230
- end
231
-
232
222
  def element_messages(elements, status)
233
223
  elements.map do |element|
234
224
  if status == :failed
@@ -249,9 +239,11 @@ module Cucumber
249
239
  class SnippetData
250
240
  attr_reader :actual_keyword, :step
251
241
  def initialize(actual_keyword, step)
252
- @actual_keyword, @step = actual_keyword, step
242
+ @actual_keyword = actual_keyword
243
+ @step = step
253
244
  end
254
245
  end
255
246
  end
256
247
  end
257
248
  end
249
+ # rubocop:enable Metrics/ModuleLength