cucumber 4.0.0.rc.6 → 5.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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