cucumber 4.0.0.rc.4 → 4.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3cf95e63d73ffec417fa0dfc1f13e208355e78783a9f092d8e143dc5ca26d636
4
- data.tar.gz: 869fe72a5dd449be55d00e2e72d8f78c236961141bf1cc85a7919bca426ec299
3
+ metadata.gz: a1f051aade812ee4bb28ab3670734b189ade8bc0cd0150a686e21874594ae62f
4
+ data.tar.gz: 80c272791953dc442492c0571acffc628cb7b1f37a28a00adeef413bc7f76e1b
5
5
  SHA512:
6
- metadata.gz: 37c240a47d8127723e75c33051ff4e546a7e5a084a22400bb55e6d00d6d578ab7d5d7daf905259cba6625a512986fcacd4076810202e6f63dbffea16b366e9f5
7
- data.tar.gz: 4556b216164535c0c2b39a1f2116b511f0cb1cccfee41cddb513073d0d887014edb38a632978347d1c127e228f1bd683317fbc62588bd4b497cdd51e10a3c550
6
+ metadata.gz: 5026e105060af702f3b0adf50f3925ce04fdee7de79c2482093831cab838e2a605d69c056733d7820b6592c7229ee93e1ce64b80ae373ac7acd29f11d113d3a8
7
+ data.tar.gz: c66fe1effa60270eb430bc2c381252e5c3da5dec524e49c58a7e508febaeb0b1398791f75eba5542395672b2431dafcfb820da2870410a52474ebc157bfbe333
@@ -10,8 +10,83 @@ Please visit [cucumber/CONTRIBUTING.md](https://github.com/cucumber/cucumber/blo
10
10
 
11
11
  ----
12
12
 
13
- ## [4.0.0.rc.4](https://github.com/cucumber/cucumber-ruby/compare/v4.0.0.rc.3...4.0.0.rc.4)
13
+ ## [4.1.0](https://github.com/cucumber/cucumber-ruby/compare/v4.0.1...v4.1.0)
14
+
15
+ ### Changed
16
+
17
+ * Use [`cucumber-create-meta`](https://rubygems.org/gems/cucumber-create-meta) to produce the `Meta` message before the run.
18
+
19
+ * Updated gems:
20
+ * `cucumber-wire` ~> 3.1.0
21
+ * `cucumber-core` ~> 7.1.0
22
+ * `cucumber-gherkin` ~> 14.0.1
23
+ * Fix issue with empty feature files [#1427](https://github.com/cucumber/cucumber-ruby/issues/1427)
24
+ * `cucumber-messages` ~> 12.2.0
25
+ * `cucumber-html-formatter` ~> 7.0.0
26
+ * Fix issue with Hook attachments [#1420](https://github.com/cucumber/cucumber-ruby/issues/1420)
27
+
28
+ ### Fixed
29
+
30
+ * `AfterStep` hook do not cause issue when running `message` formatter. [#1433](https://github.com/cucumber/cucumber-ruby/issues/1433) - [#1434](https://github.com/cucumber/cucumber-ruby/pull/1434)
31
+
32
+
33
+ ## [4.0.1](https://github.com/cucumber/cucumber-ruby/compare/v4.0.0...v4.0.1)
34
+
35
+ ### Fixed
36
+
37
+ * force reference to `diff-lcs` to 1.3 as 1.4 introduced breaking changes.
38
+
39
+ ## [4.0.0](https://github.com/cucumber/cucumber-ruby/compare/v4.0.0.rc.5...v4.0.0)
40
+
41
+ ### Changed
42
+
43
+ * `log` method can now be called with non-string objects and will run `.to_s` on them. [#1410](https://github.com/cucumber/cucumber-ruby/issues/1410)
44
+
45
+ ### Improved
14
46
 
47
+ * Display snippet when using undefined parameter type [#1411](https://github.com/cucumber/cucumber-ruby/issues/1411)
48
+
49
+ ## [4.0.0.rc.6](https://github.com/cucumber/cucumber-ruby/compare/v4.0.0.rc.5...4.0.0.rc.6)
50
+
51
+ ### Changed
52
+
53
+ * Code snippet for an undefined step with a Doc String will ouput `doc_string` instead of `string` in block params
54
+ ([#1401](https://github.com/cucumber/cucumber-ruby/issues/1401)
55
+ [#1402](https://github.com/cucumber/cucumber-ruby/pull/1402)
56
+ [karamosky](https://github.com/karamosky))
57
+
58
+ * Updated monorepo libraries:
59
+ - cucumber-gherkin ~> 13
60
+ - cucumber-html-formatter ~> 6
61
+ - cucumber-cucumber-expressions ~> 10
62
+
63
+ * Use `cucumber-ruby-core` 7.0.0
64
+
65
+ * Use `cucumber-ruby-wire` 3.0.0
66
+
67
+ * Use `body` field of attachments
68
+
69
+ ### Improved
70
+
71
+ * `--out url` updates:
72
+ * supports redirects
73
+ * use `PUT` method by default
74
+ * use a cURL like options (for example: `cucumber --out 'http://example.com -X POST -H Content-Type: json`)
75
+
76
+ ## [4.0.0.rc.5](https://github.com/cucumber/cucumber-ruby/compare/v4.0.0.rc.4...4.0.0.rc.5)
77
+
78
+ ### Added
79
+
80
+ * New html formatter enabled by option `--format html --out report.html`.
81
+
82
+ * Accept `--out URL` to POST results to a web server
83
+ If a URL is used as output, the output will be sent with a POST request.
84
+ This can be overridden by specifying e.g. `http-method=PUT` as a query parameter.
85
+ Other `http-` prefixed query parameters will be converted to request headers
86
+ (with the `http-` prefix stripped off).
87
+
88
+
89
+ ## [4.0.0.rc.4](https://github.com/cucumber/cucumber-ruby/compare/v4.0.0.rc.3...4.0.0.rc.4)
15
90
 
16
91
  ### Added
17
92
 
@@ -42,7 +117,7 @@ Please visit [cucumber/CONTRIBUTING.md](https://github.com/cucumber/cucumber/blo
42
117
  * If you wish to alter this, then you can set a top level config option: `Cucumber.use_legacy_autoloader`
43
118
  * Like most config options, setting this inside a `spec_helper.rb` or `env.rb` file is advised
44
119
  * For more information on this change, including why it was made. Please read this
45
- [Blog Post](www.google.com)
120
+ [Blog Post](https://cucumber.io/blog/open-source/tweaking-cucumber-rubys-auto-loader/)
46
121
  ([#1349](https://github.com/cucumber/cucumber-ruby/pull/1349),
47
122
  [#1043](https://github.com/cucumber/cucumber-ruby/issues/1043)
48
123
  [luke-hill](https://github.com/luke-hill))
data/README.md CHANGED
@@ -15,7 +15,7 @@ your team.
15
15
 
16
16
  Where to get more info:
17
17
 
18
- * The main website: https://cucumber.io/
18
+ * The main website: https://cucumber.io/
19
19
  * Documentation: https://cucumber.io/docs
20
20
  * Ruby API Documentation: http://www.rubydoc.info/github/cucumber/cucumber-ruby/
21
21
  * Support forum: https://groups.google.com/group/cukes
@@ -28,7 +28,7 @@ See [CONTRIBUTING.md](CONTRIBUTING.md) for info on contributing to Cucumber.
28
28
  * Ruby 2.5
29
29
  * Ruby 2.4
30
30
  * Ruby 2.3
31
- * JRuby 9.1
31
+ * JRuby 9.2 (with [some limitations](https://github.com/cucumber/cucumber-ruby/blob/master/docs/jruby-limitations.md))
32
32
 
33
33
  ## Code of Conduct
34
34
 
@@ -24,6 +24,7 @@ module Cucumber
24
24
  'junit' => ['Cucumber::Formatter::Junit', 'Generates a report similar to Ant+JUnit.'],
25
25
  'json' => ['Cucumber::Formatter::Json', '[DEPRECATED] Prints the feature as JSON'],
26
26
  'message' => ['Cucumber::Formatter::Message', 'Outputs protobuf messages'],
27
+ 'html' => ['Cucumber::Formatter::HTML', 'Outputs HTML report'],
27
28
  'summary' => ['Cucumber::Formatter::Summary', 'Summary output of feature and scenarios']
28
29
  }.freeze
29
30
  max = BUILTIN_FORMATS.keys.map(&:length).max
@@ -104,7 +105,7 @@ module Cucumber
104
105
  add_option :formats, [*parse_formats(v), @out_stream]
105
106
  end
106
107
  opts.on('--init', *init_msg) { |_v| initialize_project }
107
- opts.on('-o', '--out [FILE|DIR]', *out_msg) { |v| out_stream v }
108
+ opts.on('-o', '--out [FILE|DIR|URL]', *out_msg) { |v| out_stream v }
108
109
  opts.on('-t TAG_EXPRESSION', '--tags TAG_EXPRESSION', *tags_msg) { |v| add_tag v }
109
110
  opts.on('-n NAME', '--name NAME', *name_msg) { |v| add_option :name_regexps, /#{v}/ }
110
111
  opts.on('-e', '--exclude PATTERN', *exclude_msg) { |v| add_option :excludes, Regexp.new(v) }
@@ -295,10 +296,14 @@ Specify SEED to reproduce the shuffling from a previous run.
295
296
 
296
297
  def out_msg
297
298
  [
298
- 'Write output to a file/directory instead of STDOUT. This option',
299
+ 'Write output to a file/directory/URL instead of STDOUT. This option',
299
300
  'applies to the previously specified --format, or the',
300
301
  'default format if no format is specified. Check the specific',
301
- "formatter's docs to see whether to pass a file or a dir."
302
+ "formatter's docs to see whether to pass a file, dir or URL.",
303
+ "\n",
304
+ 'When using a URL, the output of the formatter will be sent as the HTTP request body.',
305
+ 'HTTP headers and request method can be set with cURL like options.',
306
+ 'Example: --out "http://example.com -X POST -H Content-Type:text/json"'
302
307
  ]
303
308
  end
304
309
 
@@ -49,7 +49,4 @@ module Cucumber
49
49
  super(messages.join("\n"))
50
50
  end
51
51
  end
52
-
53
- class LogTypeInvalid < StandardError
54
- end
55
52
  end
@@ -38,7 +38,8 @@ module Cucumber
38
38
  TestStepCreated,
39
39
  TestStepFinished,
40
40
  TestStepStarted,
41
- Envelope
41
+ Envelope,
42
+ UndefinedParameterType
42
43
  )
43
44
  end
44
45
  end
@@ -0,0 +1,10 @@
1
+ require 'cucumber/core/events'
2
+
3
+ module Cucumber
4
+ module Events
5
+ class UndefinedParameterType < Core::Event.new(:type_name, :expression)
6
+ attr_reader :type_name
7
+ attr_reader :expression
8
+ end
9
+ end
10
+ end
@@ -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'
@@ -116,14 +118,21 @@ module Cucumber
116
118
  @snippets_input << Console::SnippetData.new(keyword, test_step)
117
119
  end
118
120
 
121
+ def collect_undefined_parameter_type_names(undefined_parameter_type)
122
+ @undefined_parameter_types << undefined_parameter_type.type_name
123
+ end
124
+
119
125
  def print_snippets(options)
120
126
  return unless options[:snippets]
121
- return if @snippets_input.empty?
122
127
 
123
128
  snippet_text_proc = lambda do |step_keyword, step_name, multiline_arg|
124
129
  snippet_text(step_keyword, step_name, multiline_arg)
125
130
  end
126
- do_print_snippets(snippet_text_proc)
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)
135
+ end
127
136
  end
128
137
 
129
138
  def do_print_snippets(snippet_text_proc)
@@ -181,6 +190,24 @@ module Cucumber
181
190
  @io.puts "Using the #{profiles_sentence} profile#{'s' if profiles.size > 1}..."
182
191
  end
183
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
+
184
211
  private
185
212
 
186
213
  FORMATS = Hash.new { |hash, format| hash[format] = method(format).to_proc }
@@ -219,3 +246,4 @@ module Cucumber
219
246
  end
220
247
  end
221
248
  end
249
+ # rubocop:enable Metrics/ModuleLength
@@ -0,0 +1,24 @@
1
+ require 'cucumber/formatter/io'
2
+ require 'cucumber/html_formatter'
3
+ require 'cucumber/formatter/message_builder'
4
+
5
+ module Cucumber
6
+ module Formatter
7
+ class HTML < MessageBuilder
8
+ include Io
9
+
10
+ def initialize(config)
11
+ @io = ensure_io(config.out_stream)
12
+ @html_formatter = Cucumber::HTMLFormatter::Formatter.new(@io)
13
+ @html_formatter.write_pre_message
14
+
15
+ super(config)
16
+ end
17
+
18
+ def output_envelope(envelope)
19
+ @html_formatter.write_message(envelope)
20
+ @html_formatter.write_post_message if envelope.test_run_finished
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,146 @@
1
+ require 'net/http'
2
+ require 'tempfile'
3
+
4
+ module Cucumber
5
+ module Formatter
6
+ class HTTPIO
7
+ class << self
8
+ # Returns an IO that will write to a HTTP request's body
9
+ def open(url, https_verify_mode = nil)
10
+ @https_verify_mode = https_verify_mode
11
+ uri, method, headers = CurlOptionParser.parse(url)
12
+ IOHTTPBuffer.new(uri, method, headers, https_verify_mode)
13
+ end
14
+ end
15
+ end
16
+
17
+ class CurlOptionParser
18
+ def self.parse(options)
19
+ chunks = options.split(/\s/).compact
20
+ http_method = 'PUT'
21
+ url = chunks[0]
22
+ headers = ''
23
+
24
+ last_flag = nil
25
+ chunks.each do |chunk|
26
+ if ['-X', '--request'].include?(chunk)
27
+ last_flag = '-X'
28
+ next
29
+ end
30
+
31
+ if chunk == '-H'
32
+ last_flag = '-H'
33
+ next
34
+ end
35
+
36
+ if last_flag == '-X'
37
+ http_method = chunk
38
+ last_flag = nil
39
+ end
40
+
41
+ headers += chunk if last_flag == '-H'
42
+ end
43
+
44
+ [
45
+ url,
46
+ http_method,
47
+ make_headers(headers)
48
+ ]
49
+ end
50
+
51
+ def self.make_headers(headers)
52
+ hash_headers = {}
53
+ str_scanner = /("(?<key>[^":]+)\s*:\s*(?<value>[^":]+)")|('(?<key1>[^':]+)\s*:\s*(?<value1>[^':]+)')/
54
+
55
+ headers.scan(str_scanner) do |header|
56
+ header = header.compact!
57
+ hash_headers[header[0]] = header[1]&.strip
58
+ end
59
+
60
+ hash_headers
61
+ end
62
+ end
63
+
64
+ class IOHTTPBuffer
65
+ attr_reader :uri, :method, :headers
66
+
67
+ def initialize(uri, method, headers = {}, https_verify_mode = nil)
68
+ @uri = URI(uri)
69
+ @method = method
70
+ @headers = headers
71
+ @write_io = Tempfile.new('cucumber', encoding: 'UTF-8')
72
+ @https_verify_mode = https_verify_mode
73
+ end
74
+
75
+ def close
76
+ post_content(@uri, @method, @headers)
77
+ @write_io.close
78
+ end
79
+
80
+ def write(data)
81
+ @write_io.write(data)
82
+ end
83
+
84
+ def flush
85
+ @write_io.flush
86
+ end
87
+
88
+ def closed?
89
+ @write_io.closed?
90
+ end
91
+
92
+ private
93
+
94
+ def post_content(uri, method, headers, attempt = 10)
95
+ content = @write_io
96
+ http = build_client(uri, @https_verify_mode)
97
+
98
+ raise StandardError, "request to #{uri} failed (too many redirections)" if attempt <= 0
99
+ req = build_request(
100
+ uri,
101
+ method,
102
+ headers.merge(
103
+ 'Content-Length' => content.size.to_s
104
+ )
105
+ )
106
+
107
+ content.rewind
108
+ req.body_stream = content
109
+
110
+ begin
111
+ response = http.request(req)
112
+ rescue SystemCallError
113
+ # We may get the redirect response before pushing the file.
114
+ response = http.request(build_request(uri, method, headers))
115
+ end
116
+
117
+ case response
118
+ when Net::HTTPSuccess
119
+ response
120
+ when Net::HTTPRedirection
121
+ post_content(URI(response['Location']), method, headers, attempt - 1)
122
+ else
123
+ raise StandardError, "request to #{uri} failed with status #{response.code}"
124
+ end
125
+ end
126
+
127
+ def build_request(uri, method, headers)
128
+ method_class_name = "#{method[0].upcase}#{method[1..-1].downcase}"
129
+ req = Net::HTTP.const_get(method_class_name).new(uri)
130
+ headers.each do |header, value|
131
+ req[header] = value
132
+ end
133
+ req
134
+ end
135
+
136
+ def build_client(uri, https_verify_mode)
137
+ http = Net::HTTP.new(uri.hostname, uri.port)
138
+ if uri.scheme == 'https'
139
+ http.use_ssl = true
140
+ http.verify_mode = https_verify_mode if https_verify_mode
141
+ end
142
+ http
143
+ end
144
+ end
145
+ end
146
+ end
@@ -9,17 +9,18 @@ module Cucumber
9
9
  @pipe = pipe
10
10
  @buffer = StringIO.new
11
11
  @wrapped = true
12
+ @lock = Mutex.new
12
13
  end
13
14
 
14
15
  def write(str)
15
- lock.synchronize do
16
+ @lock.synchronize do
16
17
  @buffer << str if @wrapped
17
18
  return @pipe.write(str)
18
19
  end
19
20
  end
20
21
 
21
22
  def buffer_string
22
- lock.synchronize do
23
+ @lock.synchronize do
23
24
  return @buffer.string.dup
24
25
  end
25
26
  end
@@ -67,12 +68,6 @@ module Cucumber
67
68
  return $stdout
68
69
  end
69
70
  end
70
-
71
- private
72
-
73
- def lock
74
- @lock ||= Mutex.new
75
- end
76
71
  end
77
72
  end
78
73
  end