cucumber 7.1.0 → 8.0.0.rc.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (76) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +79 -1
  3. data/CONTRIBUTING.md +2 -6
  4. data/README.md +4 -7
  5. data/lib/autotest/cucumber_mixin.rb +5 -2
  6. data/lib/autotest/discover.rb +3 -2
  7. data/lib/cucumber/cli/configuration.rb +4 -1
  8. data/lib/cucumber/cli/main.rb +4 -3
  9. data/lib/cucumber/cli/options.rb +8 -2
  10. data/lib/cucumber/cli/profile_loader.rb +1 -5
  11. data/lib/cucumber/cli/rerun_file.rb +1 -1
  12. data/lib/cucumber/configuration.rb +5 -4
  13. data/lib/cucumber/constantize.rb +1 -1
  14. data/lib/cucumber/deprecate.rb +2 -1
  15. data/lib/cucumber/errors.rb +1 -1
  16. data/lib/cucumber/events/hook_test_step_created.rb +1 -2
  17. data/lib/cucumber/events/step_activated.rb +0 -6
  18. data/lib/cucumber/events/step_definition_registered.rb +0 -5
  19. data/lib/cucumber/events/test_case_created.rb +1 -2
  20. data/lib/cucumber/events/test_run_finished.rb +2 -1
  21. data/lib/cucumber/events/test_step_created.rb +1 -2
  22. data/lib/cucumber/events/undefined_parameter_type.rb +1 -2
  23. data/lib/cucumber/events.rb +1 -1
  24. data/lib/cucumber/file_specs.rb +2 -1
  25. data/lib/cucumber/filters/activate_steps.rb +1 -0
  26. data/lib/cucumber/filters/tag_limits/verifier.rb +1 -3
  27. data/lib/cucumber/filters/tag_limits.rb +1 -3
  28. data/lib/cucumber/formatter/ansicolor.rb +63 -63
  29. data/lib/cucumber/formatter/ast_lookup.rb +2 -2
  30. data/lib/cucumber/formatter/backtrace_filter.rb +1 -1
  31. data/lib/cucumber/formatter/console.rb +10 -2
  32. data/lib/cucumber/formatter/console_issues.rb +6 -1
  33. data/lib/cucumber/formatter/duration_extractor.rb +1 -0
  34. data/lib/cucumber/formatter/errors.rb +1 -0
  35. data/lib/cucumber/formatter/fanout.rb +1 -1
  36. data/lib/cucumber/formatter/http_io.rb +6 -1
  37. data/lib/cucumber/formatter/ignore_missing_messages.rb +1 -1
  38. data/lib/cucumber/formatter/io.rb +3 -1
  39. data/lib/cucumber/formatter/json.rb +8 -6
  40. data/lib/cucumber/formatter/junit.rb +6 -3
  41. data/lib/cucumber/formatter/message_builder.rb +3 -2
  42. data/lib/cucumber/formatter/pretty.rb +15 -5
  43. data/lib/cucumber/formatter/progress.rb +1 -0
  44. data/lib/cucumber/formatter/query/hook_by_test_step.rb +1 -0
  45. data/lib/cucumber/formatter/query/test_case_started_by_test_case.rb +2 -0
  46. data/lib/cucumber/formatter/rerun.rb +2 -0
  47. data/lib/cucumber/formatter/summary.rb +1 -0
  48. data/lib/cucumber/formatter/unicode.rb +4 -4
  49. data/lib/cucumber/formatter/usage.rb +3 -3
  50. data/lib/cucumber/gherkin/data_table_parser.rb +1 -0
  51. data/lib/cucumber/gherkin/formatter/ansi_escapes.rb +2 -2
  52. data/lib/cucumber/glue/dsl.rb +4 -9
  53. data/lib/cucumber/glue/hook.rb +2 -1
  54. data/lib/cucumber/glue/invoke_in_world.rb +4 -4
  55. data/lib/cucumber/glue/proto_world.rb +10 -9
  56. data/lib/cucumber/glue/registry_and_more.rb +4 -18
  57. data/lib/cucumber/glue/step_definition.rb +6 -3
  58. data/lib/cucumber/hooks.rb +1 -0
  59. data/lib/cucumber/multiline_argument/data_table/diff_matrices.rb +2 -1
  60. data/lib/cucumber/multiline_argument/data_table.rb +58 -71
  61. data/lib/cucumber/platform.rb +2 -2
  62. data/lib/cucumber/rake/task.rb +10 -7
  63. data/lib/cucumber/rspec/disable_option_parser.rb +6 -3
  64. data/lib/cucumber/running_test_case.rb +1 -0
  65. data/lib/cucumber/runtime/meta_message_builder.rb +106 -0
  66. data/lib/cucumber/runtime/support_code.rb +3 -0
  67. data/lib/cucumber/runtime/user_interface.rb +5 -4
  68. data/lib/cucumber/runtime.rb +21 -37
  69. data/lib/cucumber/step_match.rb +5 -3
  70. data/lib/cucumber/step_match_search.rb +3 -2
  71. data/lib/cucumber/term/ansicolor.rb +74 -50
  72. data/lib/cucumber/term/banner.rb +1 -0
  73. data/lib/cucumber/version +1 -1
  74. data/lib/cucumber.rb +2 -1
  75. data/lib/simplecov_setup.rb +1 -1
  76. metadata +74 -73
