cucumber 2.0.0.beta.3 → 2.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 +4 -4
- data/.travis.yml +3 -3
- data/History.md +131 -32
- data/Rakefile +0 -2
- data/cucumber.gemspec +4 -3
- data/examples/i18n/ht/Rakefile +6 -0
- data/examples/i18n/ht/features/adisyon.feature +17 -0
- data/examples/i18n/ht/features/divizyon.feature +10 -0
- data/examples/i18n/ht/features/step_definitions/kalkilatris_steps.rb +25 -0
- data/examples/i18n/ht/lib/kalkilatris.rb +14 -0
- data/examples/tcl/features/step_definitions/fib_steps.rb +1 -1
- data/features/docs/cli/dry_run.feature +48 -0
- data/features/docs/cli/exclude_files.feature +1 -2
- data/features/docs/cli/run_specific_scenarios.feature +28 -66
- data/features/docs/cli/strict_mode.feature +24 -1
- data/features/docs/defining_steps/nested_steps.feature +49 -0
- data/features/docs/defining_steps/skip_scenario.feature +31 -2
- data/features/docs/defining_steps/snippets.feature +15 -0
- data/features/docs/exception_in_after_step_hook.feature +1 -1
- data/features/docs/exception_in_around_hook.feature +80 -0
- data/features/docs/extending_cucumber/custom_filter.feature +29 -0
- data/features/docs/extending_cucumber/custom_formatter.feature +65 -7
- data/features/docs/formatters/debug_formatter.feature +24 -17
- data/features/docs/formatters/json_formatter.feature +65 -1
- data/features/docs/formatters/junit_formatter.feature +40 -0
- data/features/docs/formatters/pretty_formatter.feature +42 -0
- data/features/docs/formatters/rerun_formatter.feature +3 -2
- data/features/docs/getting_started.feature +1 -1
- data/features/docs/{wire_protocol_erb.feature → wire_protocol/erb_configuration.feature} +2 -2
- data/features/docs/wire_protocol/handle_unexpected_response.feature +30 -0
- data/features/docs/wire_protocol/invoke_message.feature +216 -0
- data/features/docs/wire_protocol/readme.md +26 -0
- data/features/docs/wire_protocol/snippets_message.feature +51 -0
- data/features/docs/wire_protocol/step_matches_message.feature +81 -0
- data/features/docs/{wire_protocol_table_diffing.feature → wire_protocol/table_diffing.feature} +1 -0
- data/features/docs/{wire_protocol_tags.feature → wire_protocol/tags.feature} +1 -0
- data/features/docs/{wire_protocol_timeouts.feature → wire_protocol/timeouts.feature} +1 -0
- data/features/docs/work_in_progress.feature +1 -1
- data/features/docs/writing_support_code/after_hooks.feature +24 -0
- data/features/docs/writing_support_code/around_hooks.feature +31 -0
- data/features/docs/writing_support_code/before_hook.feature +7 -3
- data/features/docs/writing_support_code/tagged_hooks.feature +44 -6
- data/features/lib/step_definitions/wire_steps.rb +18 -1
- data/features/lib/support/fake_wire_server.rb +10 -7
- data/lib/cucumber/cli/configuration.rb +6 -11
- data/lib/cucumber/cli/main.rb +2 -2
- data/lib/cucumber/cli/options.rb +8 -1
- data/lib/cucumber/cli/profile_loader.rb +1 -1
- data/lib/cucumber/core_ext/instance_exec.rb +1 -1
- data/lib/cucumber/encoding.rb +5 -0
- data/lib/cucumber/errors.rb +8 -0
- data/lib/cucumber/file_specs.rb +3 -1
- data/lib/cucumber/filters/activate_steps.rb +33 -0
- data/lib/cucumber/filters/apply_after_hooks.rb +9 -0
- data/lib/cucumber/filters/apply_after_step_hooks.rb +12 -0
- data/lib/cucumber/filters/apply_around_hooks.rb +12 -0
- data/lib/cucumber/filters/apply_before_hooks.rb +9 -0
- data/lib/cucumber/{runtime → filters}/gated_receiver.rb +5 -1
- data/lib/cucumber/filters/prepare_world.rb +45 -0
- data/lib/cucumber/filters/quit.rb +28 -0
- data/lib/cucumber/filters/randomizer.rb +40 -0
- data/lib/cucumber/{runtime → filters}/tag_limits/test_case_index.rb +4 -2
- data/lib/cucumber/{runtime → filters}/tag_limits/verifier.rb +4 -2
- data/lib/cucumber/filters/tag_limits.rb +45 -0
- data/lib/cucumber/filters.rb +9 -0
- data/lib/cucumber/formatter/ansicolor.rb +0 -8
- data/lib/cucumber/formatter/console.rb +37 -20
- data/lib/cucumber/formatter/debug.rb +1 -8
- data/lib/cucumber/formatter/fanout.rb +27 -0
- data/lib/cucumber/formatter/gherkin_formatter_adapter.rb +10 -9
- data/lib/cucumber/formatter/html.rb +31 -6
- data/lib/cucumber/formatter/ignore_missing_messages.rb +20 -0
- data/lib/cucumber/formatter/junit.rb +97 -2
- data/lib/cucumber/formatter/legacy_api/adapter.rb +1060 -0
- data/lib/cucumber/formatter/legacy_api/ast.rb +376 -0
- data/lib/cucumber/formatter/legacy_api/results.rb +51 -0
- data/lib/cucumber/formatter/legacy_api/runtime_facade.rb +30 -0
- data/lib/cucumber/formatter/pretty.rb +14 -0
- data/lib/cucumber/formatter/progress.rb +10 -0
- data/lib/cucumber/formatter/rerun.rb +14 -88
- data/lib/cucumber/hooks.rb +97 -0
- data/lib/cucumber/language_support/language_methods.rb +0 -54
- data/lib/cucumber/multiline_argument/data_table.rb +41 -29
- data/lib/cucumber/platform.rb +3 -3
- data/lib/cucumber/project_initializer.rb +43 -0
- data/lib/cucumber/rb_support/rb_hook.rb +2 -2
- data/lib/cucumber/rb_support/rb_step_definition.rb +11 -2
- data/lib/cucumber/rb_support/rb_transform.rb +3 -1
- data/lib/cucumber/rb_support/rb_world.rb +2 -2
- data/lib/cucumber/rb_support/snippet.rb +1 -1
- data/lib/cucumber/rspec/doubles.rb +1 -1
- data/lib/cucumber/running_test_case.rb +115 -0
- data/lib/cucumber/runtime/after_hooks.rb +24 -0
- data/lib/cucumber/runtime/before_hooks.rb +23 -0
- data/lib/cucumber/runtime/for_programming_languages.rb +4 -8
- data/lib/cucumber/runtime/step_hooks.rb +22 -0
- data/lib/cucumber/runtime/support_code.rb +70 -5
- data/lib/cucumber/runtime.rb +56 -112
- data/lib/cucumber/step_match.rb +26 -2
- data/lib/cucumber.rb +7 -3
- data/spec/cucumber/cli/configuration_spec.rb +16 -1
- data/spec/cucumber/cli/profile_loader_spec.rb +10 -0
- data/spec/cucumber/core_ext/instance_exec_spec.rb +4 -0
- data/spec/cucumber/file_specs_spec.rb +21 -2
- data/spec/cucumber/filters/activate_steps_spec.rb +57 -0
- data/spec/cucumber/{runtime → filters}/gated_receiver_spec.rb +3 -3
- data/spec/cucumber/{runtime → filters}/tag_limits/test_case_index_spec.rb +3 -3
- data/spec/cucumber/{runtime → filters}/tag_limits/verifier_spec.rb +4 -4
- data/spec/cucumber/{runtime/tag_limits/filter_spec.rb → filters/tag_limits_spec.rb} +6 -6
- data/spec/cucumber/formatter/debug_spec.rb +25 -530
- data/spec/cucumber/formatter/html_spec.rb +140 -0
- data/spec/cucumber/formatter/junit_spec.rb +212 -156
- data/spec/cucumber/formatter/legacy_api/adapter_spec.rb +2090 -0
- data/spec/cucumber/formatter/pretty_spec.rb +248 -2
- data/spec/cucumber/formatter/rerun_spec.rb +107 -0
- data/spec/cucumber/formatter/spec_helper.rb +17 -8
- data/spec/cucumber/hooks_spec.rb +30 -0
- data/spec/cucumber/multiline_argument/data_table_spec.rb +53 -47
- data/spec/cucumber/project_initializer_spec.rb +87 -0
- data/spec/cucumber/rb_support/rb_language_spec.rb +2 -2
- data/spec/cucumber/rb_support/rb_step_definition_spec.rb +32 -7
- data/spec/cucumber/rb_support/rb_transform_spec.rb +20 -0
- data/spec/cucumber/rb_support/snippet_spec.rb +6 -6
- data/spec/cucumber/running_test_case_spec.rb +83 -0
- data/spec/cucumber/runtime_spec.rb +1 -5
- data/spec/spec_helper.rb +3 -4
- metadata +149 -107
- data/bin/cuke +0 -60
- data/features/docs/extending_cucumber/formatter_callbacks.feature +0 -370
- data/features/docs/output_from_hooks.feature +0 -128
- data/features/docs/report_called_undefined_steps.feature +0 -57
- data/features/docs/wire_protocol.feature +0 -337
- data/gem_tasks/yard/default/layout/html/bubble_32x32.png +0 -0
- data/gem_tasks/yard/default/layout/html/footer.erb +0 -5
- data/gem_tasks/yard/default/layout/html/index.erb +0 -1
- data/gem_tasks/yard/default/layout/html/layout.erb +0 -25
- data/gem_tasks/yard/default/layout/html/logo.erb +0 -1
- data/gem_tasks/yard/default/layout/html/setup.rb +0 -4
- data/gem_tasks/yard.rake +0 -43
- data/lib/cucumber/mappings.rb +0 -238
- data/lib/cucumber/reports/legacy_formatter.rb +0 -1349
- data/lib/cucumber/runtime/results.rb +0 -64
- data/lib/cucumber/runtime/tag_limits/filter.rb +0 -31
- data/lib/cucumber/runtime/tag_limits.rb +0 -15
- data/spec/cucumber/mappings_spec.rb +0 -180
- data/spec/cucumber/reports/legacy_formatter_spec.rb +0 -1860
- data/spec/cucumber/runtime/results_spec.rb +0 -88
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
require 'cucumber/constantize'
|
|
2
2
|
require 'cucumber/runtime/for_programming_languages'
|
|
3
|
+
require 'cucumber/runtime/step_hooks'
|
|
4
|
+
require 'cucumber/runtime/before_hooks'
|
|
5
|
+
require 'cucumber/runtime/after_hooks'
|
|
3
6
|
|
|
4
7
|
module Cucumber
|
|
5
8
|
|
|
@@ -7,7 +10,6 @@ module Cucumber
|
|
|
7
10
|
|
|
8
11
|
class SupportCode
|
|
9
12
|
|
|
10
|
-
# TODO: figure out a way to move this to the core. We'd need to have access to the mappings to pass those in.
|
|
11
13
|
require 'forwardable'
|
|
12
14
|
class StepInvoker
|
|
13
15
|
include Gherkin::Rubify
|
|
@@ -21,7 +23,7 @@ module Cucumber
|
|
|
21
23
|
|
|
22
24
|
def step(step)
|
|
23
25
|
location = Core::Ast::Location.of_caller
|
|
24
|
-
@support_code.
|
|
26
|
+
@support_code.invoke_dynamic_step(step.name, multiline_arg(step, location))
|
|
25
27
|
end
|
|
26
28
|
|
|
27
29
|
def eof
|
|
@@ -56,14 +58,24 @@ module Cucumber
|
|
|
56
58
|
# Given I have 8 cukes in my belly
|
|
57
59
|
# Then I should not be thirsty
|
|
58
60
|
# })
|
|
59
|
-
def
|
|
61
|
+
def invoke_dynamic_steps(steps_text, i18n, file_colon_line)
|
|
60
62
|
file, line = file_colon_line.split(':')
|
|
61
63
|
parser = Gherkin::Parser::Parser.new(StepInvoker.new(self), true, 'steps', false, i18n.iso_code)
|
|
62
64
|
parser.parse(steps_text, file, line.to_i)
|
|
63
65
|
end
|
|
64
66
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
+
# @api private
|
|
68
|
+
# This allows users to attempt to find, match and execute steps
|
|
69
|
+
# from code as the features are running, as opposed to regular
|
|
70
|
+
# steps which are compiled into test steps before execution.
|
|
71
|
+
#
|
|
72
|
+
# These are commonly called nested steps.
|
|
73
|
+
def invoke_dynamic_step(step_name, multiline_argument, location=nil)
|
|
74
|
+
begin
|
|
75
|
+
step_match(step_name).invoke(multiline_argument)
|
|
76
|
+
rescue Undefined => exception
|
|
77
|
+
raise UndefinedDynamicStep, step_name
|
|
78
|
+
end
|
|
67
79
|
end
|
|
68
80
|
|
|
69
81
|
# Loads and registers programming language implementation.
|
|
@@ -121,6 +133,59 @@ module Cucumber
|
|
|
121
133
|
end.flatten
|
|
122
134
|
end
|
|
123
135
|
|
|
136
|
+
def find_match(test_step)
|
|
137
|
+
begin
|
|
138
|
+
match = step_match(test_step.name)
|
|
139
|
+
rescue Cucumber::Undefined
|
|
140
|
+
return NoStepMatch.new(test_step.source.last, test_step.name)
|
|
141
|
+
end
|
|
142
|
+
if @configuration.dry_run?
|
|
143
|
+
return SkippingStepMatch.new
|
|
144
|
+
end
|
|
145
|
+
match
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
def find_after_step_hooks(test_case)
|
|
149
|
+
ruby = load_programming_language('rb')
|
|
150
|
+
scenario = RunningTestCase.new(test_case)
|
|
151
|
+
|
|
152
|
+
action_blocks = ruby.hooks_for(:after_step, scenario).map do |hook|
|
|
153
|
+
->(*args) { hook.invoke('AfterStep', args) }
|
|
154
|
+
end
|
|
155
|
+
StepHooks.new action_blocks
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
def apply_before_hooks(test_case)
|
|
159
|
+
ruby = load_programming_language('rb')
|
|
160
|
+
scenario = RunningTestCase.new(test_case)
|
|
161
|
+
|
|
162
|
+
action_blocks = ruby.hooks_for(:before, scenario).map do |hook|
|
|
163
|
+
->(result) { hook.invoke('Before', scenario.with_result(result)) }
|
|
164
|
+
end
|
|
165
|
+
BeforeHooks.new(action_blocks).apply_to(test_case)
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
def apply_after_hooks(test_case)
|
|
169
|
+
ruby = load_programming_language('rb')
|
|
170
|
+
scenario = RunningTestCase.new(test_case)
|
|
171
|
+
|
|
172
|
+
action_blocks = ruby.hooks_for(:after, scenario).map do |hook|
|
|
173
|
+
->(result) { hook.invoke('After', scenario.with_result(result)) }
|
|
174
|
+
end
|
|
175
|
+
AfterHooks.new(action_blocks).apply_to(test_case)
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
def find_around_hooks(test_case)
|
|
179
|
+
ruby = load_programming_language('rb')
|
|
180
|
+
scenario = RunningTestCase.new(test_case)
|
|
181
|
+
|
|
182
|
+
ruby.hooks_for(:around, scenario).map do |hook|
|
|
183
|
+
Hooks.around_hook(test_case.source) do |run_scenario|
|
|
184
|
+
hook.invoke('Around', scenario, &run_scenario)
|
|
185
|
+
end
|
|
186
|
+
end
|
|
187
|
+
end
|
|
188
|
+
|
|
124
189
|
def step_match(step_name, name_to_report=nil) #:nodoc:
|
|
125
190
|
@match_cache ||= {}
|
|
126
191
|
|
data/lib/cucumber/runtime.rb
CHANGED
|
@@ -9,6 +9,8 @@ require 'cucumber/load_path'
|
|
|
9
9
|
require 'cucumber/language_support/language_methods'
|
|
10
10
|
require 'cucumber/formatter/duration'
|
|
11
11
|
require 'cucumber/file_specs'
|
|
12
|
+
require 'cucumber/filters'
|
|
13
|
+
require 'cucumber/formatter/fanout'
|
|
12
14
|
|
|
13
15
|
module Cucumber
|
|
14
16
|
module FixRuby21Bug9285
|
|
@@ -30,14 +32,12 @@ module Cucumber
|
|
|
30
32
|
end
|
|
31
33
|
|
|
32
34
|
class FeatureFolderNotFoundException < FileException
|
|
33
|
-
include FixRuby21Bug9285 if Cucumber::RUBY_2_1
|
|
35
|
+
include FixRuby21Bug9285 if Cucumber::RUBY_2_1 || Cucumber::RUBY_2_2
|
|
34
36
|
end
|
|
35
37
|
|
|
36
38
|
require 'cucumber/core'
|
|
37
39
|
require 'cucumber/runtime/user_interface'
|
|
38
|
-
require 'cucumber/runtime/results'
|
|
39
40
|
require 'cucumber/runtime/support_code'
|
|
40
|
-
require 'cucumber/runtime/tag_limits'
|
|
41
41
|
class Runtime
|
|
42
42
|
attr_reader :results, :support_code, :configuration
|
|
43
43
|
|
|
@@ -46,17 +46,15 @@ module Cucumber
|
|
|
46
46
|
include Runtime::UserInterface
|
|
47
47
|
|
|
48
48
|
def initialize(configuration = Configuration.default)
|
|
49
|
-
@current_scenario = nil
|
|
50
49
|
@configuration = Configuration.parse(configuration)
|
|
51
50
|
@support_code = SupportCode.new(self, @configuration)
|
|
52
|
-
@results = Results.new
|
|
51
|
+
@results = Formatter::LegacyApi::Results.new
|
|
53
52
|
end
|
|
54
53
|
|
|
55
|
-
# Allows you to take an existing runtime and change
|
|
54
|
+
# Allows you to take an existing runtime and change its configuration
|
|
56
55
|
def configure(new_configuration)
|
|
57
56
|
@configuration = Configuration.parse(new_configuration)
|
|
58
57
|
@support_code.configure(@configuration)
|
|
59
|
-
@results.configure(@configuration)
|
|
60
58
|
end
|
|
61
59
|
|
|
62
60
|
def load_programming_language(language)
|
|
@@ -68,7 +66,8 @@ module Cucumber
|
|
|
68
66
|
fire_after_configuration_hook
|
|
69
67
|
self.visitor = report
|
|
70
68
|
|
|
71
|
-
|
|
69
|
+
receiver = Test::Runner.new(report)
|
|
70
|
+
compile features, receiver, filters
|
|
72
71
|
end
|
|
73
72
|
|
|
74
73
|
def features_paths
|
|
@@ -79,10 +78,6 @@ module Cucumber
|
|
|
79
78
|
@configuration.dry_run?
|
|
80
79
|
end
|
|
81
80
|
|
|
82
|
-
def step_visited(step) #:nodoc:
|
|
83
|
-
@results.step_visited(step)
|
|
84
|
-
end
|
|
85
|
-
|
|
86
81
|
def scenarios(status = nil)
|
|
87
82
|
@results.scenarios(status)
|
|
88
83
|
end
|
|
@@ -103,53 +98,12 @@ module Cucumber
|
|
|
103
98
|
@support_code.snippet_text(::Gherkin::I18n.code_keyword_for(step_keyword), step_name, multiline_arg)
|
|
104
99
|
end
|
|
105
100
|
|
|
106
|
-
def with_hooks(scenario, skip_hooks=false)
|
|
107
|
-
around(scenario, skip_hooks) do
|
|
108
|
-
before_and_after(scenario, skip_hooks) do
|
|
109
|
-
yield scenario
|
|
110
|
-
end
|
|
111
|
-
end
|
|
112
|
-
end
|
|
113
|
-
|
|
114
|
-
def around(scenario, skip_hooks=false, &block) #:nodoc:
|
|
115
|
-
if skip_hooks
|
|
116
|
-
yield
|
|
117
|
-
return
|
|
118
|
-
end
|
|
119
|
-
|
|
120
|
-
@support_code.around(scenario, block)
|
|
121
|
-
end
|
|
122
|
-
|
|
123
|
-
def before_and_after(scenario, skip_hooks=false) #:nodoc:
|
|
124
|
-
before(scenario) unless skip_hooks
|
|
125
|
-
yield scenario
|
|
126
|
-
after(scenario) unless skip_hooks
|
|
127
|
-
record_result scenario
|
|
128
|
-
end
|
|
129
|
-
|
|
130
|
-
def record_result(scenario)
|
|
131
|
-
@results.scenario_visited(scenario)
|
|
132
|
-
end
|
|
133
|
-
|
|
134
101
|
def begin_scenario(scenario)
|
|
135
102
|
@support_code.fire_hook(:begin_scenario, scenario)
|
|
136
103
|
end
|
|
137
104
|
|
|
138
|
-
def
|
|
139
|
-
|
|
140
|
-
@current_scenario = scenario
|
|
141
|
-
@support_code.fire_hook(:before, scenario)
|
|
142
|
-
end
|
|
143
|
-
|
|
144
|
-
def after(scenario) #:nodoc:
|
|
145
|
-
@current_scenario = nil
|
|
146
|
-
return if dry_run?
|
|
147
|
-
@support_code.fire_hook(:after, scenario)
|
|
148
|
-
end
|
|
149
|
-
|
|
150
|
-
def after_step #:nodoc:
|
|
151
|
-
return if dry_run?
|
|
152
|
-
@support_code.fire_hook(:execute_after_step, @current_scenario)
|
|
105
|
+
def end_scenario(scenario)
|
|
106
|
+
@support_code.fire_hook(:end_scenario)
|
|
153
107
|
end
|
|
154
108
|
|
|
155
109
|
def unknown_programming_language?
|
|
@@ -159,8 +113,7 @@ module Cucumber
|
|
|
159
113
|
# Returns Ast::DocString for +string_without_triple_quotes+.
|
|
160
114
|
#
|
|
161
115
|
def doc_string(string_without_triple_quotes, content_type='', line_offset=0)
|
|
162
|
-
|
|
163
|
-
location = Core::Ast::Location.new(file, line)
|
|
116
|
+
location = Core::Ast::Location.of_caller
|
|
164
117
|
Core::Ast::DocString.new(string_without_triple_quotes, content_type, location)
|
|
165
118
|
end
|
|
166
119
|
|
|
@@ -223,74 +176,65 @@ module Cucumber
|
|
|
223
176
|
end
|
|
224
177
|
end
|
|
225
178
|
|
|
226
|
-
require 'cucumber/
|
|
227
|
-
|
|
228
|
-
|
|
179
|
+
require 'cucumber/formatter/legacy_api/adapter'
|
|
180
|
+
require 'cucumber/formatter/legacy_api/runtime_facade'
|
|
181
|
+
require 'cucumber/formatter/legacy_api/results'
|
|
182
|
+
require 'cucumber/formatter/ignore_missing_messages'
|
|
183
|
+
require 'cucumber/core/report/summary'
|
|
184
|
+
def report
|
|
185
|
+
@report ||= Formatter::Fanout.new([summary_report] + formatters)
|
|
229
186
|
end
|
|
230
187
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
188
|
+
def summary_report
|
|
189
|
+
@summary_report ||= Core::Report::Summary.new
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
def formatters
|
|
193
|
+
@formatters ||= @configuration.formatter_factories { |factory, path_or_io, options|
|
|
194
|
+
results = Formatter::LegacyApi::Results.new
|
|
195
|
+
runtime_facade = Formatter::LegacyApi::RuntimeFacade.new(results, @support_code, @configuration)
|
|
196
|
+
formatter = factory.new(runtime_facade, path_or_io, options)
|
|
197
|
+
Formatter::LegacyApi::Adapter.new(
|
|
198
|
+
Formatter::IgnoreMissingMessages.new(formatter),
|
|
199
|
+
results, @support_code, @configuration)
|
|
200
|
+
}
|
|
234
201
|
end
|
|
235
202
|
|
|
203
|
+
def failure?
|
|
204
|
+
if @configuration.wip?
|
|
205
|
+
summary_report.test_cases.total_passed > 0
|
|
206
|
+
else
|
|
207
|
+
summary_report.test_cases.total_failed > 0 || summary_report.test_steps.total_failed > 0 ||
|
|
208
|
+
(@configuration.strict? && (summary_report.test_steps.total_undefined > 0 || summary_report.test_steps.total_pending > 0))
|
|
209
|
+
end
|
|
210
|
+
end
|
|
211
|
+
public :failure?
|
|
212
|
+
|
|
236
213
|
require 'cucumber/core/test/filters'
|
|
237
214
|
def filters
|
|
238
215
|
tag_expressions = @configuration.tag_expressions
|
|
239
216
|
name_regexps = @configuration.name_regexps
|
|
240
217
|
tag_limits = @configuration.tag_limits
|
|
241
218
|
[].tap do |filters|
|
|
242
|
-
filters <<
|
|
243
|
-
filters <<
|
|
244
|
-
filters <<
|
|
245
|
-
filters <<
|
|
246
|
-
filters <<
|
|
247
|
-
filters <<
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
class Randomizer
|
|
252
|
-
def initialize(seed, receiver)
|
|
253
|
-
@receiver = receiver
|
|
254
|
-
@test_cases = []
|
|
255
|
-
@seed = seed
|
|
256
|
-
end
|
|
257
|
-
|
|
258
|
-
def test_case(test_case)
|
|
259
|
-
@test_cases << test_case
|
|
260
|
-
end
|
|
261
|
-
|
|
262
|
-
def done
|
|
263
|
-
shuffled_test_cases.each do |test_case|
|
|
264
|
-
test_case.describe_to(@receiver)
|
|
219
|
+
filters << Filters::Randomizer.new(@configuration.seed) if @configuration.randomize?
|
|
220
|
+
filters << Filters::TagLimits.new(tag_limits) if tag_limits.any?
|
|
221
|
+
filters << Cucumber::Core::Test::TagFilter.new(tag_expressions)
|
|
222
|
+
filters << Cucumber::Core::Test::NameFilter.new(name_regexps)
|
|
223
|
+
filters << Cucumber::Core::Test::LocationsFilter.new(filespecs.locations)
|
|
224
|
+
filters << Filters::Quit.new
|
|
225
|
+
filters << Filters::ActivateSteps.new(@support_code)
|
|
226
|
+
@configuration.filters.each do |filter|
|
|
227
|
+
filters << filter
|
|
265
228
|
end
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
end
|
|
274
|
-
|
|
275
|
-
attr_reader :seed
|
|
276
|
-
private :seed
|
|
277
|
-
end
|
|
278
|
-
|
|
279
|
-
class Quit
|
|
280
|
-
def initialize(receiver)
|
|
281
|
-
@receiver = receiver
|
|
282
|
-
end
|
|
283
|
-
|
|
284
|
-
def test_case(test_case)
|
|
285
|
-
unless Cucumber.wants_to_quit
|
|
286
|
-
test_case.describe_to @receiver
|
|
229
|
+
unless configuration.dry_run?
|
|
230
|
+
filters << Filters::ApplyAfterStepHooks.new(@support_code)
|
|
231
|
+
filters << Filters::ApplyBeforeHooks.new(@support_code)
|
|
232
|
+
filters << Filters::ApplyAfterHooks.new(@support_code)
|
|
233
|
+
filters << Filters::ApplyAroundHooks.new(@support_code)
|
|
234
|
+
# need to do this last so it becomes the first test step
|
|
235
|
+
filters << Filters::PrepareWorld.new(self)
|
|
287
236
|
end
|
|
288
237
|
end
|
|
289
|
-
|
|
290
|
-
def done
|
|
291
|
-
@receiver.done
|
|
292
|
-
self
|
|
293
|
-
end
|
|
294
238
|
end
|
|
295
239
|
|
|
296
240
|
def load_step_definitions
|
data/lib/cucumber/step_match.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
require 'cucumber/multiline_argument'
|
|
2
|
+
|
|
1
3
|
module Cucumber
|
|
2
4
|
class StepMatch #:nodoc:
|
|
3
5
|
attr_reader :step_definition, :step_arguments
|
|
@@ -12,15 +14,21 @@ module Cucumber
|
|
|
12
14
|
end
|
|
13
15
|
|
|
14
16
|
def args
|
|
15
|
-
@step_arguments.map{|g| g.val
|
|
17
|
+
@step_arguments.map{|g| g.val }
|
|
16
18
|
end
|
|
17
19
|
|
|
18
20
|
def name
|
|
19
21
|
@name_to_report
|
|
20
22
|
end
|
|
21
23
|
|
|
24
|
+
def activate(test_step)
|
|
25
|
+
test_step.with_action do
|
|
26
|
+
invoke(MultilineArgument.from_core(test_step.source.last.multiline_arg))
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
22
30
|
def invoke(multiline_arg)
|
|
23
|
-
all_args =
|
|
31
|
+
all_args = deep_clone_args
|
|
24
32
|
multiline_arg.append_to(all_args)
|
|
25
33
|
@step_definition.invoke(all_args)
|
|
26
34
|
end
|
|
@@ -80,6 +88,17 @@ module Cucumber
|
|
|
80
88
|
def inspect #:nodoc:
|
|
81
89
|
sprintf("#<%s:0x%x>", self.class, self.object_id)
|
|
82
90
|
end
|
|
91
|
+
|
|
92
|
+
private
|
|
93
|
+
def deep_clone_args
|
|
94
|
+
Marshal.load( Marshal.dump( args ) )
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
class SkippingStepMatch
|
|
99
|
+
def activate(test_step)
|
|
100
|
+
return test_step.with_action { raise Core::Test::Result::Skipped.new }
|
|
101
|
+
end
|
|
83
102
|
end
|
|
84
103
|
|
|
85
104
|
class NoStepMatch #:nodoc:
|
|
@@ -110,5 +129,10 @@ module Cucumber
|
|
|
110
129
|
def step_arguments
|
|
111
130
|
[]
|
|
112
131
|
end
|
|
132
|
+
|
|
133
|
+
def activate(test_step)
|
|
134
|
+
# noop
|
|
135
|
+
return test_step
|
|
136
|
+
end
|
|
113
137
|
end
|
|
114
138
|
end
|
data/lib/cucumber.rb
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
$:.unshift(File.dirname(__FILE__)) unless
|
|
2
|
-
$:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
|
|
3
|
-
|
|
4
1
|
require 'yaml'
|
|
2
|
+
require 'cucumber/encoding'
|
|
5
3
|
require 'cucumber/platform'
|
|
6
4
|
require 'cucumber/runtime'
|
|
7
5
|
require 'cucumber/cli/main'
|
|
@@ -22,5 +20,11 @@ module Cucumber
|
|
|
22
20
|
def logger=(logger)
|
|
23
21
|
@log = logger
|
|
24
22
|
end
|
|
23
|
+
|
|
24
|
+
def deprecate(class_name, method, message)
|
|
25
|
+
return self # deprecation warnings will come in v2.1
|
|
26
|
+
called_by = caller[1]
|
|
27
|
+
warn("Deprecated: #{class_name}##{method} #{message}. Caller: #{called_by}")
|
|
28
|
+
end
|
|
25
29
|
end
|
|
26
30
|
end
|
|
@@ -398,7 +398,22 @@ END_OF_MESSAGE
|
|
|
398
398
|
expect(config.feature_files).to eq ["cucumber.feature"]
|
|
399
399
|
end
|
|
400
400
|
|
|
401
|
-
it "
|
|
401
|
+
it "gets the feature files from the rerun file" do
|
|
402
|
+
allow(File).to receive(:directory?).and_return(false)
|
|
403
|
+
allow(File).to receive(:file?).and_return(true)
|
|
404
|
+
allow(IO).to receive(:read).and_return(
|
|
405
|
+
"cucumber.feature:1:3 cucumber space.feature:134 domain folder/cuke.feature:1 domain folder/different cuke:4:5" )
|
|
406
|
+
|
|
407
|
+
config.parse!(%w{@rerun.txt})
|
|
408
|
+
|
|
409
|
+
expect(config.feature_files).to eq [
|
|
410
|
+
"cucumber.feature:1:3",
|
|
411
|
+
"cucumber space.feature:134",
|
|
412
|
+
"domain folder/cuke.feature:1",
|
|
413
|
+
"domain folder/different cuke:4:5"]
|
|
414
|
+
end
|
|
415
|
+
|
|
416
|
+
it "should allow specifying environment variables on the command line" do
|
|
402
417
|
config.parse!(["foo=bar"])
|
|
403
418
|
|
|
404
419
|
expect(ENV["foo"]).to eq "bar"
|
|
@@ -31,6 +31,16 @@ module Cucumber
|
|
|
31
31
|
|
|
32
32
|
expect(loader.args_from('default')).to eq ['--format','ugly','features/sync_imap_mailbox.feature:16:22']
|
|
33
33
|
end
|
|
34
|
+
|
|
35
|
+
it "treats percent sign as ERB code block after YAML directive" do
|
|
36
|
+
yml = <<-HERE
|
|
37
|
+
---
|
|
38
|
+
% x = '--format "pretty" features/sync_imap_mailbox.feature:16:22'
|
|
39
|
+
default: <%= x %>
|
|
40
|
+
HERE
|
|
41
|
+
given_cucumber_yml_defined_as yml
|
|
42
|
+
expect(loader.args_from('default')).to eq ['--format','pretty','features/sync_imap_mailbox.feature:16:22']
|
|
43
|
+
end
|
|
34
44
|
end
|
|
35
45
|
end
|
|
36
46
|
end
|
|
@@ -4,6 +4,7 @@ module Cucumber
|
|
|
4
4
|
describe FileSpecs do
|
|
5
5
|
let(:file_specs) { FileSpecs.new(["features/foo.feature:1:2:3", "features/bar.feature:4:5:6"]) }
|
|
6
6
|
let(:locations) { file_specs.locations }
|
|
7
|
+
let(:files) { file_specs.files }
|
|
7
8
|
|
|
8
9
|
it "parses locations from multiple files" do
|
|
9
10
|
expect(locations.length).to eq 6
|
|
@@ -18,8 +19,6 @@ module Cucumber
|
|
|
18
19
|
end
|
|
19
20
|
|
|
20
21
|
it "parses file names from multiple file specs" do
|
|
21
|
-
files = file_specs.files
|
|
22
|
-
|
|
23
22
|
expect(files.length).to eq 2
|
|
24
23
|
expect(files).to eq [
|
|
25
24
|
"features/foo.feature",
|
|
@@ -27,6 +26,15 @@ module Cucumber
|
|
|
27
26
|
]
|
|
28
27
|
end
|
|
29
28
|
|
|
29
|
+
context "when files are not unique" do
|
|
30
|
+
let(:file_specs) { FileSpecs.new(["features/foo.feature:4", "features/foo.feature:34"]) }
|
|
31
|
+
|
|
32
|
+
it "parses unique file names" do
|
|
33
|
+
expect(files.length).to eq 1
|
|
34
|
+
expect(files).to eq ["features/foo.feature"]
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
30
38
|
context "when no line number is specified" do
|
|
31
39
|
let(:file_specs) { FileSpecs.new(["features/foo.feature", "features/bar.feature:34"]) }
|
|
32
40
|
|
|
@@ -37,5 +45,16 @@ module Cucumber
|
|
|
37
45
|
]
|
|
38
46
|
end
|
|
39
47
|
end
|
|
48
|
+
|
|
49
|
+
context "when the same file is referenced more than once" do
|
|
50
|
+
let(:file_specs) { FileSpecs.new(["features/foo.feature:10", "features/foo.feature:1"]) }
|
|
51
|
+
|
|
52
|
+
it "returns locations in the order specified" do
|
|
53
|
+
expect(locations).to eq [
|
|
54
|
+
Cucumber::Core::Ast::Location.new("features/foo.feature", 10),
|
|
55
|
+
Cucumber::Core::Ast::Location.new("features/foo.feature", 1),
|
|
56
|
+
]
|
|
57
|
+
end
|
|
58
|
+
end
|
|
40
59
|
end
|
|
41
60
|
end
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
require 'cucumber/filters/activate_steps'
|
|
2
|
+
require 'cucumber/core/gherkin/writer'
|
|
3
|
+
require 'cucumber/core'
|
|
4
|
+
|
|
5
|
+
describe Cucumber::Filters::ActivateSteps do
|
|
6
|
+
include Cucumber::Core::Gherkin::Writer
|
|
7
|
+
include Cucumber::Core
|
|
8
|
+
|
|
9
|
+
let(:step_definitions) { double(find_match: step_match) }
|
|
10
|
+
let(:step_match) { double(activate: activated_test_step) }
|
|
11
|
+
let(:activated_test_step) { double }
|
|
12
|
+
let(:receiver) { double.as_null_object }
|
|
13
|
+
|
|
14
|
+
context "a scenario with a single step" do
|
|
15
|
+
let(:doc) do
|
|
16
|
+
gherkin do
|
|
17
|
+
feature do
|
|
18
|
+
scenario do
|
|
19
|
+
step 'a passing step'
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
it "activates each step" do
|
|
26
|
+
expect(step_match).to receive(:activate) do |test_step|
|
|
27
|
+
expect(test_step.name).to eq 'a passing step'
|
|
28
|
+
end
|
|
29
|
+
compile [doc], receiver, [Cucumber::Filters::ActivateSteps.new(step_definitions)]
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
context "a scenario outline" do
|
|
34
|
+
let(:doc) do
|
|
35
|
+
gherkin do
|
|
36
|
+
feature do
|
|
37
|
+
scenario_outline do
|
|
38
|
+
step 'a <status> step'
|
|
39
|
+
|
|
40
|
+
examples do
|
|
41
|
+
row 'status'
|
|
42
|
+
row 'passing'
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
it "activates each step" do
|
|
50
|
+
expect(step_match).to receive(:activate) do |test_step|
|
|
51
|
+
expect(test_step.name).to eq 'a passing step'
|
|
52
|
+
end
|
|
53
|
+
compile [doc], receiver, [Cucumber::Filters::ActivateSteps.new(step_definitions)]
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
end
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
require "cucumber/
|
|
1
|
+
require "cucumber/filters/gated_receiver"
|
|
2
2
|
|
|
3
|
-
describe Cucumber::
|
|
4
|
-
subject(:gated_receiver) { Cucumber::
|
|
3
|
+
describe Cucumber::Filters::GatedReceiver do
|
|
4
|
+
subject(:gated_receiver) { Cucumber::Filters::GatedReceiver.new(receiver) }
|
|
5
5
|
|
|
6
6
|
let(:receiver) { double(:receiver) }
|
|
7
7
|
let(:test_cases){ [double(:test_case), double(:test_case)] }
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
require "cucumber/
|
|
1
|
+
require "cucumber/filters/tag_limits"
|
|
2
2
|
|
|
3
|
-
describe Cucumber::
|
|
4
|
-
subject(:index) { Cucumber::
|
|
3
|
+
describe Cucumber::Filters::TagLimits::TestCaseIndex do
|
|
4
|
+
subject(:index) { Cucumber::Filters::TagLimits::TestCaseIndex.new }
|
|
5
5
|
|
|
6
6
|
let(:test_cases) do
|
|
7
7
|
[
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
require "cucumber/
|
|
1
|
+
require "cucumber/filters/tag_limits"
|
|
2
2
|
|
|
3
|
-
describe Cucumber::
|
|
3
|
+
describe Cucumber::Filters::TagLimits::Verifier do
|
|
4
4
|
describe "#verify!" do
|
|
5
|
-
subject(:verifier) { Cucumber::
|
|
5
|
+
subject(:verifier) { Cucumber::Filters::TagLimits::Verifier.new(tag_limits) }
|
|
6
6
|
let(:test_case_index) { double(:test_case_index) }
|
|
7
7
|
|
|
8
8
|
context "the tag counts exceed the tag limits" do
|
|
@@ -28,7 +28,7 @@ describe Cucumber::Runtime::TagLimits::Verifier do
|
|
|
28
28
|
expect {
|
|
29
29
|
verifier.verify!(test_case_index)
|
|
30
30
|
}.to raise_error(
|
|
31
|
-
Cucumber::
|
|
31
|
+
Cucumber::Filters::TagLimitExceededError,
|
|
32
32
|
"@exceed_me occurred 2 times, but the limit was set to 1\n" +
|
|
33
33
|
" path/to/some.feature:3\n" +
|
|
34
34
|
" path/to/some/other.feature:8"
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
require "cucumber/
|
|
1
|
+
require "cucumber/filters/tag_limits"
|
|
2
2
|
|
|
3
|
-
describe Cucumber::
|
|
4
|
-
subject(:filter) { Cucumber::
|
|
3
|
+
describe Cucumber::Filters::TagLimits do
|
|
4
|
+
subject(:filter) { Cucumber::Filters::TagLimits.new(tag_limits, receiver) }
|
|
5
5
|
|
|
6
6
|
let(:tag_limits) { double(:tag_limits) }
|
|
7
7
|
let(:receiver) { double(:receiver) }
|
|
@@ -11,8 +11,8 @@ describe Cucumber::Runtime::TagLimits::Filter do
|
|
|
11
11
|
let(:test_case) { double(:test_case) }
|
|
12
12
|
|
|
13
13
|
before do
|
|
14
|
-
allow(Cucumber::
|
|
15
|
-
allow(Cucumber::
|
|
14
|
+
allow(Cucumber::Filters::GatedReceiver).to receive(:new).with(receiver) { gated_receiver }
|
|
15
|
+
allow(Cucumber::Filters::TagLimits::TestCaseIndex).to receive(:new) { test_case_index }
|
|
16
16
|
end
|
|
17
17
|
|
|
18
18
|
describe "#test_case" do
|
|
@@ -36,7 +36,7 @@ describe Cucumber::Runtime::TagLimits::Filter do
|
|
|
36
36
|
let(:verifier) { double(:verifier) }
|
|
37
37
|
|
|
38
38
|
before do
|
|
39
|
-
allow(Cucumber::
|
|
39
|
+
allow(Cucumber::Filters::TagLimits::Verifier).to receive(:new).with(tag_limits) { verifier }
|
|
40
40
|
allow(gated_receiver).to receive(:done)
|
|
41
41
|
end
|
|
42
42
|
|