cucumber 2.0.0.rc.4 → 2.0.0.rc.5

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.
Files changed (61) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +74 -52
  3. data/examples/i18n/ht/Rakefile +6 -0
  4. data/examples/i18n/ht/features/adisyon.feature +17 -0
  5. data/examples/i18n/ht/features/divizyon.feature +10 -0
  6. data/examples/i18n/ht/features/step_definitions/kalkilatris_steps.rb +25 -0
  7. data/examples/i18n/ht/lib/kalkilatris.rb +14 -0
  8. data/features/docs/cli/dry_run.feature +43 -0
  9. data/features/docs/cli/strict_mode.feature +24 -1
  10. data/features/docs/defining_steps/nested_steps.feature +49 -0
  11. data/features/docs/exception_in_after_step_hook.feature +1 -1
  12. data/features/docs/exception_in_around_hook.feature +80 -0
  13. data/features/docs/formatters/json_formatter.feature +65 -1
  14. data/features/docs/formatters/junit_formatter.feature +40 -0
  15. data/features/docs/{wire_protocol_erb.feature → wire_protocol/erb_configuration.feature} +2 -2
  16. data/features/docs/wire_protocol/handle_unexpected_response.feature +30 -0
  17. data/features/docs/wire_protocol/invoke_message.feature +216 -0
  18. data/features/docs/wire_protocol/readme.md +26 -0
  19. data/features/docs/wire_protocol/snippets_message.feature +51 -0
  20. data/features/docs/wire_protocol/step_matches_message.feature +81 -0
  21. data/features/docs/{wire_protocol_table_diffing.feature → wire_protocol/table_diffing.feature} +1 -0
  22. data/features/docs/{wire_protocol_tags.feature → wire_protocol/tags.feature} +1 -0
  23. data/features/docs/{wire_protocol_timeouts.feature → wire_protocol/timeouts.feature} +1 -0
  24. data/features/docs/work_in_progress.feature +1 -1
  25. data/features/docs/writing_support_code/around_hooks.feature +31 -0
  26. data/features/docs/writing_support_code/before_hook.feature +7 -3
  27. data/features/docs/writing_support_code/tagged_hooks.feature +44 -6
  28. data/features/lib/step_definitions/wire_steps.rb +18 -1
  29. data/features/lib/support/fake_wire_server.rb +10 -7
  30. data/lib/cucumber.rb +1 -3
  31. data/lib/cucumber/cli/options.rb +7 -0
  32. data/lib/cucumber/encoding.rb +5 -0
  33. data/lib/cucumber/errors.rb +8 -0
  34. data/lib/cucumber/filters/prepare_world.rb +13 -5
  35. data/lib/cucumber/formatter/console.rb +1 -1
  36. data/lib/cucumber/formatter/gherkin_formatter_adapter.rb +9 -6
  37. data/lib/cucumber/formatter/junit.rb +95 -0
  38. data/lib/cucumber/formatter/legacy_api/adapter.rb +39 -3
  39. data/lib/cucumber/platform.rb +1 -1
  40. data/lib/cucumber/project_initializer.rb +43 -0
  41. data/lib/cucumber/rb_support/rb_step_definition.rb +11 -2
  42. data/lib/cucumber/rb_support/rb_world.rb +2 -2
  43. data/lib/cucumber/rb_support/snippet.rb +1 -1
  44. data/lib/cucumber/rspec/doubles.rb +1 -1
  45. data/lib/cucumber/running_test_case.rb +115 -0
  46. data/lib/cucumber/runtime.rb +5 -1
  47. data/lib/cucumber/runtime/for_programming_languages.rb +2 -2
  48. data/lib/cucumber/runtime/support_code.rb +18 -8
  49. data/spec/cucumber/formatter/junit_spec.rb +212 -156
  50. data/spec/cucumber/formatter/legacy_api/adapter_spec.rb +89 -1
  51. data/spec/cucumber/formatter/pretty_spec.rb +13 -0
  52. data/spec/cucumber/project_initializer_spec.rb +87 -0
  53. data/spec/cucumber/rb_support/rb_step_definition_spec.rb +21 -3
  54. data/spec/cucumber/rb_support/snippet_spec.rb +6 -6
  55. data/spec/cucumber/running_test_case_spec.rb +83 -0
  56. data/spec/spec_helper.rb +1 -4
  57. metadata +35 -18
  58. data/bin/cuke +0 -60
  59. data/features/docs/report_called_undefined_steps.feature +0 -57
  60. data/features/docs/wire_protocol.feature +0 -337
  61. data/lib/cucumber/ast/facade.rb +0 -117