@@ -3,21 +3,48 @@
3
3
  require 'cucumber/platform'
4
4
  require 'cucumber/term/ansicolor'
5
5
 
6
- Cucumber::Term::ANSIColor.coloring = false if !STDOUT.tty? && !ENV.key?('AUTOTEST')
6
+ Cucumber::Term::ANSIColor.coloring = false if !$stdout.tty? && !ENV.key?('AUTOTEST')
7
7
 
8
8
  module Cucumber
9
9
  module Formatter
10
- # Defines aliases for coloured output. You don't invoke any methods from this
11
- # module directly, but you can change the output colours by defining
12
- # a <tt>CUCUMBER_COLORS</tt> variable in your shell, very much like how you can
13
- # tweak the familiar POSIX command <tt>ls</tt> with
14
- # <a href="http://mipsisrisc.com/rambling/2008/06/27/lscolorsls_colors-now-with-linux-support/">$LSCOLORS/$LS_COLORS</a>
10
+ # This module allows to format cucumber related outputs using ANSI escape sequences.
11
+ #
12
+ # For example, it provides a `passed` method which returns the string with
13
+ # the ANSI escape sequence to format it green per default.
14
+ #
15
+ # To use this, include or extend it in your class.
16
+ #
17
+ # Example:
18
+ #
19
+ # require 'cucumber/formatter/ansicolor'
20
+ #
21
+ # class MyFormatter
22
+ # extend Cucumber::Term::ANSIColor
23
+ #
24
+ # def on_test_step_finished(event)
25
+ # $stdout.puts undefined(event.test_step) if event.result.undefined?
26
+ # $stdout.puts passed(event.test_step) if event.result.passed?
27
+ # end
28
+ # end
29
+ #
30
+ # This module also allows the user to customize the format of cucumber outputs
31
+ # using environment variables.
32
+ #
33
+ # For instance, if your shell has a black background and a green font (like the
34
+ # "Homebrew" settings for OS X' Terminal.app), you may want to override passed
35
+ # steps to be white instead of green.
36
+ #
37
+ # Example:
38
+ #
39
+ # export CUCUMBER_COLORS="passed=white,bold:passed_param=white,bold,underline"
15
40
  #
16
41
  # The colours that you can change are:
17
42
  #
18
43
  # * <tt>undefined</tt> - defaults to <tt>yellow</tt>
19
44
  # * <tt>pending</tt> - defaults to <tt>yellow</tt>
20
45
  # * <tt>pending_param</tt> - defaults to <tt>yellow,bold</tt>
46
+ # * <tt>flaky</tt> - defaults to <tt>yellow</tt>
47
+ # * <tt>flaky_param</tt> - defaults to <tt>yellow,bold</tt>
21
48
  # * <tt>failed</tt> - defaults to <tt>red</tt>
22
49
  # * <tt>failed_param</tt> - defaults to <tt>red,bold</tt>
23
50
  # * <tt>passed</tt> - defaults to <tt>green</tt>
@@ -29,26 +56,18 @@ module Cucumber
29
56
  # * <tt>comment</tt> - defaults to <tt>grey</tt>
30
57
  # * <tt>tag</tt> - defaults to <tt>cyan</tt>
31
58
  #
32
- # For instance, if your shell has a black background and a green font (like the
33
- # "Homebrew" settings for OS X' Terminal.app), you may want to override passed
34
- # steps to be white instead of green.
35
- #
36
- # Although not listed, you can also use <tt>grey</tt>.
37
- #
38
- # Examples: (On Windows, use SET instead of export.)
39
- #
40
- # export CUCUMBER_COLORS="passed=white"
41
- # export CUCUMBER_COLORS="passed=white,bold:passed_param=white,bold,underline"
42
- #
43
59
  # To see what colours and effects are available, just run this in your shell:
