cucumber 4.0.0.rc.5 → 5.0.0

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.
@@ -5,21 +5,23 @@ module Cucumber
5
5
  module Interceptor
6
6
  class Pipe
7
7
  attr_reader :pipe
8
+
8
9
  def initialize(pipe)
9
10
  @pipe = pipe
10
11
  @buffer = StringIO.new
11
12
  @wrapped = true
13
+ @lock = Mutex.new
12
14
  end
13
15
 
14
16
  def write(str)
15
- lock.synchronize do
17
+ @lock.synchronize do
16
18
  @buffer << str if @wrapped
17
19
  return @pipe.write(str)
18
20
  end
19
21
  end
20
22
 
21
23
  def buffer_string
22
- lock.synchronize do
24
+ @lock.synchronize do
23
25
  return @buffer.string.dup
24
26
  end
25
27
  end
@@ -30,7 +32,7 @@ module Cucumber
30
32
  end
31
33
 
32
34
  def method_missing(method, *args, &blk)
33
- @pipe.send(method, *args, &blk) || super
35
+ @pipe.respond_to?(method) ? @pipe.send(method, *args, &blk) : super
34
36
  end
35
37
 
36
38
  def respond_to_missing?(method, include_private = false)
@@ -67,12 +69,6 @@ module Cucumber
67
69
  return $stdout
68
70
  end
69
71
  end
70
-
71
- private
72
-
73
- def lock
74
- @lock ||= Mutex.new
75
- end
76
72
  end
77
73
  end
78
74
  end
@@ -1,6 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'cucumber/formatter/http_io'
4
+ require 'cucumber/formatter/url_reporter'
5
+ require 'cucumber/cli/options'
4
6
 
5
7
  module Cucumber
6
8
  module Formatter
@@ -9,19 +11,53 @@ module Cucumber
9
11
 
10
12
  def ensure_io(path_or_url_or_io)
11
13
  return nil if path_or_url_or_io.nil?