@@ -102,6 +102,10 @@ module Cucumber
102
102
  @support_code.fire_hook(:begin_scenario, scenario)
103
103
  end
104
104
 
105
+ def end_scenario(scenario)
106
+ @support_code.fire_hook(:end_scenario)
107
+ end
108
+
105
109
  def unknown_programming_language?
106
110
  @support_code.unknown_programming_language?
107
111
  end
@@ -201,7 +205,7 @@ module Cucumber
201
205
  summary_report.test_cases.total_passed > 0
202
206
  else
203
207
  summary_report.test_cases.total_failed > 0 || summary_report.test_steps.total_failed > 0 ||
204
- (@configuration.strict? && (summary_report.test_steps.total_undefined > 0 || summary_report.test_steps.total_skipped > 0))
208
+ (@configuration.strict? && (summary_report.test_steps.total_undefined > 0 || summary_report.test_steps.total_pending > 0))
205
209
  end
206
210
  end
207
211
  public :failure?
@@ -23,8 +23,8 @@ module Cucumber
23
23
  :step_match
24
24
 
25
25
  def_delegators :@support_code,
26
- :invoke_steps,
27
- :invoke,
26
+ :invoke_dynamic_steps,
27
+ :invoke_dynamic_step,
28
28
  :load_programming_language
29
29
 
30
30
  # Returns a Cucumber::MultilineArgument::DataTable for +text_or_table+, which can either
@@ -23,7 +23,7 @@ module Cucumber
23
23
 
24
24
  def step(step)
25
25
  location = Core::Ast::Location.of_caller
26
- @support_code.invoke(step.name, multiline_arg(step, location))
26
+ @support_code.invoke_dynamic_step(step.name, multiline_arg(step, location))
27
27
  end
28
28
 
29
29
  def eof
@@ -58,14 +58,24 @@ module Cucumber
58
58
  # Given I have 8 cukes in my belly
59
59
  # Then I should not be thirsty
60
60
  # })
61
- def invoke_steps(steps_text, i18n, file_colon_line)
61
+ def invoke_dynamic_steps(steps_text, i18n, file_colon_line)
62
62
  file, line = file_colon_line.split(':')
63
63
  parser = Gherkin::Parser::Parser.new(StepInvoker.new(self), true, 'steps', false, i18n.iso_code)
64
64
  parser.parse(steps_text, file, line.to_i)
65
65
  end
66
66
 
67
- def invoke(step_name, multiline_argument, location=nil)
68
- step_match(step_name).invoke(multiline_argument)
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
69
79
  end
70
80
 
71
81
  # Loads and registers programming language implementation.
@@ -137,7 +147,7 @@ module Cucumber
137
147
 
138
148
  def find_after_step_hooks(test_case)
139
149
  ruby = load_programming_language('rb')
140
- scenario = Ast::Facade.new(test_case).build_scenario
150
+ scenario = RunningTestCase.new(test_case)
141
151
 
142
152
  action_blocks = ruby.hooks_for(:after_step, scenario).map do |hook|
143
153
  ->(*args) { hook.invoke('AfterStep', args) }
@@ -147,7 +157,7 @@ module Cucumber
147
157
 
148
158
  def apply_before_hooks(test_case)
149
159
  ruby = load_programming_language('rb')
