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

Sign up to get free protection for your applications and to get access to all the features.
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