12
- return path_or_url_or_io if path_or_url_or_io.respond_to?(:write)
13
- io = if path_or_url_or_io.match(%r{^https?://})
14
- HTTPIO.open(path_or_url_or_io)
14
+ return path_or_url_or_io if io?(path_or_url_or_io)
15
+
16
+ io = if url?(path_or_url_or_io)
17
+ url = path_or_url_or_io
18
+ reporter = url.start_with?(Cucumber::Cli::Options::CUCUMBER_PUBLISH_URL) ? URLReporter.new($stdout) : NoReporter.new
19
+ HTTPIO.open(url, nil, reporter)
15
20
  else
16
21
  File.open(path_or_url_or_io, Cucumber.file_mode('w'))
17
22
  end
18
- at_exit do
19
- unless io.closed?
20
- io.flush
21
- io.close
23
+ @io_objects_to_close ||= []
24
+ @io_objects_to_close.push(io)
25
+ io
26
+ end
27
+
28
+ module ClassMethods
29
+ def new(*args, &block)
30
+ instance = super
31
+
32
+ config = args[0]
33
+ if config.respond_to? :on_event
34
+ config.on_event :test_run_finished do
35
+ ios = instance.instance_variable_get(:@io_objects_to_close) || []
36
+ ios.each do |io|
37
+ at_exit do
38
+ unless io.closed?
39
+ io.flush
40
+ io.close
41
+ end
42
+ end
43
+ end
44
+ end
22
45
  end
46
+
47
+ instance
23
48
  end
24
- io
49
+ end
50
+
51
+ def self.included(formatter_class)
52
+ formatter_class.extend(ClassMethods)
53
+ end
54
+
55
+ def io?(path_or_url_or_io)
56
+ path_or_url_or_io.respond_to?(:write)
57
+ end
58
+
59
+ def url?(path_or_url_or_io)
60
+ path_or_url_or_io.match(%r{^https?://})
25
61
  end
26
62
 
27
63
  def ensure_file(path, name)
@@ -29,6 +29,7 @@ module Cucumber
29
29
  config.on_event :test_step_finished, &method(:on_test_step_finished)
30
30
  config.on_event :test_case_finished, &method(:on_test_case_finished)
31
31
  config.on_event :test_run_finished, &method(:on_test_run_finished)
32
+ config.on_event :undefined_parameter_type, &method(:on_undefined_parameter_type)
32
33
 
33
34
  @test_case_by_step_id = {}
34
35
  @current_test_case_started_id = nil
@@ -47,11 +48,13 @@ module Cucumber
47
48
  }
48
49
 
49
50
  if media_type.start_with?('text/')
50
- attachment_data[:text] = src
51
- elsif src.respond_to? :read
52
- attachment_data[:binary] = Base64.encode64(src.read)
51
+ attachment_data[:content_encoding] = Cucumber::Messages::Attachment::ContentEncoding::IDENTITY
52
+ attachment_data[:body] = src
53
53
  else
54
- attachment_data[:binary] = Base64.encode64(src)
54
+ body = src.respond_to?(:read) ? src.read : src
55
+
56
+ attachment_data[:content_encoding] = Cucumber::Messages::Attachment::ContentEncoding::BASE64
57
+ attachment_data[:body] = Base64.strict_encode64(body)
55
58
  end
56
59
 
57
60
  message = Cucumber::Messages::Envelope.new(
@@ -124,7 +127,7 @@ module Cucumber
124
127
 
125
128
  def step_match_arguments(step)
126
129
  @step_definitions_by_test_step.step_match_arguments(step).map do |argument|
127
- Cucumber::Messages::StepMatchArgument.new(
130
+ Cucumber::Messages::TestCase::TestStep::StepMatchArgumentsList::StepMatchArgument.new(
128
131
  group: argument_group_to_message(argument.group),
129
132
  parameter_type_name: argument.parameter_type.name
130
133
  )
@@ -132,7 +135,7 @@ module Cucumber
132
135
  end
133
136
 
134
137
  def argument_group_to_message(group)
135
- Cucumber::Messages::StepMatchArgument::Group.new(
138
+ Cucumber::Messages::TestCase::TestStep::StepMatchArgumentsList::StepMatchArgument::Group.new(
136
139
  start: group.start,
137
140
  value: group.value,
138
141
  children: group.children.map { |child| argument_group_to_message(child) }
@@ -187,7 +190,7 @@ module Cucumber
187
190
 
188
191
  result_message = result.to_message
189
192
  if result.failed? || result.pending?
190
- result_message = Cucumber::Messages::TestStepResult.new(
193
+ result_message = Cucumber::Messages::TestStepFinished::TestStepResult.new(
191
194
  status: result_message.status,
192
195
  duration: result_message.duration,
193
196
  message: create_error_message(result)
@@ -233,6 +236,17 @@ module Cucumber
233
236
  output_envelope(message)
234
237
  end
235
238
 
239
+ def on_undefined_parameter_type(event)
240
+ message = Cucumber::Messages::Envelope.new(
241
+ undefined_parameter_type: Cucumber::Messages::UndefinedParameterType.new(
242
+ name: event.type_name,
243
+ expression: event.expression
244
+ )
245
+ )
246
+
247
+ output_envelope(message)
248
+ end
249
+
236
250
  def test_case_started_id(test_case)
237
251
  @test_case_started_by_test_case.test_case_started_id_by_test_case(test_case)
238
252
  end
@@ -36,6 +36,7 @@ module Cucumber
36
36
  @config = config
37
37
  @options = config.to_hash
38
38
  @snippets_input = []
39
+ @undefined_parameter_types = []
39
40
  @total_duration = 0
40
41
  @exceptions = []
41
42
  @gherkin_sources = {}
@@ -54,6 +55,11 @@ module Cucumber
54
55
  @passed_test_cases = []
55
56
  @source_indent = 0
56
57
  @next_comment_to_be_printed = 0
58
+
59
+ bind_events(config)
60
+ end
61
+
62
+ def bind_events(config)
57
63
  config.on_event :gherkin_source_read, &method(:on_gherkin_source_read)
58
64
  config.on_event :step_activated, &method(:on_step_activated)
59
65
  config.on_event :test_case_started, &method(:on_test_case_started)
@@ -61,6 +67,7 @@ module Cucumber
61
67
  config.on_event :test_step_finished, &method(:on_test_step_finished)
62
68
  config.on_event :test_case_finished, &method(:on_test_case_finished)
63
69
  config.on_event :test_run_finished, &method(:on_test_run_finished)
70
+ config.on_event :undefined_parameter_type, &method(:collect_undefined_parameter_type_names)
64
71
  end
65
72
 
66
73
  def on_gherkin_source_read(event)
@@ -21,6 +21,7 @@ module Cucumber
21
21
  @config = config
22
22
  @io = ensure_io(config.out_stream)
23
23
  @snippets_input = []
24
+ @undefined_parameter_types = []
24
25
  @total_duration = 0
25
26
  @matches = {}
26
27
  @pending_step_matches = []
@@ -36,6 +37,7 @@ module Cucumber
36
37
  config.on_event :test_step_finished, &method(:on_test_step_finished)
37
38
  config.on_event :test_case_finished, &method(:on_test_case_finished)
38
39
  config.on_event :test_run_finished, &method(:on_test_run_finished)
40
+ config.on_event :undefined_parameter_type, &method(:collect_undefined_parameter_type_names)
39
41
  end
40
42
 
41
43
  def on_step_activated(event)
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'cucumber/term/banner'
4
+
5
+ module Cucumber
6
+ module Formatter
7
+ class PublishBannerPrinter
8
+ include Term::Banner
9
+
10
+ def initialize(configuration)
11
+ return if configuration.publish_enabled?
12
+
13
+ configuration.on_event :test_run_finished do |_event|
14
+ display_publish_ad(configuration.error_stream)
15
+ end
16
+ end
17
+
18
+ # rubocop:disable Metrics/MethodLength
19
+ def display_publish_ad(io)
20
+ display_banner(
21
+ [
22
+ [
23
+ 'Share your Cucumber Report with your team at ',
24
+ link('https://reports.cucumber.io')
25
+ ],
26
+ '',
27
+ [
28
+ 'Command line option: ',
29
+ highlight('--publish')
30
+ ],
31
+ [
32
+ 'Environment variable: ',
33
+ highlight('CUCUMBER_PUBLISH_ENABLED=true')
34
+ ],
35
+ [
36
+ 'cucumber.yml: ',
37
+ highlight('default: --publish')
38
+ ],
39
+ '',
40
+ [
41
+ 'More information at ',
42
+ link('https://reports.cucumber.io/docs/cucumber-ruby')
43
+ ],
44
+ '',
45
+ [
46
+ 'To disable this message, specify ',
47
+ pre('CUCUMBER_PUBLISH_QUIET=true'),
48
+ ' or use the '
49
+ ],
50
+ [
51
+ pre('--publish-quiet'),
52
+ ' option. You can also add this to your ',
53
+ pre('cucumber.yml:')
54
+ ],
55
+ [pre('default: --publish-quiet')]
56
+ ],
57
+ io
58
+ )
59
+ end
60
+ # rubocop:enable Metrics/MethodLength
61
+
62
+ def highlight(text)
63
+ [text, :cyan]
64
+ end
65
+
66
+ def link(text)
67
+ [text, :cyan, :bold, :underline]
68
+ end
69
+
70
+ def pre(text)
71
+ [text, :bold]
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,30 @@
1
+ require 'cucumber/term/banner'
2
+
3
+ module Cucumber
4
+ module Formatter
5
+ class URLReporter
6
+ include Term::Banner
7
+
8
+ def initialize(io)
9
+ @io = io
10
+ end
11
+
12
+ def report(url)
13
+ uri = URI(url)
14
+ display_banner(
15
+ [
16
+ 'View your Cucumber Report at:',
17
+ [["https://reports.cucumber.io#{uri.path}", :cyan, :bold, :underline]],
18
+ '',
19
+ [['This report will self-destruct in 24h unless it is claimed or deleted.', :green, :bold]]
20
+ ],
21
+ @io
22
+ )
23
+ end
24
+ end
25
+
26
+ class NoReporter
27
+ def report(url); end
28
+ end
29
+ end
30
+ end
@@ -107,9 +107,8 @@ module Cucumber
107
107
  attach(file, mime_type)
108
108
  end
109
109
 
110
- def log(message)
111
- raise Cucumber::LogTypeInvalid unless message.is_a?(String)
112
- attach(message.dup, 'text/x.cucumber.log+plain')
110
+ def log(*messages)
111
+ messages.each { |message| attach(message.to_s.dup, 'text/x.cucumber.log+plain') }
113
112
  end
114
113
 
115
114
  def attach(file, media_type)
@@ -93,12 +93,7 @@ module Cucumber
93
93
  # TODO: add a way to extract the parameter type directly from the error.
94
94
  type_name = e.message.match(/^Undefined parameter type \{(.*)\}$/)[1]
95
95
 
96
- @configuration.notify :envelope, Cucumber::Messages::Envelope.new(
97
- undefined_parameter_type: Cucumber::Messages::UndefinedParameterType.new(
98
- name: type_name,
99
- expression: string_or_regexp
100
- )
101
- )
96
+ @configuration.notify :undefined_parameter_type, type_name, string_or_regexp
102
97
  end
103
98
 
104
99
  def build_rb_world_factory(world_modules, namespaced_world_modules, proc)
@@ -192,6 +187,7 @@ module Cucumber
192
187
 
193
188
  Cucumber::Messages::Envelope.new(
194
189
  parameter_type: Cucumber::Messages::ParameterType.new(
190
+ id: @configuration.id_generator.new_id,
195
191
  name: parameter_type.name,
196
192
  regular_expressions: parameter_type.regexps.map(&:to_s),
197
193
  prefer_for_regular_expression_match: parameter_type.prefer_for_regexp_match?,
@@ -174,7 +174,7 @@ module Cucumber
174
174
 
175
175
  class DocString
176
176
  def append_block_parameter_to(array)
177
- array << 'string'
177
+ array << 'doc_string'
178
178
  end
179
179
 
180
180
  def append_comment_to(string); end
@@ -77,7 +77,7 @@ module Cucumber
77
77
  Cucumber::Messages::Envelope.new(
78
78
  step_definition: Cucumber::Messages::StepDefinition.new(
79
79
  id: id,
80
- pattern: Cucumber::Messages::StepDefinitionPattern.new(
80
+ pattern: Cucumber::Messages::StepDefinition::StepDefinitionPattern.new(
81
81
  source: expression.source.to_s,
82
82
  type: expression_type
83
83
  ),
@@ -92,8 +92,8 @@ module Cucumber
92
92
  end
93
93
 
94
94
  def expression_type
95
- return Cucumber::Messages::StepDefinitionPatternType::CUCUMBER_EXPRESSION if expression.is_a?(CucumberExpressions::CucumberExpression)
96
- Cucumber::Messages::StepDefinitionPatternType::REGULAR_EXPRESSION
95
+ return Cucumber::Messages::StepDefinition::StepDefinitionPattern::StepDefinitionPatternType::CUCUMBER_EXPRESSION if expression.is_a?(CucumberExpressions::CucumberExpression)
96
+ Cucumber::Messages::StepDefinition::StepDefinitionPattern::StepDefinitionPatternType::REGULAR_EXPRESSION
97
97
  end
98
98
 
99
99
  # @api private
@@ -95,7 +95,7 @@ module Cucumber
95
95
  def changes
96
96
  require 'diff/lcs'
97
97
  diffable_cell_matrix = cell_matrix.dup.extend(::Diff::LCS)
98
- diffable_cell_matrix.diff(other_table_cell_matrix).flatten
98
+ diffable_cell_matrix.diff(other_table_cell_matrix).flatten(1)
99
99
  end
100
100
 
101
101
  def inspect_rows(missing_row, inserted_row)
@@ -7,7 +7,7 @@ require 'cucumber/core/platform'
7
7
 
8
8
  module Cucumber
9
9
  unless defined?(Cucumber::VERSION)
10
- VERSION = File.read(File.expand_path('version', __dir__))
10
+ VERSION = File.read(File.expand_path('version', __dir__)).strip
11
11
  BINARY = File.expand_path(File.dirname(__FILE__) + '/../../bin/cucumber')
12
12
  LIBDIR = File.expand_path(File.dirname(__FILE__) + '/../../lib')
13
13
  RAILS = defined?(Rails)
@@ -156,7 +156,7 @@ module Cucumber
156
156
 
157
157
  def runner(_task_args = nil) #:nodoc:
158
158
  cucumber_opts = [(ENV['CUCUMBER_OPTS'] ? ENV['CUCUMBER_OPTS'].split(/\s+/) : nil) || cucumber_opts_with_profile]
159
- return ForkedCucumberRunner.new(libs, binary, cucumber_opts, bundler, feature_files) if @fork
159
+ return ForkedCucumberRunner.new(libs, binary, cucumber_opts, bundler, feature_files) if fork
160
160
  InProcessCucumberRunner.new(libs, cucumber_opts, feature_files)
161
161
  end
162
162
 
@@ -13,9 +13,7 @@ Before do
13
13
  end
14
14
 
15
15
  After do
16
- begin
17
- RSpec::Mocks.verify
18
- ensure
19
- RSpec::Mocks.teardown
20
- end
16
+ RSpec::Mocks.verify
17
+ ensure
18
+ RSpec::Mocks.teardown
21
19
  end
@@ -2,6 +2,7 @@
2
2
 
3
3
  require 'fileutils'
4
4
  require 'cucumber/configuration'
5
+ require 'cucumber/create_meta'
5
6
  require 'cucumber/load_path'
6
7
  require 'cucumber/formatter/duration'
7
8
  require 'cucumber/file_specs'
@@ -9,6 +10,8 @@ require 'cucumber/filters'
9
10
  require 'cucumber/formatter/fanout'
10
11
  require 'cucumber/gherkin/i18n'
11
12
  require 'cucumber/step_match_search'
13
+ require 'cucumber/messages'
14
+ require 'sys/uname'
12
15
 
13
16
  module Cucumber
14
17
  module FixRuby21Bug9285
@@ -62,6 +65,10 @@ module Cucumber
62
65
 
63
66
  require 'cucumber/wire/plugin'
64
67
  def run!
68
+ @configuration.notify :envelope, Cucumber::Messages::Envelope.new(
69
+ meta: Cucumber::CreateMeta.create_meta('cucumber-ruby', Cucumber::VERSION)
70
+ )
71
+
65
72
  load_step_definitions
66
73
  install_wire_plugin
67
74
  fire_after_configuration_hook
@@ -159,11 +166,14 @@ module Cucumber
159
166
 
160
167
  require 'cucumber/formatter/ignore_missing_messages'
161
168
  require 'cucumber/formatter/fail_fast'
169
+ require 'cucumber/formatter/publish_banner_printer'
162
170
  require 'cucumber/core/report/summary'
171
+
163
172
  def report
164
173
  return @report if @report
165
174
  reports = [summary_report] + formatters
166
175
  reports << fail_fast_report if @configuration.fail_fast?
176
+ reports << publish_banner_printer unless @configuration.publish_quiet?
167
177
  @report ||= Formatter::Fanout.new(reports)
168
178
  end
169
179
 
@@ -175,6 +185,10 @@ module Cucumber
175
185
  @fail_fast_report ||= Formatter::FailFast.new(@configuration)
176
186
  end
177
187
 
188
+ def publish_banner_printer
189
+ @publish_banner_printer ||= Formatter::PublishBannerPrinter.new(@configuration)
190
+ end
191
+
178
192
  def formatters
179
193
  @formatters ||=
180
194
  @configuration.formatter_factories do |factory, formatter_options, path_or_io|