cucumber 7.1.0 → 8.0.0.rc.1
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 +4 -4
- data/CHANGELOG.md +79 -1
- data/CONTRIBUTING.md +2 -6
- data/README.md +4 -7
- data/lib/autotest/cucumber_mixin.rb +5 -2
- data/lib/autotest/discover.rb +3 -2
- data/lib/cucumber/cli/configuration.rb +4 -1
- data/lib/cucumber/cli/main.rb +4 -3
- data/lib/cucumber/cli/options.rb +8 -2
- data/lib/cucumber/cli/profile_loader.rb +1 -5
- data/lib/cucumber/cli/rerun_file.rb +1 -1
- data/lib/cucumber/configuration.rb +5 -4
- data/lib/cucumber/constantize.rb +1 -1
- data/lib/cucumber/deprecate.rb +2 -1
- data/lib/cucumber/errors.rb +1 -1
- data/lib/cucumber/events/hook_test_step_created.rb +1 -2
- data/lib/cucumber/events/step_activated.rb +0 -6
- data/lib/cucumber/events/step_definition_registered.rb +0 -5
- data/lib/cucumber/events/test_case_created.rb +1 -2
- data/lib/cucumber/events/test_run_finished.rb +2 -1
- data/lib/cucumber/events/test_step_created.rb +1 -2
- data/lib/cucumber/events/undefined_parameter_type.rb +1 -2
- data/lib/cucumber/events.rb +1 -1
- data/lib/cucumber/file_specs.rb +2 -1
- data/lib/cucumber/filters/activate_steps.rb +1 -0
- data/lib/cucumber/filters/tag_limits/verifier.rb +1 -3
- data/lib/cucumber/filters/tag_limits.rb +1 -3
- data/lib/cucumber/formatter/ansicolor.rb +63 -63
- data/lib/cucumber/formatter/ast_lookup.rb +2 -2
- data/lib/cucumber/formatter/backtrace_filter.rb +1 -1
- data/lib/cucumber/formatter/console.rb +10 -2
- data/lib/cucumber/formatter/console_issues.rb +6 -1
- data/lib/cucumber/formatter/duration_extractor.rb +1 -0
- data/lib/cucumber/formatter/errors.rb +1 -0
- data/lib/cucumber/formatter/fanout.rb +1 -1
- data/lib/cucumber/formatter/http_io.rb +6 -1
- data/lib/cucumber/formatter/ignore_missing_messages.rb +1 -1
- data/lib/cucumber/formatter/io.rb +3 -1
- data/lib/cucumber/formatter/json.rb +8 -6
- data/lib/cucumber/formatter/junit.rb +6 -3
- data/lib/cucumber/formatter/message_builder.rb +3 -2
- data/lib/cucumber/formatter/pretty.rb +15 -5
- data/lib/cucumber/formatter/progress.rb +1 -0
- data/lib/cucumber/formatter/query/hook_by_test_step.rb +1 -0
- data/lib/cucumber/formatter/query/test_case_started_by_test_case.rb +2 -0
- data/lib/cucumber/formatter/rerun.rb +2 -0
- data/lib/cucumber/formatter/summary.rb +1 -0
- data/lib/cucumber/formatter/unicode.rb +4 -4
- data/lib/cucumber/formatter/usage.rb +3 -3
- data/lib/cucumber/gherkin/data_table_parser.rb +1 -0
- data/lib/cucumber/gherkin/formatter/ansi_escapes.rb +2 -2
- data/lib/cucumber/glue/dsl.rb +4 -9
- data/lib/cucumber/glue/hook.rb +2 -1
- data/lib/cucumber/glue/invoke_in_world.rb +4 -4
- data/lib/cucumber/glue/proto_world.rb +10 -9
- data/lib/cucumber/glue/registry_and_more.rb +4 -18
- data/lib/cucumber/glue/step_definition.rb +6 -3
- data/lib/cucumber/hooks.rb +1 -0
- data/lib/cucumber/multiline_argument/data_table/diff_matrices.rb +2 -1
- data/lib/cucumber/multiline_argument/data_table.rb +58 -71
- data/lib/cucumber/platform.rb +2 -2
- data/lib/cucumber/rake/task.rb +10 -7
- data/lib/cucumber/rspec/disable_option_parser.rb +6 -3
- data/lib/cucumber/running_test_case.rb +1 -0
- data/lib/cucumber/runtime/meta_message_builder.rb +106 -0
- data/lib/cucumber/runtime/support_code.rb +3 -0
- data/lib/cucumber/runtime/user_interface.rb +5 -4
- data/lib/cucumber/runtime.rb +21 -37
- data/lib/cucumber/step_match.rb +5 -3
- data/lib/cucumber/step_match_search.rb +3 -2
- data/lib/cucumber/term/ansicolor.rb +74 -50
- data/lib/cucumber/term/banner.rb +1 -0
- data/lib/cucumber/version +1 -1
- data/lib/cucumber.rb +2 -1
- data/lib/simplecov_setup.rb +1 -1
- metadata +74 -73
@@ -15,11 +15,13 @@ module Cucumber
|
|
15
15
|
|
16
16
|
def attempt_by_test_case(test_case)
|
17
17
|
raise TestCaseUnknownError, "No test case found for #{test_case.id} }. Known: #{@attempts_by_test_case_id.keys}" unless @attempts_by_test_case_id.key?(test_case.id)
|
18
|
+
|
18
19
|
@attempts_by_test_case_id[test_case.id]
|
19
20
|
end
|
20
21
|
|
21
22
|
def test_case_started_id_by_test_case(test_case)
|
22
23
|
raise TestCaseUnknownError, "No test case found for #{test_case.id} }. Known: #{@test_case_started_id_by_test_case_id.keys}" unless @test_case_started_id_by_test_case_id.key?(test_case.id)
|
24
|
+
|
23
25
|
@test_case_started_id_by_test_case_id[test_case.id]
|
24
26
|
end
|
25
27
|
|
@@ -15,6 +15,7 @@ module Cucumber
|
|
15
15
|
test_case, result = *event.attributes
|
16
16
|
if @config.strict.strict?(:flaky)
|
17
17
|
next if result.ok?(@config.strict)
|
18
|
+
|
18
19
|
add_to_failures(test_case)
|
19
20
|
else
|
20
21
|
unless @latest_failed_test_case.nil?
|
@@ -31,6 +32,7 @@ module Cucumber
|
|
31
32
|
config.on_event :test_run_finished do
|
32
33
|
add_to_failures(@latest_failed_test_case) unless @latest_failed_test_case.nil?
|
33
34
|
next if @failures.empty?
|
35
|
+
|
34
36
|
@io.print file_failures.join("\n")
|
35
37
|
end
|
36
38
|
end
|
@@ -17,7 +17,7 @@ if Cucumber::WINDOWS
|
|
17
17
|
end
|
18
18
|
else
|
19
19
|
Cucumber::CODEPAGE = 'cp1252'.freeze
|
20
|
-
|
20
|
+
$stderr.puts("WARNING: Couldn't detect your output codepage. Assuming it is 1252. You may have to chcp 1252 or SET CUCUMBER_OUTPUT_ENCODING=cp1252.")
|
21
21
|
end
|
22
22
|
|
23
23
|
module Cucumber
|
@@ -28,7 +28,7 @@ if Cucumber::WINDOWS
|
|
28
28
|
def cucumber_preprocess_output(*out)
|
29
29
|
out.map { |arg| arg.to_s.encode(Encoding.default_external) }
|
30
30
|
rescue Encoding::UndefinedConversionError => e
|
31
|
-
|
31
|
+
$stderr.cucumber_puts("WARNING: #{e.message}")
|
32
32
|
out
|
33
33
|
end
|
34
34
|
|
@@ -45,8 +45,8 @@ if Cucumber::WINDOWS
|
|
45
45
|
end
|
46
46
|
|
47
47
|
Kernel.extend(self)
|
48
|
-
|
49
|
-
|
48
|
+
$stdout.extend(self)
|
49
|
+
$stderr.extend(self)
|
50
50
|
end
|
51
51
|
end
|
52
52
|
end
|
@@ -78,7 +78,7 @@ module Cucumber
|
|
78
78
|
if @stepdef_to_match[stepdef_key].any?
|
79
79
|
print_steps(stepdef_key)
|
80
80
|
else
|
81
|
-
@io.puts(
|
81
|
+
@io.puts(" #{format_string('NOT MATCHED BY ANY STEPS', :failed)}")
|
82
82
|
end
|
83
83
|
end
|
84
84
|
@io.puts
|
@@ -86,7 +86,7 @@ module Cucumber
|
|
86
86
|
end
|
87
87
|
|
88
88
|
def print_step_definition(stepdef_key)
|
89
|
-
@io.print format_string(format('%<duration>.7f', duration: stepdef_key.mean_duration), :skipped)
|
89
|
+
@io.print "#{format_string(format('%<duration>.7f', duration: stepdef_key.mean_duration), :skipped)} " unless config.dry_run?
|
90
90
|
@io.print format_string(stepdef_key.regexp_source, stepdef_key.status)
|
91
91
|
if config.source?
|
92
92
|
indent_amount = max_length - stepdef_key.regexp_source.unpack('U*').length
|
@@ -99,7 +99,7 @@ module Cucumber
|
|
99
99
|
def print_steps(stepdef_key)
|
100
100
|
@stepdef_to_match[stepdef_key].each do |step|
|
101
101
|
@io.print ' '
|
102
|
-
@io.print format_string(format('%<duration>.7f', duration: step[:duration]), :skipped)
|
102
|
+
@io.print "#{format_string(format('%<duration>.7f', duration: step[:duration]), :skipped)} " unless config.dry_run?
|
103
103
|
@io.print format_step(step[:keyword], step[:step_match], step[:status], nil)
|
104
104
|
if config.source?
|
105
105
|
indent_amount = max_length - (step[:keyword].unpack('U*').length + step[:step_match].format_args.unpack('U*').length)
|
@@ -54,7 +54,7 @@ module Cucumber
|
|
54
54
|
}.freeze
|
55
55
|
|
56
56
|
ALIASES = Hash.new do |h, k|
|
57
|
-
h[Regexp.last_match(1)]
|
57
|
+
"#{h[Regexp.last_match(1)]},bold" if k.to_s =~ /(.*)_arg/
|
58
58
|
end.merge(
|
59
59
|
'undefined' => 'yellow',
|
60
60
|
'pending' => 'yellow',
|
@@ -74,7 +74,7 @@ module Cucumber
|
|
74
74
|
end
|
75
75
|
end
|
76
76
|
|
77
|
-
ALIASES.
|
77
|
+
ALIASES.each_key do |key|
|
78
78
|
define_method(key) do
|
79
79
|
ALIASES[key].split(',').map { |color| COLORS[color] }.join('')
|
80
80
|
end
|
data/lib/cucumber/glue/dsl.rb
CHANGED
@@ -107,14 +107,6 @@ module Cucumber
|
|
107
107
|
value.nil? ? default : value
|
108
108
|
end
|
109
109
|
|
110
|
-
# Registers a proc that will run after Cucumber is configured. You can register as
|
111
|
-
# as you want (typically from ruby scripts under <tt>support/hooks.rb</tt>).
|
112
|
-
#
|
113
|
-
# DEPRECATED: please use InstallPlugin or BeforeAll instead
|
114
|
-
def AfterConfiguration(&proc)
|
115
|
-
Dsl.register_rb_hook('after_configuration', [], proc)
|
116
|
-
end
|
117
|
-
|
118
110
|
# Registers a proc that will run after Cucumber is configured in order to install an external plugin.
|
119
111
|
def InstallPlugin(&proc)
|
120
112
|
Dsl.register_rb_hook('install_plugin', [], proc)
|
@@ -155,5 +147,8 @@ module Cucumber
|
|
155
147
|
end
|
156
148
|
end
|
157
149
|
|
158
|
-
#
|
150
|
+
# rubocop:disable Style/MixinUsage
|
151
|
+
# This "should" always be present, because it allows users to write `Before` and `After`
|
152
|
+
# See. https://github.com/cucumber/cucumber-ruby/pull/1566#discussion_r683235396
|
159
153
|
extend(Cucumber::Glue::Dsl)
|
154
|
+
# rubocop:enable Style/MixinUsage
|
data/lib/cucumber/glue/hook.rb
CHANGED
@@ -32,7 +32,7 @@ module Cucumber
|
|
32
32
|
Cucumber::Messages::Envelope.new(
|
33
33
|
hook: Cucumber::Messages::Hook.new(
|
34
34
|
id: id,
|
35
|
-
tag_expression: tag_expressions.join(' '),
|
35
|
+
tag_expression: tag_expressions.empty? ? nil : tag_expressions.join(' '),
|
36
36
|
source_reference: Cucumber::Messages::SourceReference.new(
|
37
37
|
uri: location.file,
|
38
38
|
location: Cucumber::Messages::Location.new(
|
@@ -58,6 +58,7 @@ module Cucumber
|
|
58
58
|
end
|
59
59
|
|
60
60
|
next unless tag_expression.include?(',')
|
61
|
+
|
61
62
|
warn("Found tagged hook with '#{tag_expression}'." \
|
62
63
|
"'@tag1,@tag2' is no longer supported, use '@tag or @tag2' instead.")
|
63
64
|
end
|
@@ -12,6 +12,7 @@ module Cucumber
|
|
12
12
|
|
13
13
|
instance_exec_pos = backtrace.index(instance_exec_invocation_line)
|
14
14
|
return unless instance_exec_pos
|
15
|
+
|
15
16
|
replacement_line = instance_exec_pos + INSTANCE_EXEC_OFFSET
|
16
17
|
backtrace[replacement_line].gsub!(/`.*'/, "`#{pseudo_method}'") if pseudo_method
|
17
18
|
|
@@ -27,7 +28,7 @@ module Cucumber
|
|
27
28
|
if check_arity && !cucumber_compatible_arity?(args, block)
|
28
29
|
world.instance_exec do
|
29
30
|
ari = block.arity
|
30
|
-
ari = ari < 0 ?
|
31
|
+
ari = ari < 0 ? "#{ari.abs - 1}+" : ari
|
31
32
|
s1 = ari == 1 ? '' : 's'
|
32
33
|
s2 = args.length == 1 ? '' : 's'
|
33
34
|
raise ArityMismatchError, "Your block takes #{ari} argument#{s1}, but the Regexp matched #{args.length} argument#{s2}."
|
@@ -40,9 +41,8 @@ module Cucumber
|
|
40
41
|
|
41
42
|
def self.cucumber_compatible_arity?(args, block)
|
42
43
|
return true if block.arity == args.length
|
43
|
-
if block.arity
|
44
|
-
|
45
|
-
end
|
44
|
+
return true if block.arity.negative? && args.length >= (block.arity.abs - 1)
|
45
|
+
|
46
46
|
false
|
47
47
|
end
|
48
48
|
|
@@ -138,8 +138,8 @@ module Cucumber
|
|
138
138
|
# TODO: pass these in when building the module, instead of mutating them later
|
139
139
|
# Extend the World with user-defined modules
|
140
140
|
def add_modules!(world_modules, namespaced_world_modules)
|
141
|
-
add_world_modules!(world_modules)
|
142
|
-
add_namespaced_modules!(namespaced_world_modules)
|
141
|
+
add_world_modules!(world_modules) if world_modules.any?
|
142
|
+
add_namespaced_modules!(namespaced_world_modules) if namespaced_world_modules.any?
|
143
143
|
end
|
144
144
|
|
145
145
|
define_method(:step) do |name, raw_multiline_arg = nil|
|
@@ -185,14 +185,13 @@ module Cucumber
|
|
185
185
|
modules.each do |namespace, world_modules|
|
186
186
|
world_modules.each do |world_module|
|
187
187
|
variable_name = "@__#{namespace}_world"
|
188
|
+
inner_world = instance_variable_get(variable_name) || Object.new
|
189
|
+
|
190
|
+
instance_variable_set(
|
191
|
+
variable_name,
|
192
|
+
inner_world.extend(world_module)
|
193
|
+
)
|
188
194
|
|
189
|
-
inner_world = if self.class.respond_to?(namespace)
|
190
|
-
instance_variable_get(variable_name)
|
191
|
-
else
|
192
|
-
Object.new
|
193
|
-
end
|
194
|
-
instance_variable_set(variable_name,
|
195
|
-
inner_world.extend(world_module))
|
196
195
|
self.class.send(:define_method, namespace) do
|
197
196
|
instance_variable_get(variable_name)
|
198
197
|
end
|
@@ -202,6 +201,8 @@ module Cucumber
|
|
202
201
|
|
203
202
|
# @private
|
204
203
|
def stringify_namespaced_modules
|
204
|
+
return '' if @__namespaced_modules.nil?
|
205
|
+
|
205
206
|
@__namespaced_modules.map { |k, v| "#{v.join(',')} (as #{k})" }.join('+')
|
206
207
|
end
|
207
208
|
end
|
@@ -92,7 +92,7 @@ module Cucumber
|
|
92
92
|
step_definition
|
93
93
|
rescue Cucumber::CucumberExpressions::UndefinedParameterTypeError => e
|
94
94
|
# TODO: add a way to extract the parameter type directly from the error.
|
95
|
-
type_name = e.message.match(/^Undefined parameter type ['
|
95
|
+
type_name = e.message.match(/^Undefined parameter type ['|{](.*)['|}].?$/)[1]
|
96
96
|
|
97
97
|
@configuration.notify :undefined_parameter_type, type_name, string_or_regexp
|
98
98
|
end
|
@@ -100,6 +100,7 @@ module Cucumber
|
|
100
100
|
def build_rb_world_factory(world_modules, namespaced_world_modules, proc)
|
101
101
|
if proc
|
102
102
|
raise MultipleWorld.new(@world_proc, proc) if @world_proc
|
103
|
+
|
103
104
|
@world_proc = proc
|
104
105
|
end
|
105
106
|
@world_modules ||= []
|
@@ -135,14 +136,6 @@ module Cucumber
|
|
135
136
|
@current_world = nil
|
136
137
|
end
|
137
138
|
|
138
|
-
def after_configuration(configuration)
|
139
|
-
deprecate_after_configuration_hook if hooks[:after_configuration].any?
|
140
|
-
|
141
|
-
hooks[:after_configuration].each do |hook|
|
142
|
-
hook.invoke('AfterConfiguration', configuration)
|
143
|
-
end
|
144
|
-
end
|
145
|
-
|
146
139
|
def install_plugin(configuration, registry)
|
147
140
|
hooks[:install_plugin].each do |hook|
|
148
141
|
hook.invoke('InstallPlugin', [configuration, registry])
|
@@ -170,7 +163,7 @@ module Cucumber
|
|
170
163
|
@hooks = nil
|
171
164
|
end
|
172
165
|
|
173
|
-
def hooks_for(phase, scenario)
|
166
|
+
def hooks_for(phase, scenario) # :nodoc:
|
174
167
|
hooks[phase.to_sym].select { |hook| scenario.accept_hook?(hook) }
|
175
168
|
end
|
176
169
|
|
@@ -189,6 +182,7 @@ module Cucumber
|
|
189
182
|
def create_expression(string_or_regexp)
|
190
183
|
return CucumberExpressions::CucumberExpression.new(string_or_regexp, @parameter_type_registry) if string_or_regexp.is_a?(String)
|
191
184
|
return CucumberExpressions::RegularExpression.new(string_or_regexp, @parameter_type_registry) if string_or_regexp.is_a?(Regexp)
|
185
|
+
|
192
186
|
raise ArgumentError, 'Expression must be a String or Regexp'
|
193
187
|
end
|
194
188
|
|
@@ -228,14 +222,6 @@ module Cucumber
|
|
228
222
|
def hooks
|
229
223
|
@hooks ||= Hash.new { |h, k| h[k] = [] }
|
230
224
|
end
|
231
|
-
|
232
|
-
def deprecate_after_configuration_hook
|
233
|
-
Cucumber.deprecate(
|
234
|
-
'See https://github.com/cucumber/cucumber-ruby/blob/main/UPGRADING.md#upgrading-to-710 for more info',
|
235
|
-
' AfterConfiguration hook',
|
236
|
-
'8.0.0'
|
237
|
-
)
|
238
|
-
end
|
239
225
|
end
|
240
226
|
|
241
227
|
def self.backtrace_line(proc, name)
|
@@ -25,6 +25,7 @@ module Cucumber
|
|
25
25
|
class << self
|
26
26
|
def new(id, registry, string_or_regexp, proc_or_sym, options)
|
27
27
|
raise MissingProc if proc_or_sym.nil?
|
28
|
+
|
28
29
|
super id, registry, registry.create_expression(string_or_regexp), create_proc(proc_or_sym, options)
|
29
30
|
end
|
30
31
|
|
@@ -33,6 +34,7 @@ module Cucumber
|
|
33
34
|
def create_proc(proc_or_sym, options)
|
34
35
|
return proc_or_sym if proc_or_sym.is_a?(Proc)
|
35
36
|
raise ArgumentError unless proc_or_sym.is_a?(Symbol)
|
37
|
+
|
36
38
|
message = proc_or_sym
|
37
39
|
target_proc = parse_target_proc_from(options)
|
38
40
|
patch_location_onto lambda { |*args|
|
@@ -49,6 +51,7 @@ module Cucumber
|
|
49
51
|
|
50
52
|
def parse_target_proc_from(options)
|
51
53
|
return -> { self } unless options.key?(:on)
|
54
|
+
|
52
55
|
target = options[:on]
|
53
56
|
case target
|
54
57
|
when Proc
|
@@ -65,6 +68,7 @@ module Cucumber
|
|
65
68
|
|
66
69
|
def initialize(id, registry, expression, proc)
|
67
70
|
raise 'No regexp' if expression.is_a?(Regexp)
|
71
|
+
|
68
72
|
@id = id
|
69
73
|
@registry = registry
|
70
74
|
@expression = expression
|
@@ -92,6 +96,7 @@ module Cucumber
|
|
92
96
|
|
93
97
|
def expression_type
|
94
98
|
return Cucumber::Messages::StepDefinitionPatternType::CUCUMBER_EXPRESSION if expression.is_a?(CucumberExpressions::CucumberExpression)
|
99
|
+
|
95
100
|
Cucumber::Messages::StepDefinitionPatternType::REGULAR_EXPRESSION
|
96
101
|
end
|
97
102
|
|
@@ -122,9 +127,7 @@ module Cucumber
|
|
122
127
|
|
123
128
|
# @api private
|
124
129
|
def arguments_from(step_name)
|
125
|
-
|
126
|
-
# @registry.invoked_step_definition(regexp_source, location) if args
|
127
|
-
args
|
130
|
+
@expression.match(step_name)
|
128
131
|
end
|
129
132
|
|
130
133
|
# @api private
|
data/lib/cucumber/hooks.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
module Cucumber
|
2
2
|
module MultilineArgument
|
3
3
|
class DataTable
|
4
|
-
class DiffMatrices
|
4
|
+
class DiffMatrices # :nodoc:
|
5
5
|
attr_accessor :cell_matrix, :other_table_cell_matrix, :options
|
6
6
|
|
7
7
|
def initialize(cell_matrix, other_table_cell_matrix, options)
|
@@ -113,6 +113,7 @@ module Cucumber
|
|
113
113
|
row_index = row_indices.index(i)
|
114
114
|
row = cell_matrix[row_index] if row_index
|
115
115
|
next unless row
|
116
|
+
|
116
117
|
(original_width..padded_width).each do |col_index|
|
117
118
|
surplus_cell = other_row[col_index]
|
118
119
|
row[col_index].value = surplus_cell.value if row[col_index]
|