44
60
  #
45
- # ruby -e "require 'rubygems'; require 'term/ansicolor'; puts Cucumber::Term::ANSIColor.attributes"
61
+ # ruby -e "require 'rubygems'; require 'cucumber/term/ansicolor'; puts Cucumber::Term::ANSIColor.attributes"
46
62
  #
47
63
  module ANSIColor
48
64
  include Cucumber::Term::ANSIColor
49
65
 
66
+ # :stopdoc:
50
67
  ALIASES = Hash.new do |h, k|
51
- h[Regexp.last_match(1)] + ',bold' if k.to_s =~ /(.*)_param/
68
+ next unless k.to_s =~ /(.*)_param/
69
+
70
+ "#{h[Regexp.last_match(1)]},bold"
52
71
  end.merge(
53
72
  'undefined' => 'yellow',
54
73
  'pending' => 'yellow',
@@ -60,15 +79,22 @@ module Cucumber
60
79
  'comment' => 'grey',
61
80
  'tag' => 'cyan'
62
81
  )
82
+ # :startdoc:
63
83
 
64
- if ENV['CUCUMBER_COLORS'] # Example: export CUCUMBER_COLORS="passed=red:failed=yellow"
65
- ENV['CUCUMBER_COLORS'].split(':').each do |pair|
84
+ # Apply the custom color scheme
85
+ #
86
+ # example:
87
+ #
88
+ # apply_custom_colors('passed=white')
89
+ def apply_custom_colors(colors)
90
+ colors.split(':').each do |pair|
66
91
  a = pair.split('=')
67
92
  ALIASES[a[0]] = a[1]
68
93
  end
69
94
  end
95
+ apply_custom_colors(ENV['CUCUMBER_COLORS']) if ENV['CUCUMBER_COLORS']
70
96
 
71
- # Eval to define the color-named methods required by Term::ANSIColor.
97
+ # Define the color-named methods required by Term::ANSIColor.
72
98
  #
73
99
  # Examples:
74
100
  #
@@ -80,53 +106,18 @@ module Cucumber
80
106
  # red(bold(string, &proc)) + red
81
107
  # end
82
108
  ALIASES.each_key do |method_name|
83
- next if method_name =~ /.*_param/
84
- code = <<-COLOR
85
- def #{method_name}(string=nil, &proc)
86
- #{ALIASES[method_name].split(',').join('(') + '(string, &proc' + ')' * ALIASES[method_name].split(',').length}
87
- end
88
- # This resets the colour to the non-param colour
89
- def #{method_name}_param(string=nil, &proc)
90
- #{ALIASES[method_name + '_param'].split(',').join('(') + '(string, &proc' + ')' * ALIASES[method_name + '_param'].split(',').length} + #{ALIASES[method_name].split(',').join(' + ')}
91
- end
92
- COLOR
93
- eval(code) # rubocop:disable Security/Eval
94
- end
109
+ next if method_name.end_with?('_param')
95
110
 
96
- def self.define_grey #:nodoc:
97
- gem 'genki-ruby-terminfo'
98
- require 'terminfo'
99
- case TermInfo.default_object.tigetnum('colors')
100
- when 0
101
- raise "Your terminal doesn't support colours."
102
- when 1
103
- ::Cucumber::Term::ANSIColor.coloring = false
104
- alias_method :grey, :white
105
- when 2..8
106
- alias_method :grey, :white # rubocop:disable Lint/DuplicateMethods
107
- else
108
- define_real_grey
109
- end
110
- rescue Exception => e # rubocop:disable Lint/RescueException
111
- if e.class.name == 'TermInfo::TermInfoError'
112
- STDERR.puts '*** WARNING ***'
113
- STDERR.puts "You have the genki-ruby-terminfo gem installed, but you haven't set your TERM variable."
114
- STDERR.puts 'Try setting it to TERM=xterm-256color to get grey colour in output.'
115
- STDERR.puts "\n"
116
- alias_method :grey, :white
117
- else
118
- define_real_grey
111
+ define_method(method_name) do |text = nil, &proc|
112
+ apply_styles(ALIASES[method_name], text, &proc)
119
113
  end
120
- end
121
114
 