150
- scenario = Ast::Facade.new(test_case).build_scenario
160
+ scenario = RunningTestCase.new(test_case)
151
161
 
152
162
  action_blocks = ruby.hooks_for(:before, scenario).map do |hook|
153
163
  ->(result) { hook.invoke('Before', scenario.with_result(result)) }
@@ -157,7 +167,7 @@ module Cucumber
157
167
 
158
168
  def apply_after_hooks(test_case)
159
169
  ruby = load_programming_language('rb')
160
- scenario = Ast::Facade.new(test_case).build_scenario
170
+ scenario = RunningTestCase.new(test_case)
161
171
 
162
172
  action_blocks = ruby.hooks_for(:after, scenario).map do |hook|
163
173
  ->(result) { hook.invoke('After', scenario.with_result(result)) }
@@ -167,7 +177,7 @@ module Cucumber
167
177
 
168
178
  def find_around_hooks(test_case)
169
179
  ruby = load_programming_language('rb')
170
- scenario = Ast::Facade.new(test_case).build_scenario
180
+ scenario = RunningTestCase.new(test_case)
171
181
 
172
182
  ruby.hooks_for(:around, scenario).map do |hook|
173
183
  Hooks.around_hook(test_case.source) do |run_scenario|
@@ -4,192 +4,248 @@ require 'cucumber/formatter/spec_helper'
4
4
  require 'cucumber/formatter/junit'
5
5
  require 'nokogiri'
6
6
 
7
- module Cucumber::Formatter
8
- describe Junit do
9
- extend SpecHelperDsl
10
- include SpecHelper
11
-
12
- class TestDoubleJunitFormatter < Junit
13
- attr_reader :written_files
14
-
15
- def write_file(feature_filename, data)
16
- @written_files ||= {}
17
- @written_files[feature_filename] = data
7
+ module Cucumber
8
+ module Formatter
9
+ describe Junit do
10
+ extend SpecHelperDsl
11
+ include SpecHelper
12
+
13
+ class TestDoubleJunitFormatter < Junit
14
+ attr_reader :written_files
15
+
16
+ def write_file(feature_filename, data)
17
+ @written_files ||= {}
18
+ @written_files[feature_filename] = data
19
+ end
18
20
  end
19
- end
20
21
 
21
- before(:each) do
22
- allow(File).to receive(:directory?) { true }
23
- @formatter = TestDoubleJunitFormatter.new(runtime, '', {})
24
- end
22
+ context "With no options" do
23
+ before(:each) do
24
+ allow(File).to receive(:directory?) { true }
25
+ @formatter = TestDoubleJunitFormatter.new(runtime, '', {})
26
+ end
25
27
 
26
- after(:each) do
27
- $stdout = STDOUT
28
- end
28
+ after(:each) do
29
+ $stdout = STDOUT
30
+ end
29
31
 
30
- describe "is able to strip control chars from cdata" do
31
- before(:each) do
32
- run_defined_feature
33
- @doc = Nokogiri.XML(@formatter.written_files.values.first)
34
- end
35
- define_feature "
36
- Feature: One passing scenario, one failing scenario
37
-
38
- Scenario: Passing
39
- Given a passing ctrl scenario
40
- "
41
- class Junit
42
- def before_step(step)
43
- if step.name.match("a passing ctrl scenario")
44
- Interceptor::Pipe.unwrap! :stdout
45
- @fake_io = $stdout = StringIO.new
46
- $stdout.sync = true
47
- @interceptedout = Interceptor::Pipe.wrap(:stdout)
32
+ describe "is able to strip control chars from cdata" do
33
+ before(:each) do
34
+ run_defined_feature
35
+ @doc = Nokogiri.XML(@formatter.written_files.values.first)
36
+ end
37
+ define_feature "
38
+ Feature: One passing scenario, one failing scenario
39
+
40
+ Scenario: Passing
41
+ Given a passing ctrl scenario
42
+ "
43
+ class Junit
44
+ def before_step(step)
45
+ if step.name.match("a passing ctrl scenario")
46
+ Interceptor::Pipe.unwrap! :stdout
47
+ @fake_io = $stdout = StringIO.new
48
+ $stdout.sync = true
49
+ @interceptedout = Interceptor::Pipe.wrap(:stdout)
50
+ end
51
+ end
52
+
53
+ def after_step(step)
54
+ if step.name.match("a passing ctrl scenario")
55
+ @interceptedout.write("boo\b\cx\e\a\f boo ")
56
+ $stdout = STDOUT
57
+ @fake_io.close
58
+ end
59
+ end
48
60
  end
