cucumber 3.0.2 → 4.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.
- checksums.yaml +5 -5
- data/CHANGELOG.md +216 -17
- data/CONTRIBUTING.md +4 -21
- data/README.md +8 -10
- data/bin/cucumber +1 -1
- data/lib/autotest/cucumber.rb +1 -0
- data/lib/autotest/cucumber_mixin.rb +35 -39
- data/lib/autotest/cucumber_rails.rb +1 -0
- data/lib/autotest/cucumber_rails_rspec.rb +1 -0
- data/lib/autotest/cucumber_rails_rspec2.rb +1 -0
- data/lib/autotest/cucumber_rspec.rb +1 -0
- data/lib/autotest/cucumber_rspec2.rb +1 -0
- data/lib/autotest/discover.rb +1 -0
- data/lib/cucumber.rb +2 -1
- data/lib/cucumber/cli/configuration.rb +6 -5
- data/lib/cucumber/cli/main.rb +14 -14
- data/lib/cucumber/cli/options.rb +113 -116
- data/lib/cucumber/cli/profile_loader.rb +50 -29
- data/lib/cucumber/cli/rerun_file.rb +1 -0
- data/lib/cucumber/configuration.rb +38 -29
- data/lib/cucumber/constantize.rb +8 -10
- data/lib/cucumber/core_ext/string.rb +1 -0
- data/lib/cucumber/deprecate.rb +32 -8
- data/lib/cucumber/encoding.rb +2 -1
- data/lib/cucumber/errors.rb +6 -7
- data/lib/cucumber/events.rb +14 -7
- data/lib/cucumber/events/envelope.rb +9 -0
- data/lib/cucumber/events/gherkin_source_parsed.rb +11 -0
- data/lib/cucumber/events/gherkin_source_read.rb +1 -4
- data/lib/cucumber/events/hook_test_step_created.rb +13 -0
- data/lib/cucumber/events/step_activated.rb +6 -6
- data/lib/cucumber/events/step_definition_registered.rb +4 -8
- data/lib/cucumber/events/test_case_created.rb +13 -0
- data/lib/cucumber/events/test_case_finished.rb +0 -4
- data/lib/cucumber/events/test_case_ready.rb +12 -0
- data/lib/cucumber/events/test_case_started.rb +0 -4
- data/lib/cucumber/events/test_run_finished.rb +2 -3
- data/lib/cucumber/events/test_run_started.rb +2 -4
- data/lib/cucumber/events/test_step_created.rb +13 -0
- data/lib/cucumber/events/test_step_finished.rb +0 -4
- data/lib/cucumber/events/test_step_started.rb +1 -5
- data/lib/cucumber/events/undefined_parameter_type.rb +10 -0
- data/lib/cucumber/file_specs.rb +7 -6
- data/lib/cucumber/filters.rb +2 -0
- data/lib/cucumber/filters/activate_steps.rb +6 -4
- data/lib/cucumber/filters/apply_after_hooks.rb +1 -0
- data/lib/cucumber/filters/apply_after_step_hooks.rb +1 -0
- data/lib/cucumber/filters/apply_around_hooks.rb +1 -0
- data/lib/cucumber/filters/apply_before_hooks.rb +1 -0
- data/lib/cucumber/filters/broadcast_test_case_ready_event.rb +12 -0
- data/lib/cucumber/filters/broadcast_test_run_started_event.rb +2 -1
- data/lib/cucumber/filters/gated_receiver.rb +1 -2
- data/lib/cucumber/filters/prepare_world.rb +6 -13
- data/lib/cucumber/filters/quit.rb +3 -6
- data/lib/cucumber/filters/randomizer.rb +6 -7
- data/lib/cucumber/filters/retry.rb +2 -2
- data/lib/cucumber/filters/tag_limits.rb +2 -2
- data/lib/cucumber/filters/tag_limits/test_case_index.rb +1 -2
- data/lib/cucumber/filters/tag_limits/verifier.rb +3 -6
- data/lib/cucumber/formatter/ansicolor.rb +33 -37
- data/lib/cucumber/formatter/ast_lookup.rb +165 -0
- data/lib/cucumber/formatter/backtrace_filter.rb +10 -10
- data/lib/cucumber/formatter/console.rb +65 -74
- data/lib/cucumber/formatter/console_counts.rb +4 -9
- data/lib/cucumber/formatter/console_issues.rb +9 -6
- data/lib/cucumber/formatter/duration.rb +2 -1
- data/lib/cucumber/formatter/duration_extractor.rb +4 -2
- data/lib/cucumber/formatter/errors.rb +6 -0
- data/lib/cucumber/formatter/fail_fast.rb +9 -6
- data/lib/cucumber/formatter/fanout.rb +3 -3
- data/lib/cucumber/formatter/html.rb +11 -602
- data/lib/cucumber/formatter/http_io.rb +146 -0
- data/lib/cucumber/formatter/ignore_missing_messages.rb +2 -3
- data/lib/cucumber/formatter/interceptor.rb +11 -18
- data/lib/cucumber/formatter/io.rb +18 -11
- data/lib/cucumber/formatter/json.rb +102 -109
- data/lib/cucumber/formatter/junit.rb +73 -68
- data/lib/cucumber/formatter/message.rb +22 -0
- data/lib/cucumber/formatter/message_builder.rb +255 -0
- data/lib/cucumber/formatter/pretty.rb +360 -153
- data/lib/cucumber/formatter/progress.rb +31 -32
- data/lib/cucumber/formatter/query/hook_by_test_step.rb +31 -0
- data/lib/cucumber/formatter/query/pickle_by_test.rb +26 -0
- data/lib/cucumber/formatter/query/pickle_step_by_test_step.rb +26 -0
- data/lib/cucumber/formatter/query/step_definitions_by_test_step.rb +40 -0
- data/lib/cucumber/formatter/query/test_case_started_by_test_case.rb +40 -0
- data/lib/cucumber/formatter/rerun.rb +23 -4
- data/lib/cucumber/formatter/stepdefs.rb +2 -2
- data/lib/cucumber/formatter/steps.rb +4 -5
- data/lib/cucumber/formatter/summary.rb +17 -9
- data/lib/cucumber/formatter/unicode.rb +16 -18
- data/lib/cucumber/formatter/usage.rb +30 -26
- data/lib/cucumber/gherkin/data_table_parser.rb +18 -6
- data/lib/cucumber/gherkin/formatter/ansi_escapes.rb +83 -86
- data/lib/cucumber/gherkin/formatter/escaping.rb +13 -12
- data/lib/cucumber/gherkin/i18n.rb +1 -0
- data/lib/cucumber/gherkin/steps_parser.rb +18 -8
- data/lib/cucumber/glue/dsl.rb +2 -1
- data/lib/cucumber/glue/hook.rb +35 -11
- data/lib/cucumber/glue/invoke_in_world.rb +15 -20
- data/lib/cucumber/glue/proto_world.rb +47 -39
- data/lib/cucumber/glue/registry_and_more.rb +54 -23
- data/lib/cucumber/glue/snippet.rb +24 -27
- data/lib/cucumber/glue/step_definition.rb +51 -28
- data/lib/cucumber/glue/world_factory.rb +1 -3
- data/lib/cucumber/hooks.rb +24 -14
- data/lib/cucumber/load_path.rb +1 -0
- data/lib/cucumber/multiline_argument.rb +6 -8
- data/lib/cucumber/multiline_argument/data_table.rb +106 -73
- data/lib/cucumber/multiline_argument/data_table/diff_matrices.rb +8 -11
- data/lib/cucumber/multiline_argument/doc_string.rb +2 -1
- data/lib/cucumber/platform.rb +4 -3
- data/lib/cucumber/project_initializer.rb +1 -1
- data/lib/cucumber/rake/task.rb +21 -18
- data/lib/cucumber/rspec/disable_option_parser.rb +10 -8
- data/lib/cucumber/rspec/doubles.rb +1 -0
- data/lib/cucumber/running_test_case.rb +4 -54
- data/lib/cucumber/runtime.rb +57 -61
- data/lib/cucumber/runtime/after_hooks.rb +9 -4
- data/lib/cucumber/runtime/before_hooks.rb +9 -4
- data/lib/cucumber/runtime/for_programming_languages.rb +12 -9
- data/lib/cucumber/runtime/step_hooks.rb +5 -2
- data/lib/cucumber/runtime/support_code.rb +16 -22
- data/lib/cucumber/runtime/user_interface.rb +8 -19
- data/lib/cucumber/step_definition_light.rb +6 -4
- data/lib/cucumber/step_definitions.rb +3 -2
- data/lib/cucumber/step_match.rb +20 -18
- data/lib/cucumber/step_match_search.rb +9 -9
- data/lib/cucumber/term/ansicolor.rb +39 -39
- data/lib/cucumber/unit.rb +1 -0
- data/lib/cucumber/version +1 -1
- data/lib/simplecov_setup.rb +1 -0
- metadata +214 -127
- data/lib/cucumber/formatter/cucumber.css +0 -286
- data/lib/cucumber/formatter/cucumber.sass +0 -247
- data/lib/cucumber/formatter/hook_query_visitor.rb +0 -41
- data/lib/cucumber/formatter/html_builder.rb +0 -120
- data/lib/cucumber/formatter/inline-js.js +0 -30
- data/lib/cucumber/formatter/jquery-min.js +0 -154
- data/lib/cucumber/formatter/json_pretty.rb +0 -10
- data/lib/cucumber/formatter/legacy_api/adapter.rb +0 -1028
- data/lib/cucumber/formatter/legacy_api/ast.rb +0 -394
- data/lib/cucumber/formatter/legacy_api/results.rb +0 -50
- data/lib/cucumber/formatter/legacy_api/runtime_facade.rb +0 -32
- data/lib/cucumber/step_argument.rb +0 -24
@@ -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
|
@@ -1,20 +1,19 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
module Cucumber
|
3
4
|
module Formatter
|
4
|
-
|
5
5
|
class IgnoreMissingMessages < BasicObject
|
6
6
|
def initialize(receiver)
|
7
7
|
@receiver = receiver
|
8
8
|
end
|
9
9
|
|
10
10
|
def method_missing(message, *args)
|
11
|
-
@receiver.
|
11
|
+
@receiver.respond_to?(message) ? @receiver.send(message, *args) : super
|
12
12
|
end
|
13
13
|
|
14
14
|
def respond_to_missing?(name, include_private = false)
|
15
15
|
@receiver.respond_to?(name, include_private)
|
16
16
|
end
|
17
17
|
end
|
18
|
-
|
19
18
|
end
|
20
19
|
end
|
@@ -1,5 +1,4 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
require 'thread'
|
3
2
|
|
4
3
|
module Cucumber
|
5
4
|
module Formatter
|
@@ -8,20 +7,21 @@ module Cucumber
|
|
8
7
|
attr_reader :pipe
|
9
8
|
def initialize(pipe)
|
10
9
|
@pipe = pipe
|
11
|
-
@buffer =
|
10
|
+
@buffer = StringIO.new
|
12
11
|
@wrapped = true
|
12
|
+
@lock = Mutex.new
|
13
13
|
end
|
14
14
|
|
15
15
|
def write(str)
|
16
|
-
lock.synchronize do
|
16
|
+
@lock.synchronize do
|
17
17
|
@buffer << str if @wrapped
|
18
18
|
return @pipe.write(str)
|
19
19
|
end
|
20
20
|
end
|
21
21
|
|
22
|
-
def
|
23
|
-
lock.synchronize do
|
24
|
-
return @buffer.dup
|
22
|
+
def buffer_string
|
23
|
+
@lock.synchronize do
|
24
|
+
return @buffer.string.dup
|
25
25
|
end
|
26
26
|
end
|
27
27
|
|
@@ -31,17 +31,15 @@ module Cucumber
|
|
31
31
|
end
|
32
32
|
|
33
33
|
def method_missing(method, *args, &blk)
|
34
|
-
@pipe.send(method, *args, &blk)
|
34
|
+
@pipe.send(method, *args, &blk) || super
|
35
35
|
end
|
36
36
|
|
37
|
-
def
|
37
|
+
def respond_to_missing?(method, include_private = false)
|
38
38
|
super || @pipe.respond_to?(method, include_private)
|
39
39
|
end
|
40
40
|
|
41
41
|
def self.validate_pipe(pipe)
|
42
|
-
unless [
|
43
|
-
raise ArgumentError, '#wrap only accepts :stderr or :stdout'
|
44
|
-
end
|
42
|
+
raise ArgumentError, '#wrap only accepts :stderr or :stdout' unless %i[stdout stderr].include? pipe
|
45
43
|
end
|
46
44
|
|
47
45
|
def self.unwrap!(pipe)
|
@@ -63,18 +61,13 @@ module Cucumber
|
|
63
61
|
|
64
62
|
case pipe
|
65
63
|
when :stderr
|
66
|
-
$stderr =
|
64
|
+
$stderr = new($stderr)
|
67
65
|
return $stderr
|
68
66
|
when :stdout
|
69
|
-
$stdout =
|
67
|
+
$stdout = new($stdout)
|
70
68
|
return $stdout
|
71
69
|
end
|
72
70
|
end
|
73
|
-
|
74
|
-
private
|
75
|
-
def lock
|
76
|
-
@lock||=Mutex.new
|
77
|
-
end
|
78
71
|
end
|
79
72
|
end
|
80
73
|
end
|
@@ -1,31 +1,38 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'cucumber/formatter/http_io'
|
4
|
+
|
2
5
|
module Cucumber
|
3
6
|
module Formatter
|
4
7
|
module Io
|
5
8
|
module_function
|
6
9
|
|
7
|
-
def ensure_io(
|
8
|
-
return nil if
|
9
|
-
return
|
10
|
-
|
10
|
+
def ensure_io(path_or_url_or_io)
|
11
|
+
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)
|
15
|
+
else
|
16
|
+
File.open(path_or_url_or_io, Cucumber.file_mode('w'))
|
17
|
+
end
|
11
18
|
at_exit do
|
12
|
-
unless
|
13
|
-
|
14
|
-
|
19
|
+
unless io.closed?
|
20
|
+
io.flush
|
21
|
+
io.close
|
15
22
|
end
|
16
23
|
end
|
17
|
-
|
24
|
+
io
|
18
25
|
end
|
19
26
|
|
20
27
|
def ensure_file(path, name)
|
21
|
-
raise "You *must* specify --out FILE for the #{name} formatter" unless String
|
28
|
+
raise "You *must* specify --out FILE for the #{name} formatter" unless String == path.class
|
22
29
|
raise "I can't write #{name} to a directory - it has to be a file" if File.directory?(path)
|
23
|
-
raise "I can't write #{name} to a file in the non-existing directory #{File.dirname(path)}"
|
30
|
+
raise "I can't write #{name} to a file in the non-existing directory #{File.dirname(path)}" unless File.directory?(File.dirname(path))
|
24
31
|
ensure_io(path)
|
25
32
|
end
|
26
33
|
|
27
34
|
def ensure_dir(path, name)
|
28
|
-
raise "You *must* specify --out DIR for the #{name} formatter" unless String
|
35
|
+
raise "You *must* specify --out DIR for the #{name} formatter" unless String == path.class
|
29
36
|
raise "I can't write #{name} reports to a file - it has to be a directory" if File.file?(path)
|
30
37
|
FileUtils.mkdir_p(path) unless File.directory?(path)
|
31
38
|
File.absolute_path path
|
@@ -1,9 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
|
2
|
+
|
3
|
+
require 'json'
|
3
4
|
require 'base64'
|
4
5
|
require 'cucumber/formatter/backtrace_filter'
|
5
6
|
require 'cucumber/formatter/io'
|
6
|
-
require 'cucumber/formatter/
|
7
|
+
require 'cucumber/formatter/ast_lookup'
|
8
|
+
require 'cucumber/deprecate'
|
7
9
|
|
8
10
|
module Cucumber
|
9
11
|
module Formatter
|
@@ -12,7 +14,16 @@ module Cucumber
|
|
12
14
|
include Io
|
13
15
|
|
14
16
|
def initialize(config)
|
17
|
+
Cucumber::Deprecate::CliOption.deprecate(
|
18
|
+
config.error_stream,
|
19
|
+
'--format=json',
|
20
|
+
"Please use --format=message and stand-alone json-formatter.\n" \
|
21
|
+
'json-formatter homepage: https://github.com/cucumber/cucumber/tree/master/json-formatter#cucumber-json-formatter',
|
22
|
+
'5.0.0'
|
23
|
+
)
|
24
|
+
|
15
25
|
@io = ensure_io(config.out_stream)
|
26
|
+
@ast_lookup = AstLookup.new(config)
|
16
27
|
@feature_hashes = []
|
17
28
|
@step_or_hook_hash = {}
|
18
29
|
config.on_event :test_case_started, &method(:on_test_case_started)
|
@@ -24,16 +35,18 @@ module Cucumber
|
|
24
35
|
|
25
36
|
def on_test_case_started(event)
|
26
37
|
test_case = event.test_case
|
27
|
-
builder = Builder.new(test_case)
|
28
|
-
unless same_feature_as_previous_test_case?(test_case
|
38
|
+
builder = Builder.new(test_case, @ast_lookup)
|
39
|
+
unless same_feature_as_previous_test_case?(test_case)
|
29
40
|
@feature_hash = builder.feature_hash
|
30
41
|
@feature_hashes << @feature_hash
|
31
42
|
end
|
32
43
|
@test_case_hash = builder.test_case_hash
|
33
44
|
if builder.background?
|
45
|
+
@in_background = true
|
34
46
|
feature_elements << builder.background_hash
|
35
47
|
@element_hash = builder.background_hash
|
36
48
|
else
|
49
|
+
@in_background = false
|
37
50
|
feature_elements << @test_case_hash
|
38
51
|
@element_hash = @test_case_hash
|
39
52
|
end
|
@@ -43,17 +56,17 @@ module Cucumber
|
|
43
56
|
def on_test_step_started(event)
|
44
57
|
test_step = event.test_step
|
45
58
|
return if internal_hook?(test_step)
|
46
|
-
|
47
|
-
if hook_query.hook?
|
59
|
+
if test_step.hook?
|
48
60
|
@step_or_hook_hash = {}
|
49
|
-
hooks_of_type(
|
61
|
+
hooks_of_type(test_step) << @step_or_hook_hash
|
50
62
|
return
|
51
63
|
end
|
52
64
|
if first_step_after_background?(test_step)
|
65
|
+
@in_background = false
|
53
66
|
feature_elements << @test_case_hash
|
54
67
|
@element_hash = @test_case_hash
|
55
68
|
end
|
56
|
-
@step_or_hook_hash = create_step_hash(test_step
|
69
|
+
@step_or_hook_hash = create_step_hash(test_step)
|
57
70
|
steps << @step_or_hook_hash
|
58
71
|
@step_hash = @step_or_hook_hash
|
59
72
|
end
|
@@ -73,44 +86,42 @@ module Cucumber
|
|
73
86
|
end
|
74
87
|
|
75
88
|
def on_test_run_finished(_event)
|
76
|
-
@io.write(
|
77
|
-
end
|
78
|
-
|
79
|
-
def puts(message)
|
80
|
-
test_step_output << message
|
89
|
+
@io.write(JSON.generate(@feature_hashes, pretty: true))
|
81
90
|
end
|
82
91
|
|
83
|
-
def
|
92
|
+
def attach(src, mime_type)
|
93
|
+
if mime_type == 'text/x.cucumber.log+plain'
|
94
|
+
test_step_output << src
|
95
|
+
return
|
96
|
+
end
|
84
97
|
if File.file?(src)
|
85
98
|
content = File.open(src, 'rb', &:read)
|
86
99
|
data = encode64(content)
|
100
|
+
elsif mime_type =~ /;base64$/
|
101
|
+
mime_type = mime_type[0..-8]
|
102
|
+
data = src
|
87
103
|
else
|
88
|
-
|
89
|
-
mime_type = mime_type[0..-8]
|
90
|
-
data = src
|
91
|
-
else
|
92
|
-
data = encode64(src)
|
93
|
-
end
|
104
|
+
data = encode64(src)
|
94
105
|
end
|
95
106
|
test_step_embeddings << { mime_type: mime_type, data: data }
|
96
107
|
end
|
97
108
|
|
98
109
|
private
|
99
110
|
|
100
|
-
def same_feature_as_previous_test_case?(
|
101
|
-
current_feature[:uri] ==
|
111
|
+
def same_feature_as_previous_test_case?(test_case)
|
112
|
+
current_feature[:uri] == test_case.location.file
|
102
113
|
end
|
103
114
|
|
104
115
|
def first_step_after_background?(test_step)
|
105
|
-
test_step.
|
116
|
+
@in_background && test_step.location.lines.max >= @test_case_hash[:line]
|
106
117
|
end
|
107
118
|
|
108
119
|
def internal_hook?(test_step)
|
109
|
-
test_step.
|
120
|
+
test_step.location.file.include?('lib/cucumber/')
|
110
121
|
end
|
111
122
|
|
112
123
|
def current_feature
|
113
|
-
@feature_hash ||= {}
|
124
|
+
@feature_hash ||= {} # rubocop:disable Naming/MemoizedInstanceVariableName
|
114
125
|
end
|
115
126
|
|
116
127
|
def feature_elements
|
@@ -121,16 +132,16 @@ module Cucumber
|
|
121
132
|
@element_hash[:steps] ||= []
|
122
133
|
end
|
123
134
|
|
124
|
-
def hooks_of_type(
|
125
|
-
case
|
126
|
-
when
|
127
|
-
|
128
|
-
when
|
129
|
-
|
130
|
-
when
|
131
|
-
|
135
|
+
def hooks_of_type(hook_step)
|
136
|
+
case hook_step.text
|
137
|
+
when 'Before hook'
|
138
|
+
before_hooks
|
139
|
+
when 'After hook'
|
140
|
+
after_hooks
|
141
|
+
when 'AfterStep hook'
|
142
|
+
after_step_hooks
|
132
143
|
else
|
133
|
-
|
144
|
+
raise 'Unknown hook type ' + hook_step.to_s
|
134
145
|
end
|
135
146
|
end
|
136
147
|
|
@@ -158,20 +169,20 @@ module Cucumber
|
|
158
169
|
@step_or_hook_hash[:embeddings] ||= []
|
159
170
|
end
|
160
171
|
|
161
|
-
def create_step_hash(
|
172
|
+
def create_step_hash(test_step)
|
173
|
+
step_source = @ast_lookup.step_source(test_step).step
|
162
174
|
step_hash = {
|
163
175
|
keyword: step_source.keyword,
|
164
|
-
name:
|
165
|
-
line:
|
176
|
+
name: test_step.text,
|
177
|
+
line: test_step.location.lines.min
|
166
178
|
}
|
167
|
-
step_hash[:
|
168
|
-
step_hash[:
|
169
|
-
step_hash[:rows] = create_data_table_value(step_source.multiline_arg) if step_source.multiline_arg.data_table?
|
179
|
+
step_hash[:doc_string] = create_doc_string_hash(step_source.doc_string) unless step_source.doc_string.nil?
|
180
|
+
step_hash[:rows] = create_data_table_value(step_source.data_table) unless step_source.data_table.nil?
|
170
181
|
step_hash
|
171
182
|
end
|
172
183
|
|
173
184
|
def create_doc_string_hash(doc_string)
|
174
|
-
content_type = doc_string.
|
185
|
+
content_type = doc_string.media_type || ''
|
175
186
|
{
|
176
187
|
value: doc_string.content,
|
177
188
|
content_type: content_type,
|
@@ -180,14 +191,15 @@ module Cucumber
|
|
180
191
|
end
|
181
192
|
|
182
193
|
def create_data_table_value(data_table)
|
183
|
-
data_table.
|
184
|
-
{ cells: row }
|
194
|
+
data_table.rows.map do |row|
|
195
|
+
{ cells: row.cells.map(&:value) }
|
185
196
|
end
|
186
197
|
end
|
187
198
|
|
188
199
|
def add_match_and_result(test_step, result)
|
189
200
|
@step_or_hook_hash[:match] = create_match_hash(test_step, result)
|
190
201
|
@step_or_hook_hash[:result] = create_result_hash(result)
|
202
|
+
result.embeddings.each { |e| embed(e['src'], e['mime_type'], e['label']) } if result.respond_to?(:embeddings)
|
191
203
|
end
|
192
204
|
|
193
205
|
def add_failed_around_hook(result)
|
@@ -225,113 +237,94 @@ module Cucumber
|
|
225
237
|
class Builder
|
226
238
|
attr_reader :feature_hash, :background_hash, :test_case_hash
|
227
239
|
|
228
|
-
def initialize(test_case)
|
240
|
+
def initialize(test_case, ast_lookup)
|
229
241
|
@background_hash = nil
|
230
|
-
test_case.
|
231
|
-
|
242
|
+
uri = test_case.location.file
|
243
|
+
feature = ast_lookup.gherkin_document(uri).feature
|
244
|
+
feature(feature, uri)
|
245
|
+
background(feature.children.first.background) unless feature.children.first.background.nil?
|
246
|
+
scenario(ast_lookup.scenario_source(test_case), test_case)
|
232
247
|
end
|
233
248
|
|
234
249
|
def background?
|
235
250
|
@background_hash != nil
|
236
251
|
end
|
237
252
|
|
238
|
-
def feature(feature)
|
253
|
+
def feature(feature, uri)
|
239
254
|
@feature_hash = {
|
240
|
-
|
241
|
-
|
255
|
+
id: create_id(feature.name),
|
256
|
+
uri: uri,
|
242
257
|
keyword: feature.keyword,
|
243
|
-
name: feature.
|
244
|
-
description: feature.description,
|
258
|
+
name: feature.name,
|
259
|
+
description: value_or_empty_string(feature.description),
|
245
260
|
line: feature.location.line
|
246
261
|
}
|
247
|
-
|
248
|
-
|
249
|
-
@test_case_hash[:tags] = if @test_case_hash[:tags]
|
250
|
-
@feature_hash[:tags] + @test_case_hash[:tags]
|
251
|
-
else
|
252
|
-
@feature_hash[:tags]
|
253
|
-
end
|
254
|
-
end
|
255
|
-
@feature_hash[:comments] = Formatter.create_comments_array(feature.comments) unless feature.comments.empty?
|
256
|
-
@test_case_hash[:id].insert(0, @feature_hash[:id] + ';')
|
262
|
+
return if feature.tags.empty?
|
263
|
+
@feature_hash[:tags] = create_tags_array_from_hash_array(feature.tags)
|
257
264
|
end
|
258
265
|
|
259
266
|
def background(background)
|
260
267
|
@background_hash = {
|
261
268
|
keyword: background.keyword,
|
262
|
-
name: background.
|
263
|
-
description: background.description,
|
269
|
+
name: background.name,
|
270
|
+
description: value_or_empty_string(background.description),
|
264
271
|
line: background.location.line,
|
265
272
|
type: 'background'
|
266
273
|
}
|
267
|
-
@background_hash[:comments] = Formatter.create_comments_array(background.comments) unless background.comments.empty?
|
268
274
|
end
|
269
275
|
|
270
|
-
def scenario(
|
276
|
+
def scenario(scenario_source, test_case)
|
277
|
+
scenario = scenario_source.type == :Scenario ? scenario_source.scenario : scenario_source.scenario_outline
|
271
278
|
@test_case_hash = {
|
272
|
-
id:
|
279
|
+
id: "#{@feature_hash[:id]};#{create_id_from_scenario_source(scenario_source)}",
|
273
280
|
keyword: scenario.keyword,
|
274
|
-
name:
|
275
|
-
description: scenario.description,
|
276
|
-
line:
|
281
|
+
name: test_case.name,
|
282
|
+
description: value_or_empty_string(scenario.description),
|
283
|
+
line: test_case.location.lines.max,
|
277
284
|
type: 'scenario'
|
278
285
|
}
|
279
|
-
@test_case_hash[:tags] =
|
280
|
-
@test_case_hash[:comments] = Formatter.create_comments_array(scenario.comments) unless scenario.comments.empty?
|
286
|
+
@test_case_hash[:tags] = create_tags_array_from_tags_array(test_case.tags) unless test_case.tags.empty?
|
281
287
|
end
|
282
288
|
|
283
|
-
|
284
|
-
@test_case_hash = {
|
285
|
-
id: create_id(scenario) + ';' + @example_id,
|
286
|
-
keyword: scenario.keyword,
|
287
|
-
name: scenario.to_s,
|
288
|
-
description: scenario.description,
|
289
|
-
line: @row.location.line,
|
290
|
-
type: 'scenario'
|
291
|
-
}
|
292
|
-
tags = []
|
293
|
-
tags += create_tags_array(scenario.tags) unless scenario.tags.empty?
|
294
|
-
tags += @examples_table_tags if @examples_table_tags
|
295
|
-
@test_case_hash[:tags] = tags unless tags.empty?
|
296
|
-
comments = []
|
297
|
-
comments += Formatter.create_comments_array(scenario.comments) unless scenario.comments.empty?
|
298
|
-
comments += @examples_table_comments if @examples_table_comments
|
299
|
-
comments += @row_comments if @row_comments
|
300
|
-
@test_case_hash[:comments] = comments unless comments.empty?
|
301
|
-
end
|
289
|
+
private
|
302
290
|
|
303
|
-
def
|
304
|
-
|
305
|
-
|
306
|
-
@example_id = create_id(examples_table) + ";#{@row.number + 1}"
|
291
|
+
def value_or_empty_string(value)
|
292
|
+
value.nil? ? '' : value
|
293
|
+
end
|
307
294
|
|
308
|
-
|
309
|
-
|
295
|
+
def create_id(name)
|
296
|
+
name.downcase.tr(' ', '-')
|
310
297
|
end
|
311
298
|
|
312
|
-
def
|
313
|
-
|
314
|
-
|
299
|
+
def create_id_from_scenario_source(scenario_source)
|
300
|
+
if scenario_source.type == :Scenario
|
301
|
+
create_id(scenario_source.scenario.name)
|
302
|
+
else
|
303
|
+
scenario_outline_name = scenario_source.scenario_outline.name
|
304
|
+
examples_name = scenario_source.examples.name
|
305
|
+
row_number = calculate_row_number(scenario_source)
|
306
|
+
"#{create_id(scenario_outline_name)};#{create_id(examples_name)};#{row_number}"
|
307
|
+
end
|
315
308
|
end
|
316
309
|
|
317
|
-
|
310
|
+
def calculate_row_number(scenario_source)
|
311
|
+
scenario_source.examples.table_body.each_with_index do |row, index|
|
312
|
+
return index + 2 if row == scenario_source.row
|
313
|
+
end
|
314
|
+
end
|
318
315
|
|
319
|
-
def
|
320
|
-
|
316
|
+
def create_tags_array_from_hash_array(tags)
|
317
|
+
tags_array = []
|
318
|
+
tags.each { |tag| tags_array << { name: tag.name, line: tag.location.line } }
|
319
|
+
tags_array
|
321
320
|
end
|
322
321
|
|
323
|
-
def
|
322
|
+
def create_tags_array_from_tags_array(tags)
|
324
323
|
tags_array = []
|
325
324
|
tags.each { |tag| tags_array << { name: tag.name, line: tag.location.line } }
|
326
325
|
tags_array
|
327
326
|
end
|
328
327
|
end
|
329
328
|
end
|
330
|
-
|
331
|
-
def self.create_comments_array(comments)
|
332
|
-
comments_array = []
|
333
|
-
comments.each { |comment| comments_array << { value: comment.to_s.strip, line: comment.location.line } }
|
334
|
-
comments_array
|
335
|
-
end
|
336
329
|
end
|
337
330
|
end
|