122
- def self.define_real_grey #:nodoc:
123
- define_method :grey do |string|
124
- ::Cucumber::Term::ANSIColor.coloring? ? "\e[90m#{string}\e[0m" : string
115
+ define_method("#{method_name}_param") do |text = nil, &proc|
116
+ apply_styles(ALIASES["#{method_name}_param"], text, &proc) + apply_styles(ALIASES[method_name])
125
117
  end
126
118
  end
127
119
 
128
- define_grey
129
-
120
+ # :stopdoc:
130
121
  def cukes(n)
131
122
  ('(::) ' * n).strip
132
123
  end
@@ -142,6 +133,15 @@ module Cucumber
142
133
  def yellow_cukes(n)
143
134
  blink(yellow(cukes(n)))
144
135
  end
136
+ # :startdoc:
137
+
138
+ private
139
+
140
+ def apply_styles(styles, text = nil, &proc)
141
+ styles.split(',').reverse.reduce(text) do |result, method_name|
142
+ send(method_name, result, &proc)
143
+ end
144
+ end
145
145
  end
146
146
  end
147
147
  end
@@ -45,11 +45,11 @@ module Cucumber
45
45
  break
46
46
  end
47
47
  break if node.previous_node.nil?
48
+
48
49
  node = node.previous_node
49
50
  end
50
51
  keyword = dialect.given_keywords.reject { |kw| kw == '* ' }[0] if keyword.nil?
51
- keyword = Cucumber::Gherkin::I18n.code_keyword_for(keyword)
52
- keyword
52
+ Cucumber::Gherkin::I18n.code_keyword_for(keyword)
53
53
  end
54
54
 
55
55
  ScenarioSource = Struct.new(:type, :scenario)
@@ -33,7 +33,7 @@ module Cucumber
33
33
  def exception
34
34
  return @exception if ::Cucumber.use_full_backtrace
35
35
 
36
- pwd_pattern = /#{::Regexp.escape(::Dir.pwd)}\//m # rubocop:disable Style/RegexpLiteral
36
+ pwd_pattern = /#{::Regexp.escape(::Dir.pwd)}\//m
37
37
  backtrace = @exception.backtrace.map { |line| line.gsub(pwd_pattern, './') }
38
38
 
39
39
  filtered = (backtrace || []).reject do |line|
@@ -34,7 +34,7 @@ module Cucumber
34
34
 
35
35
  def format_step(keyword, step_match, status, source_indent)
36
36
  comment = if source_indent
37
- c = indent(('# ' + step_match.location.to_s), source_indent)
37
+ c = indent("# #{step_match.location}", source_indent)
38
38
  format_string(c, :comment)
39
39
  else
40
40
  ''
@@ -109,7 +109,10 @@ module Cucumber
109
109
  # http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/10655
110
110
  def linebreaks(msg, max)
111
111
  return msg unless max && max > 0