61
+
62
+ it { expect(@doc.xpath('//testsuite/system-out').first.content).to match(/\s+boo boo\s+/) }
49
63
  end
50
64
 
51
- def after_step(step)
52
- if step.name.match("a passing ctrl scenario")
53
- @interceptedout.write("boo\b\cx\e\a\f boo ")
54
- $stdout = STDOUT
55
- @fake_io.close
65
+ describe "a feature with no name" do
66
+ define_feature <<-FEATURE
67
+ Feature:
68
+ Scenario: Passing
69
+ Given a passing scenario
70
+ FEATURE
71
+
72
+ it "raises an exception" do
73
+ expect(-> {
74
+ run_defined_feature
75
+ }).to raise_error(Junit::UnNamedFeatureError)
56
76
  end
57
77
  end
58
- end
59
78
 
60
- it { expect(@doc.xpath('//testsuite/system-out').first.content).to match(/\s+boo boo\s+/) }
61
- end
62
-
63
- describe "a feature with no name" do
64
- define_feature <<-FEATURE
65
- Feature:
66
- Scenario: Passing
67
- Given a passing scenario
68
- FEATURE
69
-
70
- it "raises an exception" do
71
- expect(-> {
72
- run_defined_feature
73
- }).to raise_error(Junit::UnNamedFeatureError)
74
- end
75
- end
76
-
77
- describe "given a single feature" do
78
- before(:each) do
79
- run_defined_feature
80
- @doc = Nokogiri.XML(@formatter.written_files.values.first)
81
- end
79
+ describe "given a single feature" do
80
+ before(:each) do
81
+ run_defined_feature
82
+ @doc = Nokogiri.XML(@formatter.written_files.values.first)
83
+ end
82
84
 
83
- describe "with a single scenario" do
84
- define_feature <<-FEATURE
85
- Feature: One passing scenario, one failing scenario
85
+ describe "with a single scenario" do
86
+ define_feature <<-FEATURE
87
+ Feature: One passing scenario, one failing scenario
86
88
 
87
- Scenario: Passing
88
- Given a passing scenario
89
- FEATURE
89
+ Scenario: Passing
90
+ Given a passing scenario
91
+ FEATURE
90
92
 
91
- it { expect(@doc.to_s).to match /One passing scenario, one failing scenario/ }
93
+ it { expect(@doc.to_s).to match /One passing scenario, one failing scenario/ }
92
94
 
93
- it 'has a root system-out node' do
94
- expect(@doc.xpath('//testsuite/system-out').size).to eq 1
95
- end
95
+ it 'has a root system-out node' do
96
+ expect(@doc.xpath('//testsuite/system-out').size).to eq 1
97
+ end
96
98
 
97
- it 'has a root system-err node' do
98
- expect(@doc.xpath('//testsuite/system-err').size).to eq 1
99
- end
99
+ it 'has a root system-err node' do
100
+ expect(@doc.xpath('//testsuite/system-err').size).to eq 1
101
+ end
100
102
 
101
- it 'has a system-out node under <testcase/>' do
102
- expect(@doc.xpath('//testcase/system-out').size).to eq 1
103
- end
103
+ it 'has a system-out node under <testcase/>' do
104
+ expect(@doc.xpath('//testcase/system-out').size).to eq 1
105
+ end
104
106
 
