cucumber 4.0.0.rc.6 → 5.1.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.
@@ -6,10 +6,12 @@ module Cucumber
6
6
  class HTTPIO
7
7
  class << self
8
8
  # Returns an IO that will write to a HTTP request's body
9
- def open(url, https_verify_mode = nil)
9
+ # https_verify_mode can be set to OpenSSL::SSL::VERIFY_NONE
10
+ # to ignore unsigned certificate - setting to nil will verify the certificate
11
+ def open(url, https_verify_mode = nil, reporter = nil)
10
12
  @https_verify_mode = https_verify_mode
11
13
  uri, method, headers = CurlOptionParser.parse(url)
12
- IOHTTPBuffer.new(uri, method, headers, https_verify_mode)
14
+ IOHTTPBuffer.new(uri, method, headers, https_verify_mode, reporter)
13
15
  end
14
16
  end
15
17
  end
@@ -64,16 +66,19 @@ module Cucumber
64
66
  class IOHTTPBuffer
65
67
  attr_reader :uri, :method, :headers
66
68
 
67
- def initialize(uri, method, headers = {}, https_verify_mode = nil)
69
+ def initialize(uri, method, headers = {}, https_verify_mode = nil, reporter = nil)
68
70
  @uri = URI(uri)
69
71
  @method = method
70
72
  @headers = headers
71
73
  @write_io = Tempfile.new('cucumber', encoding: 'UTF-8')
72
74
  @https_verify_mode = https_verify_mode
75
+ @reporter = reporter || NoReporter.new
73
76
  end
74
77
 
75
78
  def close
76
- post_content(@uri, @method, @headers)
79
+ resource_uri = send_content(@uri, @method, @headers)
80
+
81
+ @reporter.report(resource_uri)
77
82
  @write_io.close
78
83
  end
79
84
 
@@ -91,8 +96,8 @@ module Cucumber
91
96
 
92
97
  private
93
98
 
94
- def post_content(uri, method, headers, attempt = 10)
95
- content = @write_io
99
+ def send_content(uri, method, headers, attempt = 10)
100
+ content = (method == 'GET' ? StringIO.new : @write_io)
96
101
  http = build_client(uri, @https_verify_mode)
97
102
 
98
103
  raise StandardError, "request to #{uri} failed (too many redirections)" if attempt <= 0
@@ -115,10 +120,14 @@ module Cucumber
115
120
  end
116
121
 
117
122
  case response
123
+ when Net::HTTPAccepted
124
+ return uri unless response['Location']
125
+
126
+ send_content(URI(response['Location']), 'PUT', headers, attempt - 1)
118
127
  when Net::HTTPSuccess
119
- response
128
+ uri
120
129
  when Net::HTTPRedirection
121
- post_content(URI(response['Location']), method, headers, attempt - 1)
130
+ send_content(URI(response['Location']), method, headers, attempt - 1)
122
131
  else
123
132
  raise StandardError, "request to #{uri} failed with status #{response.code}"
124
133
  end
@@ -5,6 +5,7 @@ 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
@@ -31,7 +32,7 @@ module Cucumber
31
32
  end
32
33
 
33
34
  def method_missing(method, *args, &blk)
34
- @pipe.send(method, *args, &blk) || super
35
+ @pipe.respond_to?(method) ? @pipe.send(method, *args, &blk) : super
35
36
  end
36
37
 
37
38
  def respond_to_missing?(method, include_private = false)
@@ -62,10 +63,10 @@ module Cucumber
62
63
  case pipe
63
64
  when :stderr
64
65
  $stderr = new($stderr)
65
- return $stderr
66
+ $stderr
66
67
  when :stdout
67
68
  $stdout = new($stdout)
68
- return $stdout
69
+ $stdout
69
70
  end
70
71
  end
71
72
  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($stderr) : 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)
@@ -19,7 +19,7 @@ module Cucumber
19
19
  '--format=json',
20
20
  "Please use --format=message and stand-alone json-formatter.\n" \
21
21
  'json-formatter homepage: https://github.com/cucumber/cucumber/tree/master/json-formatter#cucumber-json-formatter',
22
- '5.0.0'
22
+ '6.0.0'
23
23
  )
24
24
 
25
25
  @io = ensure_io(config.out_stream)
@@ -106,7 +106,7 @@ module Cucumber
106
106
  write_file(feature_result_filename(feature_data[:uri]), @testsuite.target!)
107
107
  end
108
108
 
109
- def create_output_string(test_case, scenario, result, row_name) # rubocop:disable Metrics/PerceivedComplexity
109
+ def create_output_string(test_case, scenario, result, row_name)
110
110
  scenario_source = @ast_lookup.scenario_source(test_case)
111
111
  keyword = scenario_source.type == :Scenario ? scenario_source.scenario.keyword : scenario_source.scenario_outline.keyword
112
112
  output = "#{keyword}: #{scenario}\n\n"
@@ -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
@@ -235,6 +236,17 @@ module Cucumber
235
236
  output_envelope(message)
236
237
  end
237
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
+
238
250
  def test_case_started_id(test_case)
239
251
  @test_case_started_by_test_case.test_case_started_id_by_test_case(test_case)
240
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
@@ -7,7 +7,7 @@ module Cucumber
7
7
  class Rerun
8
8
  include Formatter::Io
9
9
 
10
- def initialize(config) # rubocop:disable Metrics/PerceivedComplexity
10
+ def initialize(config)
11
11
  @io = ensure_io(config.out_stream)
12
12
  @config = config
13
13
  @failures = {}
@@ -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
@@ -87,7 +87,7 @@ module Cucumber
87
87
  'If you simply want it in the console, '\
88
88
  'keep using "puts" (or Kernel.puts to avoid this message)',
89
89
  'puts(message)',
90
- '5.0.0'
90
+ '6.0.0'
91
91
  )
92
92
  messages.each { |message| log(message.to_s) }
93
93
  end
@@ -102,14 +102,13 @@ module Cucumber
102
102
  Cucumber.deprecate(
103
103
  'Please use attach(file, media_type) instead',
104
104
  'embed(file, mime_type, label)',
105
- '5.0.0'
105
+ '6.0.0'
106
106
  )
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)
@@ -144,7 +143,7 @@ module Cucumber
144
143
  end
145
144
 
146
145
  # Dynamially generate the API module, closuring the dependencies
147
- def self.for(runtime, language) # rubocop:disable Metrics/MethodLength
146
+ def self.for(runtime, language) # rubocop:disable Metrics/MethodLength,Metrics/AbcSize
148
147
  Module.new do # rubocop:disable Metrics/BlockLength
149
148
  def self.extended(object)
150
149
  # wrap the dynamically generated module so that we can document the methods
@@ -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)
@@ -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)
@@ -5,9 +5,7 @@ require 'cucumber/gherkin/formatter/ansi_escapes'
5
5
  begin
6
6
  # Support Rake > 0.8.7
7
7
  require 'rake/dsl_definition'
8
- # rubocop:disable Lint/HandleExceptions
9
8
  rescue LoadError
10
- # rubocop:enable Lint/HandleExceptions
11
9
  end
12
10
 
13
11
  module Cucumber
@@ -156,7 +154,7 @@ module Cucumber
156
154
 
157
155
  def runner(_task_args = nil) #:nodoc:
158
156
  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
157
+ return ForkedCucumberRunner.new(libs, binary, cucumber_opts, bundler, feature_files) if fork
160
158
  InProcessCucumberRunner.new(libs, cucumber_opts, feature_files)
161
159
  end
162
160