112
- msg.gsub(/.{1,#{max}}(?:\s|\Z)/) { ($& + 5.chr).gsub(/\n\005/, "\n").gsub(/\005/, "\n") }.rstrip
112
+
113
+ msg.gsub(/.{1,#{max}}(?:\s|\Z)/) do
114
+ (Regexp.last_match(0) + 5.chr).gsub(/\n\005/, "\n").gsub(/\005/, "\n")
115
+ end.rstrip
113
116
  end
114
117
 
115
118
  def collect_snippet_data(test_step, ast_lookup)
@@ -150,6 +153,7 @@ module Cucumber
150
153
 
151
154
  def print_passing_wip(config, passed_test_cases, ast_lookup)
152
155
  return unless config.wip?
156
+
153
157
  messages = passed_test_cases.map do |test_case|
154
158
  scenario_source = ast_lookup.scenario_source(test_case)
155
159
  keyword = scenario_source.type == :Scenario ? scenario_source.scenario.keyword : scenario_source.scenario_outline.keyword
@@ -170,6 +174,7 @@ module Cucumber
170
174
  def attach(src, media_type)
171
175
  return unless media_type == 'text/x.cucumber.log+plain'
172
176
  return unless @io
177
+
173
178
  @io.puts
174
179
  @io.puts(format_string(src, :tag))
175
180
  @io.flush
@@ -177,6 +182,7 @@ module Cucumber
177
182
 
178
183
  def print_profile_information
179
184
  return if @options[:skip_profile_information] || @options[:profiles].nil? || @options[:profiles].empty?
185
+
180
186
  do_print_profile_information(@options[:profiles])
181
187
  end
182
188
 
@@ -224,6 +230,7 @@ module Cucumber
224
230
  key = keys.join('_').to_sym
225
231
  fmt = FORMATS[key]
226
232
  raise "No format for #{key.inspect}: #{FORMATS.inspect}" if fmt.nil?
233
+
227
234
  fmt
228
235
  end
229
236
 
@@ -246,6 +253,7 @@ module Cucumber
246
253
 
247
254
  class SnippetData
248
255
  attr_reader :actual_keyword, :step
256
+
249
257
  def initialize(actual_keyword, step)
250
258
  @actual_keyword = actual_keyword
251
259
  @step = step
@@ -23,6 +23,7 @@ module Cucumber
23
23
 
24
24
  def to_s
25
25
  return if @issues.empty?
26
+
26
27
  result = Core::Test::Result::TYPES.map { |type| scenario_listing(type, @issues[type]) }
27
28
  result.flatten.join("\n")
28
29
  end
@@ -35,6 +36,7 @@ module Cucumber
35
36
 
36
37
  def scenario_listing(type, test_cases)
37
38
  return [] if test_cases.empty?
39
+
38
40
  [format_string("#{type_heading(type)} Scenarios:", type)] + test_cases.map do |test_case|
39
41
  scenario_source = @ast_lookup.scenario_source(test_case)
40
42
  keyword = scenario_source.type == :Scenario ? scenario_source.scenario.keyword : scenario_source.scenario_outline.keyword
@@ -54,7 +56,10 @@ module Cucumber
54
56
 
55
57
  def profiles_string
56
58
  return if @config.custom_profiles.empty?
57
- @config.custom_profiles.map { |profile| "-p #{profile}" }.join(' ') + ' '
59
+
60
+ profiles = @config.custom_profiles.map { |profile| "-p #{profile}" }.join(' ')
61
+
62
+ "#{profiles} "
58
63
  end
59
64
  end
60
65
  end
@@ -4,6 +4,7 @@ module Cucumber
4
4
  module Formatter
5
5
  class DurationExtractor
6
6
  attr_reader :result_duration
7
+
7
8
  def initialize(result)
8
9
  @result_duration = 0
9
10
  result.describe_to(self)
@@ -1,6 +1,7 @@
1
1
  module Cucumber
2
2
  module Formatter
3
3
  class TestCaseUnknownError < StandardError; end
4
+
4
5
  class TestStepUnknownError < StandardError; end
5
6
  end
6
7
  end
@@ -21,7 +21,7 @@ module Cucumber
21
21
  end
22
22
 
23
23
  def respond_to_missing?(name, include_private = false)
24
- recipients.any? { |recipient| recipient.respond_to?(name, include_private) }
24
+ recipients.any? { |recipient| recipient.respond_to?(name, include_private) } || super(name, include_private)
25
25
  end
26
26
  end
27
27
  end
@@ -35,6 +35,7 @@ module Cucumber
35
35
  headers = headers.merge(parse_header(header_arg))
36
36
  else
37
37
  raise StandardError, "#{options} was not a valid curl command. Can't set url to #{arg} it is already set to #{url}" if url
38
+
38
39
  url = arg
39
40
  end
40
41
  end
@@ -49,12 +50,14 @@ module Cucumber
49
50
 
50
51
  def self.remove_arg_for(args, arg)
51
52
  return args.shift unless args.empty?
53
+
52
54
  raise StandardError, "Missing argument for #{arg}"
53
55
  end
54
56
 
55
57
  def self.parse_header(header_arg)
56
58
  parts = header_arg.split(':', 2)
57
59
  raise StandardError, "#{header_arg} was not a valid header" unless parts.length == 2
60
+
58
61
  { parts[0].strip => parts[1].strip }
59
62
  end
60
63
  end
@@ -76,6 +79,7 @@ module Cucumber
76
79
  @reporter.report(response.body)
77
80
  @write_io.close
78
81
  return if response.is_a?(Net::HTTPSuccess) || response.is_a?(Net::HTTPRedirection)
82
+
79
83
  raise StandardError, "request to #{uri} failed with status #{response.code}"
80
84
  end
81
85
 
@@ -98,6 +102,7 @@ module Cucumber
98
102
  http = build_client(uri, @https_verify_mode)
99
103
 
100
104
  raise StandardError, "request to #{uri} failed (too many redirections)" if attempt <= 0
105
+
101
106
  req = build_request(
102
107
  uri,
103
108
  method,
@@ -126,7 +131,7 @@ module Cucumber
126
131
  end
127
132
 
128
133
  def build_request(uri, method, headers)
129
- method_class_name = "#{method[0].upcase}#{method[1..-1].downcase}"
134
+ method_class_name = "#{method[0].upcase}#{method[1..].downcase}"
130
135
  req = Net::HTTP.const_get(method_class_name).new(uri)
131
136
  headers.each do |header, value|
132
137
  req[header] = value
@@ -12,7 +12,7 @@ module Cucumber
12
12
  end
13
13
 
14
14
  def respond_to_missing?(name, include_private = false)
15
- @receiver.respond_to?(name, include_private)
15
+ @receiver.respond_to?(name, include_private) || super(name, include_private)
16
16
  end
17
17
  end
18
18
  end
@@ -57,19 +57,21 @@ module Cucumber
57
57
  end
58
58
 
59
59
  def url?(path_or_url_or_io)
60
- path_or_url_or_io.match(%r{^https?://})
60
+ path_or_url_or_io.match(/^https?:\/\//)
61
61
  end
62
62
 
63
63
  def ensure_file(path, name)
64
64
  raise "You *must* specify --out FILE for the #{name} formatter" unless String == path.class
65
65
  raise "I can't write #{name} to a directory - it has to be a file" if File.directory?(path)
66
66
  raise "I can't write #{name} to a file in the non-existing directory #{File.dirname(path)}" unless File.directory?(File.dirname(path))
67
+
67
68
  ensure_io(path, nil)
68
69
  end
69
70
 
70
71
  def ensure_dir(path, name)
71
72
  raise "You *must* specify --out DIR for the #{name} formatter" unless String == path.class
72
73
  raise "I can't write #{name} reports to a file - it has to be a directory" if File.file?(path)
74
+
73
75
  FileUtils.mkdir_p(path) unless File.directory?(path)
74
76
  File.absolute_path path
75
77
  end
@@ -68,6 +68,7 @@ module Cucumber
68
68
  test_step, result = *event.attributes
69
69
  result = result.with_filtered_backtrace(Cucumber::Formatter::BacktraceFilter)
70
70
  return if internal_hook?(test_step)
71
+
71
72
  add_match_and_result(test_step, result)
72
73
  @any_step_failed = true if result.failed?
73
74
  end
@@ -81,7 +82,7 @@ module Cucumber
81
82
  end
82
83
 
83
84
  def on_test_run_finished(_event)
84
- @io.write(JSON.generate(@feature_hashes, pretty: true))
85
+ @io.write(JSON.pretty_generate(@feature_hashes))
85
86
  end
86
87
 
87
88
  def attach(src, mime_type)
@@ -105,7 +106,7 @@ module Cucumber
105
106
  end
106
107
 
107
108
  def first_step_after_background?(test_step)
108
- @in_background && test_step.location.lines.max >= @test_case_hash[:line]
109
+ @in_background && test_step.location.file == @feature_hash[:uri] && test_step.location.lines.max >= @test_case_hash[:line]
109
110
  end
110
111
 
111
112
  def internal_hook?(test_step)
@@ -133,7 +134,7 @@ module Cucumber
133
134
  when 'AfterStep hook'
134
135
  after_step_hooks
135
136
  else
136
- raise 'Unknown hook type ' + hook_step.to_s
137
+ raise "Unknown hook type #{hook_step}"
137
138
  end
138
139
  end
139
140
 
@@ -175,15 +176,15 @@ module Cucumber
175
176
  name: test_step.text,
176
177
  line: test_step.location.lines.min
177
178
  }
178
- step_hash[:doc_string] = create_doc_string_hash(step_source.doc_string) unless step_source.doc_string.nil?
179
+ step_hash[:doc_string] = create_doc_string_hash(step_source.doc_string, test_step.multiline_arg.content) unless step_source.doc_string.nil?
179
180
  step_hash[:rows] = create_data_table_value(step_source.data_table) unless step_source.data_table.nil?
180
181
  step_hash
181
182
  end
182
183
 
183
- def create_doc_string_hash(doc_string)
184
+ def create_doc_string_hash(doc_string, doc_string_content)
184
185
  content_type = doc_string.media_type || ''
185
186
  {
186
- value: doc_string.content,
187
+ value: doc_string_content,
187
188
  content_type: content_type,
188
189
  line: doc_string.location.line
189
190
  }
@@ -259,6 +260,7 @@ module Cucumber
259
260
  line: feature.location.line
260
261
  }
261
262
  return if feature.tags.empty?
263
+
262
264
  @feature_hash[:tags] = create_tags_array_from_hash_array(feature.tags)
263
265
  end
264
266
 
@@ -84,6 +84,7 @@ module Cucumber
84
84
  uri = test_case.location.file
85
85
  feature = @ast_lookup.gherkin_document(uri).feature
86
86
  raise UnNamedFeatureError, uri if feature.name.empty?
87
+
87
88
  @current_feature_data = @features_data[uri]
88
89
  @current_feature_data[:uri] = uri unless @current_feature_data[:uri]
89
90
  @current_feature_data[:feature] = feature unless @current_feature_data[:feature]
@@ -111,6 +112,7 @@ module Cucumber
111
112
  keyword = scenario_source.type == :Scenario ? scenario_source.scenario.keyword : scenario_source.scenario_outline.keyword
112
113
  output = "#{keyword}: #{scenario}\n\n"
113
114
  return output if result.ok?(@config.strict)
115
+
114
116
  if scenario_source.type == :Scenario
115
117
  if @failing_test_step
116
118
  if @failing_test_step.hook?
@@ -125,7 +127,7 @@ module Cucumber
125
127
  else
126
128
  output += "Example row: #{row_name}\n"
127
129
  end
128
- output + "\nMessage:\n"
130
+ "#{output}\nMessage:\n"
129
131
  end
130
132
 
131
133
  def build_testcase(result, scenario_designation, output)
@@ -191,7 +193,7 @@ module Cucumber
191
193
  end
192
194
 
193
195
  def basename(feature_file)
194
- File.basename(feature_file.gsub(/[\\\/]/, '-'), '.feature') # rubocop:disable Style/RegexpLiteral
196
+ File.basename(feature_file.gsub(/[\\\/]/, '-'), '.feature')
195
197
  end
196
198
 
197
199
  def write_file(feature_filename, data)
@@ -228,13 +230,14 @@ module Cucumber
228
230
  end
229
231
 
230
232
  def examples_table_row(row)
231
- @row_name = '| ' + row.cells.map(&:value).join(' | ') + ' |'
233
+ @row_name = "| #{row.cells.map(&:value).join(' | ')} |"
232
234
  @name_suffix = " (outline example : #{@row_name})"
233
235
  end
234
236
  end
235
237
 
236
238
  class ResultBuilder
237
239
  attr_reader :test_case_duration
240
+
238
241
  def initialize(result)
239
242
  @test_case_duration = 0
240
243
  result.describe_to(self)
@@ -226,10 +226,11 @@ module Cucumber
226
226
  output_envelope(message)
227
227
  end
228
228
 
229
- def on_test_run_finished(*)
229
+ def on_test_run_finished(event)
230
230
  message = Cucumber::Messages::Envelope.new(
231
231
  test_run_finished: Cucumber::Messages::TestRunFinished.new(
232
- timestamp: time_to_timestamp(Time.now)
232
+ timestamp: time_to_timestamp(Time.now),
233
+ success: event.success
233
234
  )
234
235
  )
235
236
 
@@ -24,11 +24,9 @@ module Cucumber
24
24
  include Console
25
25
  include Io
26
26
  include Cucumber::Gherkin::Formatter::Escaping
27
- attr_reader :config, :options
27
+ attr_reader :config, :options, :current_feature_uri, :current_scenario_outline, :current_examples, :current_test_case, :in_scenario_outline, :print_background_steps
28
28
  private :config, :options
29
- attr_reader :current_feature_uri, :current_scenario_outline, :current_examples, :current_test_case
30
29
  private :current_feature_uri, :current_scenario_outline, :current_examples, :current_test_case
31
- attr_reader :in_scenario_outline, :print_background_steps
32
30
  private :in_scenario_outline, :print_background_steps
33
31
 
34
32
  def initialize(config)
@@ -105,16 +103,19 @@ module Cucumber
105
103
 
106
104
  def on_test_step_started(event)
107
105
  return if event.test_step.hook?
106
+
108
107
  print_step_header(current_test_case) if first_step_after_printing_background_steps?(event.test_step)
109
108
  end
110
109
 
111
110
  def on_test_step_finished(event)
112
111
  collect_snippet_data(event.test_step, @ast_lookup) if event.result.undefined?
113
112
  return if in_scenario_outline && !options[:expand]
113
+
114
114
  exception_to_be_printed = find_exception_to_be_printed(event.result)
115
115
  print_step_data(event.test_step, event.result) if print_step_data?(event, exception_to_be_printed)
116
116
  print_step_output
117
117
  return unless exception_to_be_printed
118
+
118
119
  print_exception(exception_to_be_printed, event.result.to_sym, 6)
119
120
  @exceptions << exception_to_be_printed
120
121
  end
@@ -127,6 +128,7 @@ module Cucumber
127
128
  else
128
129
  exception_to_be_printed = find_exception_to_be_printed(event.result)
129
130
  return unless exception_to_be_printed
131
+
130
132
  print_exception(exception_to_be_printed, event.result.to_sym, 6)
131
133
  @exceptions << exception_to_be_printed
132
134
  end
@@ -140,6 +142,7 @@ module Cucumber
140
142
 
141
143
  def attach(src, media_type)
142
144
  return unless media_type == 'text/x.cucumber.log+plain'
145
+
143
146
  @test_step_output.push src
144
147
  end
145
148
 
@@ -147,9 +150,11 @@ module Cucumber
147
150
 
148
151
  def find_exception_to_be_printed(result)
149
152
  return nil if result.ok?(options[:strict])
153
+
150
154
  result = result.with_filtered_backtrace(Cucumber::Formatter::BacktraceFilter)
151
155
  exception = result.failed? ? result.exception : result
152
156
  return nil if @exceptions.include?(exception)
157
+
153
158
  exception
154
159
  end
155
160
 
@@ -196,6 +201,7 @@ module Cucumber
196
201
  def feature_has_background?
197
202
  feature_children = gherkin_document.feature.children
198
203
  return false if feature_children.empty?
204
+
199
205
  !feature_children.first.background.nil?
200
206
  end
201
207
 
@@ -239,6 +245,7 @@ module Cucumber
239
245
  def first_step_after_printing_background_steps?(test_step)
240
246
  return false unless print_background_steps
241
247
  return false unless test_step.location.lines.max >= current_test_case.location.lines.max
248
+
242
249
  @print_background_steps = false
243
250
  true
244
251
  end
@@ -262,7 +269,8 @@ module Cucumber
262
269
  def print_comments(up_to_line, indent_amount)
263
270
  comments = gherkin_document.comments
264
271
  return if comments.empty? || comments.length <= @next_comment_to_be_printed
265
- comments[@next_comment_to_be_printed..-1].each do |comment|
272
+
273
+ comments[@next_comment_to_be_printed..].each do |comment|
266
274
  if comment.location.line <= up_to_line
267
275
  @io.puts(indent(format_string(comment.text.strip, :comment), indent_amount))
268
276
  @next_comment_to_be_printed += 1
@@ -294,6 +302,7 @@ module Cucumber
294
302
 
295
303
  def print_description(description)
296
304
  return unless description
305
+
297
306
  description.split("\n").each do |line|
298
307
  @io.puts(line)
299
308
  end
@@ -398,6 +407,7 @@ module Cucumber
398
407
  end
399
408
  @io.puts
400
409
  next if options[:no_multiline]
410
+
401
411
  print_doc_string(step.doc_string.content, :skipped, 6) unless step.doc_string.nil?
402
412
  print_data_table(step.data_table, :skipped, 6) unless step.data_table.nil?
403
413
  end
@@ -445,7 +455,7 @@ module Cucumber
445
455
  language = ::Gherkin::Dialect.for(language_code)
446
456
  scenario_keyword = language.scenario_keywords[0]
447
457
  row = scenario_source(test_case).row
448
- expanded_name = '| ' + row.cells.map(&:value).join(' | ') + ' |'
458
+ expanded_name = "| #{row.cells.map(&:value).join(' | ')} |"
449
459
  @source_indent = calculate_source_indent_for_expanded_test_case(test_case, scenario_keyword, expanded_name)
450
460
  @io.puts
451
461
  print_keyword_name(scenario_keyword, expanded_name, 6, test_case.location)
@@ -58,6 +58,7 @@ module Cucumber
58
58
  progress(result.to_sym) if !test_step.hook? || result.failed?
59
59
 
60
60
  return if test_step.hook?
61
+
61
62
  collect_snippet_data(test_step, @ast_lookup) if result.undefined?
62
63
  @pending_step_matches << @matches[test_step.to_s] if result.pending?
63
64
  @failed_results << result if result.failed?
@@ -13,6 +13,7 @@ module Cucumber
13
13
 
14
14
  def hook_id(test_step)
15
15
  return @hook_id_by_test_step_id[test_step.id] if @hook_id_by_test_step_id.key?(test_step.id)
16
+
16
17
  raise TestStepUnknownError, "No hook found for #{test_step.id} }. Known: #{@hook_id_by_test_step_id.keys}"
17
18
  end
18
19