105
- it 'has a system-err node under <testcase/>' do
106
- expect(@doc.xpath('//testcase/system-err').size).to eq 1
107
- end
108
- end
107
+ it 'has a system-err node under <testcase/>' do
108
+ expect(@doc.xpath('//testcase/system-err').size).to eq 1
109
+ end
110
+ end
109
111
 
110
- describe "with a scenario in a subdirectory" do
111
- define_feature %{
112
- Feature: One passing scenario, one failing scenario
112
+ describe "with a scenario in a subdirectory" do
113
+ define_feature %{
114
+ Feature: One passing scenario, one failing scenario
113
115
 
114
- Scenario: Passing
115
- Given a passing scenario
116
- }, File.join('features', 'some', 'path', 'spec.feature')
116
+ Scenario: Passing
117
+ Given a passing scenario
118
+ }, File.join('features', 'some', 'path', 'spec.feature')
117
119
 
118
- it 'writes the filename including the subdirectory' do
119
- expect(@formatter.written_files.keys.first).to eq File.join('', 'TEST-features-some-path-spec.xml')
120
- end
121
- end
120
+ it 'writes the filename including the subdirectory' do
121
+ expect(@formatter.written_files.keys.first).to eq File.join('', 'TEST-features-some-path-spec.xml')
122
+ end
123
+ end
122
124
 
123
- describe "with a scenario outline table" do
124
- define_steps do
125
- Given(/.*/) { }
126
- end
125
+ describe "with a scenario outline table" do
126
+ define_steps do
127
+ Given(/.*/) { }
128
+ end
129
+
130
+ define_feature <<-FEATURE
131
+ Feature: Eat things when hungry
132
+
133
+ Scenario Outline: Eat things
134
+ Given <Things>
135
+ And stuff:
136
+ | foo |
137
+ | bar |
138
+
139
+ Examples: Good
140
+ | Things |
141
+ | Cucumber |
142
+ | Whisky |
143
+ Examples: Evil
144
+ | Things |
145
+ | Big Mac |
146
+ FEATURE
147
+
148
+ it { expect(@doc.to_s).to match /Eat things when hungry/ }
149
+ it { expect(@doc.to_s).to match /Cucumber/ }
150
+ it { expect(@doc.to_s).to match /Whisky/ }
151
+ it { expect(@doc.to_s).to match /Big Mac/ }
152
+ it { expect(@doc.to_s).not_to match /Things/ }
153
+ it { expect(@doc.to_s).not_to match /Good|Evil/ }
154
+ it { expect(@doc.to_s).not_to match /type="skipped"/}
155
+ end
127
156
 
128
- define_feature <<-FEATURE
129
- Feature: Eat things when hungry
130
-
131
- Scenario Outline: Eat things
132
- Given <Things>
133
- And stuff:
134
- | foo |
135
- | bar |
136
-
137
- Examples: Good
138
- | Things |
139
- | Cucumber |
140
- | Whisky |
141
- Examples: Evil
142
- | Things |
143
- | Big Mac |
144
- FEATURE
145
-
146
- it { expect(@doc.to_s).to match /Eat things when hungry/ }
147
- it { expect(@doc.to_s).to match /Cucumber/ }
148
- it { expect(@doc.to_s).to match /Whisky/ }
149
- it { expect(@doc.to_s).to match /Big Mac/ }
150
- it { expect(@doc.to_s).not_to match /Things/ }
151
- it { expect(@doc.to_s).not_to match /Good|Evil/ }
152
- it { expect(@doc.to_s).not_to match /type="skipped"/}
153
- end
157
+ describe "scenario with skipped test in junit report" do
158
+ define_feature <<-FEATURE
159
+ Feature: junit report with skipped test
154
160
 
155
- describe "scenario with skipped test in junit report" do
156
- define_feature <<-FEATURE
157
- Feature: junit report with skipped test
161
+ Scenario Outline: skip a test and junit report of the same
162
+ Given a <skip> scenario
158
163
 
159
- Scenario Outline: skip a test and junit report of the same
160
- Given a <skip> scenario
164
+ Examples:
165
+ | skip |
166
+ | undefined |
167
+ | still undefined |
168
+ FEATURE
161
169
 
162
- Examples:
163
- | skip |
164
- | undefined |
165
- | still undefined |
166
- FEATURE
170
+ it { expect(@doc.to_s).to match /skipped="2"/}
171
+ end
167
172
 
168
- it { expect(@doc.to_s).to match /skipped="2"/}
173
+ describe "with a regular data table scenario" do
174
+ define_steps do
175
+ Given(/the following items on a shortlist/) { |table| }
176
+ When(/I go.*/) { }
177
+ Then(/I should have visited at least/) { |table| }
178
+ end
179
+
180
+ define_feature <<-FEATURE
181
+ Feature: Shortlist
182
+
183
+ Scenario: Procure items
184
+ Given the following items on a shortlist:
185
+ | item |
186
+ | milk |
187
+ | cookies |
188
+ When I get some..
189
+ Then I'll eat 'em
190
+
191
+ FEATURE
192
+ # these type of tables shouldn't crash (or generate test cases)
193
+ it { expect(@doc.to_s).not_to match /milk/ }
194
+ it { expect(@doc.to_s).not_to match /cookies/ }
195
+ end
196
+ end
169
197
  end
198
+
199
+ context "In --expand mode" do
200
+ let(:runtime) { Runtime.new({:expand => true}) }
201
+ before(:each) do
202
+ allow(File).to receive(:directory?) { true }
203
+ @formatter = TestDoubleJunitFormatter.new(runtime, '', {:expand => true})
204
+ end
170
205
 
171
- describe "with a regular data table scenario" do
172
- define_steps do
173
- Given(/the following items on a shortlist/) { |table| }
174
- When(/I go.*/) { }
175
- Then(/I should have visited at least/) { |table| }
206
+ after(:each) do
207
+ $stdout = STDOUT
176
208
  end
177
209
 
178
- define_feature <<-FEATURE
179
- Feature: Shortlist
180
-
181
- Scenario: Procure items
182
- Given the following items on a shortlist:
183
- | item |
184
- | milk |
185
- | cookies |
186
- When I get some..
187
- Then I'll eat 'em
188
-
189
- FEATURE
190
- # these type of tables shouldn't crash (or generate test cases)
191
- it { expect(@doc.to_s).not_to match /milk/ }
192
- it { expect(@doc.to_s).not_to match /cookies/ }
210
+ describe "given a single feature" do
211
+ before(:each) do
212
+ run_defined_feature
213
+ @doc = Nokogiri.XML(@formatter.written_files.values.first)
214
+ end
215
+
216
+ describe "with a scenario outline table" do
217
+ define_steps do
218
+ Given(/.*/) { }
219
+ end
220
+
221
+ define_feature <<-FEATURE
222
+ Feature: Eat things when hungry
223
+
224
+ Scenario Outline: Eat things
225
+ Given <Things>
226
+ And stuff:
227
+ | foo |
228
+ | bar |
229
+
230
+ Examples: Good
231
+ | Things |
232
+ | Cucumber |
233
+ | Whisky |
234
+ Examples: Evil
235
+ | Things |
236
+ | Big Mac |
237
+ FEATURE
238
+
239
+ it { expect(@doc.to_s).to match /Eat things when hungry/ }
240
+ it { expect(@doc.to_s).to match /Cucumber/ }
241
+ it { expect(@doc.to_s).to match /Whisky/ }
242
+ it { expect(@doc.to_s).to match /Big Mac/ }
243
+ it { expect(@doc.to_s).not_to match /Things/ }
244
+ it { expect(@doc.to_s).not_to match /Good|Evil/ }
245
+ it { expect(@doc.to_s).not_to match /type="skipped"/}
246
+ end
247
+ end
248
+
193
249
  end
194
250
  end
195
251
  end