cucumber 0.3.102 → 0.3.103

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 (47) hide show
  1. data/History.txt +18 -0
  2. data/Manifest.txt +6 -2
  3. data/examples/java/README.textile +3 -3
  4. data/examples/self_test/features/sample.feature +1 -1
  5. data/examples/self_test/features/search_sample.feature +1 -1
  6. data/features/custom_formatter.feature +4 -4
  7. data/features/steps_formatter.feature +2 -1
  8. data/lib/cucumber/ast.rb +1 -0
  9. data/lib/cucumber/ast/table.rb +4 -4
  10. data/lib/cucumber/ast/tree_walker.rb +185 -0
  11. data/lib/cucumber/ast/visitor.rb +2 -106
  12. data/lib/cucumber/cli/configuration.rb +28 -28
  13. data/lib/cucumber/cli/language_help_formatter.rb +5 -7
  14. data/lib/cucumber/cli/main.rb +3 -3
  15. data/lib/cucumber/core_ext/string.rb +0 -22
  16. data/lib/cucumber/formatter/html.rb +203 -113
  17. data/lib/cucumber/formatter/junit.rb +29 -23
  18. data/lib/cucumber/formatter/pdf.rb +74 -69
  19. data/lib/cucumber/formatter/pretty.rb +93 -78
  20. data/lib/cucumber/formatter/profile.rb +2 -2
  21. data/lib/cucumber/formatter/progress.rb +16 -10
  22. data/lib/cucumber/formatter/rerun.rb +4 -5
  23. data/lib/cucumber/formatter/steps.rb +6 -7
  24. data/lib/cucumber/formatter/tag_cloud.rb +7 -6
  25. data/lib/cucumber/formatter/usage.rb +7 -10
  26. data/lib/cucumber/language_support/step_definition_methods.rb +4 -4
  27. data/lib/cucumber/rails/action_controller.rb +1 -1
  28. data/lib/cucumber/rails/active_record.rb +27 -14
  29. data/lib/cucumber/rb_support/rb_language.rb +5 -0
  30. data/lib/cucumber/rb_support/rb_step_definition.rb +9 -16
  31. data/lib/cucumber/rb_support/regexp_argument_matcher.rb +21 -0
  32. data/lib/cucumber/step_argument.rb +9 -0
  33. data/lib/cucumber/step_match.rb +24 -5
  34. data/lib/cucumber/version.rb +1 -1
  35. data/rails_generators/cucumber/templates/env.rb +14 -0
  36. data/spec/cucumber/ast/background_spec.rb +1 -2
  37. data/spec/cucumber/ast/scenario_outline_spec.rb +3 -2
  38. data/spec/cucumber/ast/scenario_spec.rb +1 -1
  39. data/spec/cucumber/ast/tree_walker_spec.rb +18 -0
  40. data/spec/cucumber/formatter/html_spec.rb +221 -2
  41. data/spec/cucumber/formatter/progress_spec.rb +9 -4
  42. data/spec/cucumber/parser/feature_parser_spec.rb +31 -27
  43. data/spec/cucumber/rb_support/regexp_argument_matcher_spec.rb +18 -0
  44. data/spec/cucumber/step_match_spec.rb +40 -0
  45. metadata +8 -4
  46. data/lib/cucumber/rb_support/rb_group.rb +0 -11
  47. data/spec/cucumber/core_ext/string_spec.rb +0 -41
@@ -2,7 +2,7 @@ module Cucumber #:nodoc:
2
2
  class VERSION #:nodoc:
3
3
  MAJOR = 0
4
4
  MINOR = 3
5
- TINY = 102
5
+ TINY = 103
6
6
  PATCH = nil # Set to nil for official release
7
7
 
8
8
  STRING = [MAJOR, MINOR, TINY, PATCH].compact.join('.')
@@ -3,6 +3,20 @@ ENV["RAILS_ENV"] ||= "cucumber"
3
3
  require File.expand_path(File.dirname(__FILE__) + '/../../config/environment')
4
4
  require 'cucumber/rails/world'
5
5
 
6
+ # Whether or not to run each scenario within a database transaction.
7
+ #
8
+ # If you leave this to true, you can turn off traqnsactions on a
9
+ # per-scenario basis, simply tagging it with @no-txn
10
+ Cucumber::Rails::World.use_transactional_fixtures = true
11
+
12
+ # Whether or not to allow Rails to rescue errors and render them on
13
+ # an error page. Default is false, which will cause an error to be
14
+ # raised.
15
+ #
16
+ # If you leave this to false, you can turn on Rails rescuing on a
17
+ # per-scenario basis, simply tagging it with @allow-rescue
18
+ ActionController::Base.allow_rescue = false
19
+
6
20
  # Comment out the next line if you don't want Cucumber Unicode support
7
21
  require 'cucumber/formatter/unicode'
8
22
 
@@ -22,8 +22,7 @@ module Cucumber
22
22
 
23
23
  register
24
24
 
25
- @visitor = Visitor.new(@step_mother)
26
- @visitor.options = {}
25
+ @visitor = TreeWalker.new(@step_mother)
27
26
 
28
27
  @feature = mock('feature', :visit? => true).as_null_object
29
28
  end
@@ -57,14 +57,15 @@ module Cucumber
57
57
  end
58
58
 
59
59
  it "should replace all variables and call outline once for each table row" do
60
- visitor = Visitor.new(@step_mother)
60
+ visitor = TreeWalker.new(@step_mother)
61
61
  visitor.should_receive(:visit_table_row).exactly(3).times
62
62
  visitor.visit_feature_element(@scenario_outline)
63
63
  end
64
64
 
65
65
  it "should pretty print" do
66
66
  require 'cucumber/formatter/pretty'
67
- visitor = Formatter::Pretty.new(@step_mother, STDOUT, {:comment => true, :tag_names => {}})
67
+ formatter = Formatter::Pretty.new(@step_mother, STDOUT, {:comment => true, :tag_names => {}})
68
+ visitor = TreeWalker.new(@step_mother, [formatter])
68
69
  visitor.visit_feature_element(@scenario_outline)
69
70
  end
70
71
  end
@@ -17,7 +17,7 @@ module Cucumber
17
17
  @dsl.Given /y is (\d+)/ do |n|
18
18
  $y = n.to_i
19
19
  end
20
- @visitor = Visitor.new(@step_mother)
20
+ @visitor = TreeWalker.new(@step_mother)
21
21
  @visitor.options = {}
22
22
  end
23
23
 
@@ -0,0 +1,18 @@
1
+ require File.dirname(__FILE__) + '/../../spec_helper'
2
+
3
+ module Cucumber::Ast
4
+ describe TreeWalker do
5
+ describe "when one of the listeners implements the method #visit_features" do
6
+ it "should issue a warning about that interface being deprecated" do
7
+ tw = TreeWalker.new(nil, [mock('listener', :visit_features => nil)], {})
8
+ tw.should_receive(:warn).with /no longer supported/
9
+ tw.visit_features(mock('features', :accept => nil))
10
+ end
11
+ end
12
+ it "should visit features" do
13
+ tw = TreeWalker.new(nil, [mock('listener', :before_visit_features => nil)], {})
14
+ tw.should_not_receive(:warn)
15
+ tw.visit_features(mock('features', :accept => nil))
16
+ end
17
+ end
18
+ end
@@ -1,16 +1,235 @@
1
1
  require File.dirname(__FILE__) + '/../../spec_helper'
2
2
  require 'cucumber/formatter/html'
3
+ require 'nokogiri'
4
+ require 'cucumber/rb_support/rb_language'
3
5
 
4
6
  module Cucumber
5
7
  module Formatter
8
+ module SpecHelperDsl
9
+ attr_reader :feature_content, :step_defs
10
+
11
+ def define_feature(string)
12
+ @feature_content = string
13
+ end
14
+
15
+ def define_steps(&block)
16
+ @step_defs = block
17
+ end
18
+ end
19
+ module SpecHelper
20
+ def load_features(content)
21
+ feature_file = FeatureFile.new(nil, content)
22
+ features = Ast::Features.new
23
+ features.add_feature feature_file.parse(@step_mother, {})
24
+ features
25
+ end
26
+
27
+ def run(features)
28
+ # options = { :verbose => true }
29
+ options = {}
30
+ tree_walker = Cucumber::Ast::TreeWalker.new(@step_mother, [@formatter], options, STDOUT)
31
+ tree_walker.visit_features(features)
32
+ end
33
+
34
+ def define_steps
35
+ return unless step_defs = self.class.step_defs
36
+ rb = @step_mother.load_programming_language('rb')
37
+ dsl = Object.new
38
+ dsl.extend RbSupport::RbDsl
39
+ dsl.instance_exec &step_defs
40
+ @step_mother.register_step_definitions(rb.step_definitions)
41
+ end
42
+
43
+ Spec::Matchers.define :have_css_node do |css, regexp|
44
+ match do |doc|
45
+ nodes = doc.css(css)
46
+ nodes.detect{ |node| node.text =~ regexp }
47
+ end
48
+ end
49
+ end
50
+
6
51
  describe Html do
7
52
  before(:each) do
8
53
  @out = StringIO.new
9
- @html = Html.new(mock("step mother"), @out, {})
54
+ @formatter = Html.new(mock("step mother"), @out, {})
55
+ @step_mother = StepMother.new
10
56
  end
57
+
58
+ extend SpecHelperDsl
59
+ include SpecHelper
11
60
 
12
61
  it "should not raise an error when visiting a blank feature name" do
13
- lambda { @html.visit_feature_name("") }.should_not raise_error
62
+ lambda { @formatter.feature_name("") }.should_not raise_error
63
+ end
64
+
65
+ describe "given a single feature" do
66
+ before(:each) do
67
+ features = load_features(self.class.feature_content || raise("No feature content defined!"))
68
+ define_steps
69
+ run(features)
70
+ @doc = Nokogiri.HTML(@out.string)
71
+ end
72
+
73
+ describe "with a comment" do
74
+ define_feature <<-FEATURE
75
+ # Healthy
76
+ FEATURE
77
+
78
+ it { @out.string.should =~ /^\<!DOCTYPE/ }
79
+ it { @out.string.should =~ /\<\/html\>$/ }
80
+ it { @doc.should have_css_node('.feature .comment', /Healthy/) }
81
+ end
82
+
83
+ describe "with a tag" do
84
+ define_feature <<-FEATURE
85
+ @foo
86
+ FEATURE
87
+
88
+ it { @doc.should have_css_node('.feature .tag', /foo/) }
89
+ end
90
+
91
+ describe "with a narrative" do
92
+ define_feature <<-FEATURE
93
+ Feature: Bananas
94
+ In order to find my inner monkey
95
+ As a human
96
+ I must eat bananas
97
+ FEATURE
98
+
99
+ it { @doc.should have_css_node('.feature h2', /Bananas/) }
100
+ it { @doc.should have_css_node('.feature .narrative', /must eat bananas/) }
101
+ end
102
+
103
+ describe "with a background" do
104
+ define_feature <<-FEATURE
105
+ Feature: Bananas
106
+
107
+ Background:
108
+ Given there are bananas
109
+ FEATURE
110
+
111
+ it { @doc.should have_css_node('.feature .background', /there are bananas/) }
112
+ end
113
+
114
+ describe "with a scenario" do
115
+ define_feature <<-FEATURE
116
+ Scenario: Monkey eats banana
117
+ Given there are bananas
118
+ FEATURE
119
+
120
+ it { @doc.should have_css_node('.feature h3', /Monkey eats banana/) }
121
+ it { @doc.should have_css_node('.feature .scenario .step', /there are bananas/) }
122
+ end
123
+
124
+ describe "with a scenario outline" do
125
+ define_feature <<-FEATURE
126
+ Scenario Outline: Monkey eats a balanced diet
127
+ Given there are <Things>
128
+
129
+ Examples: Fruit
130
+ | Things |
131
+ | apples |
132
+ | bananas |
133
+ Examples: Vegetables
134
+ | Things |
135
+ | broccoli |
136
+ | carrots |
137
+ FEATURE
138
+
139
+ it { @doc.should have_css_node('.feature .scenario.outline h4', /Fruit/) }
140
+ it { @doc.should have_css_node('.feature .scenario.outline h4', /Vegetables/) }
141
+ it { @doc.css('.feature .scenario.outline h4').length.should == 2}
142
+ it { @doc.should have_css_node('.feature .scenario.outline table', //) }
143
+ it { @doc.should have_css_node('.feature .scenario.outline table td', /carrots/) }
144
+ end
145
+
146
+ describe "with a step with a py string" do
147
+ define_feature <<-FEATURE
148
+ Scenario: Monkey goes to town
149
+ Given there is a monkey called:
150
+ """
151
+ foo
152
+ """
153
+ FEATURE
154
+
155
+ it { @doc.should have_css_node('.feature .scenario .val', /foo/) }
156
+ end
157
+
158
+ describe "with a multiline step arg" do
159
+ define_feature <<-FEATURE
160
+ Scenario: Monkey goes to town
161
+ Given there are monkeys:
162
+ | name |
163
+ | foo |
164
+ | bar |
165
+ FEATURE
166
+
167
+ it { @doc.should have_css_node('.feature .scenario table td', /foo/) }
168
+ end
169
+
170
+ describe "with a table in the background and the scenario" do
171
+ define_feature <<-FEATURE
172
+ Background:
173
+ Given table:
174
+ | a | b |
175
+ | c | d |
176
+ Scenario:
177
+ Given another table:
178
+ | e | f |
179
+ | g | h |
180
+ FEATURE
181
+
182
+ it { @doc.css('td').length.should == 8 }
183
+ end
184
+
185
+ describe "with a py string in the background and the scenario" do
186
+ define_feature <<-FEATURE
187
+ Background:
188
+ Given stuff:
189
+ """
190
+ foo
191
+ """
192
+ Scenario:
193
+ Given more stuff:
194
+ """
195
+ bar
196
+ """
197
+ FEATURE
198
+
199
+ it { @doc.css('.feature .background pre.val').length.should == 1 }
200
+ it { @doc.css('.feature .scenario pre.val').length.should == 1 }
201
+ end
202
+
203
+ describe "with a step that fails in the scenario" do
204
+ define_steps do
205
+ Given(/boo/) { raise 'eek' }
206
+ end
207
+
208
+ define_feature(<<-FEATURE)
209
+ Scenario: Monkey gets a fright
210
+ Given boo
211
+ FEATURE
212
+
213
+ it { @doc.should have_css_node('.feature .scenario .step.failed', /eek/) }
214
+ end
215
+
216
+ describe "with a step that fails in the backgound" do
217
+ define_steps do
218
+ Given(/boo/) { raise 'eek' }
219
+ end
220
+
221
+ define_feature(<<-FEATURE)
222
+ Background:
223
+ Given boo
224
+ Scenario:
225
+ Given yay
226
+ FEATURE
227
+
228
+ it { @doc.should have_css_node('.feature .background .step.failed', /eek/) }
229
+ it { @doc.should_not have_css_node('.feature .scenario .step.failed', //) }
230
+ it { @doc.should have_css_node('.feature .scenario .step.undefined', /yay/) }
231
+ end
232
+
14
233
  end
15
234
  end
16
235
  end
@@ -8,13 +8,18 @@ module Cucumber
8
8
  before(:each) do
9
9
  Term::ANSIColor.coloring = false
10
10
  @out = StringIO.new
11
- @progress = Progress.new(mock("step mother"), @out, {})
11
+ progress = Progress.new(mock("step mother"), @out, {})
12
+ @visitor = Ast::TreeWalker.new(nil, [progress])
12
13
  end
13
14
 
14
15
  describe "visiting a table cell value without a status" do
15
16
  it "should take the status from the last run step" do
16
- @progress.visit_step_result('', '', nil, :failed, nil, 10, nil)
17
- @progress.visit_table_cell_value('value', nil)
17
+ @visitor.visit_step_result('', '', nil, :failed, nil, 10, nil)
18
+ outline_table = mock()
19
+ outline_table.should_receive(:accept) do |visitor|
20
+ visitor.visit_table_cell_value('value', nil)
21
+ end
22
+ @visitor.visit_outline_table(outline_table)
18
23
 
19
24
  @out.string.should == "FF"
20
25
  end
@@ -22,7 +27,7 @@ module Cucumber
22
27
 
23
28
  describe "visiting a table cell which is a table header" do
24
29
  it "should not output anything" do
25
- @progress.visit_table_cell_value('value', :skipped_param)
30
+ @visitor.visit_table_cell_value('value', :skipped_param)
26
31
 
27
32
  @out.string.should == ""
28
33
  end
@@ -361,34 +361,38 @@ Given I am a step
361
361
 
362
362
  describe "Filtering" do
363
363
  it "should filter outline tables" do
364
- ff = FeatureFile.new(
365
- File.dirname(__FILE__) + '/../../../examples/self_test/features/outline_sample.feature:12')
366
- f = ff.parse(@step_mother, {:lang => 'en'})
367
- f.to_sexp.should ==
364
+ path = '/self_test/features/outline_sample.feature'
365
+ f = parse_example_file("#{path}:12")
366
+ actual_sexp = f.to_sexp
367
+
368
+ # check path is equivalent, if not same
369
+ File.expand_path(actual_sexp[1]).should == File.expand_path(File.dirname(__FILE__) + "/../../../examples#{path}")
370
+ actual_sexp[1] = 'made/up/path.feature'
371
+ actual_sexp.should ==
368
372
  [:feature,
369
- "./spec/cucumber/parser/../../../examples/self_test/features/outline_sample.feature",
370
- "Feature: Outline Sample",
371
- [:scenario_outline,
372
- "Scenario Outline:",
373
- "Test state",
374
- [:step, 6, "Given", "<state> without a table"],
375
- [:step, 7, "Given", "<other_state> without a table"],
376
- [:examples,
377
- "Examples:",
378
- "Rainbow colours",
379
- [:table,
380
- [:row, 9, [:cell, "state"], [:cell, "other_state"]],
381
- # [:row, 10, [:cell, "missing"], [:cell, "passing"]],
382
- # [:row, 11, [:cell, "passing"], [:cell, "passing"]],
383
- [:row, 12, [:cell, "failing"], [:cell, "passing"]]]]
384
- # ,
385
- # [:examples,
386
- # "Examples:",
387
- # "Only passing",
388
- # [:table,
389
- # [:row, 14, [:cell, "state"], [:cell, "other_state"]],
390
- # [:row, 15, [:cell, "passing"], [:cell, "passing"]]]]]
391
- ]]
373
+ 'made/up/path.feature',
374
+ "Feature: Outline Sample",
375
+ [:scenario_outline,
376
+ "Scenario Outline:",
377
+ "Test state",
378
+ [:step, 6, "Given", "<state> without a table"],
379
+ [:step, 7, "Given", "<other_state> without a table"],
380
+ [:examples,
381
+ "Examples:",
382
+ "Rainbow colours",
383
+ [:table,
384
+ [:row, 9,
385
+ [:cell, "state"],
386
+ [:cell, "other_state"]
387
+ ],
388
+ [:row, 12,
389
+ [:cell, "failing"],
390
+ [:cell, "passing"]
391
+ ]
392
+ ]
393
+ ]
394
+ ]
395
+ ]
392
396
  end
393
397
  end
394
398
  end
@@ -0,0 +1,18 @@
1
+ require File.dirname(__FILE__) + '/../../spec_helper'
2
+ require 'cucumber/rb_support/regexp_argument_matcher'
3
+
4
+ module Cucumber
5
+ module RbSupport
6
+ describe RegexpArgumentMatcher do
7
+ it "should create 2 arguments" do
8
+ arguments = RegexpArgumentMatcher.arguments_from(/I (\w+) (\w+)/, "I like fish")
9
+ arguments.map{|argument| [argument.val, argument.pos]}.should == [["like", 2], ["fish", 7]]
10
+ end
11
+
12
+ it "should create 2 arguments when first group is optional" do
13
+ arguments = RegexpArgumentMatcher.arguments_from(/should( not)? be flashed '([^']*?)'$/, "I should be flashed 'Login failed.'")
14
+ arguments.map{|argument| [argument.val, argument.pos]}.should == [[nil, nil], ["Login failed.", 21]]
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,40 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+ require 'cucumber/rb_support/rb_step_definition'
3
+ require 'cucumber/rb_support/rb_language'
4
+
5
+ module Cucumber
6
+ describe StepMatch do
7
+ before do
8
+ @rb_language = RbSupport::RbLanguage.new(nil)
9
+ end
10
+
11
+ def stepdef(regexp)
12
+ RbSupport::RbStepDefinition.new(@rb_language, regexp, lambda{})
13
+ end
14
+
15
+ it "should format groups with format string" do
16
+ m = stepdef(/I (\w+) (\d+) (\w+) this (\w+)/).step_match("I ate 1 egg this morning", nil)
17
+ m.format_args("<span>%s</span>").should == "I <span>ate</span> <span>1</span> <span>egg</span> this <span>morning</span>"
18
+ end
19
+
20
+ it "should format groups with format string when there are dupes" do
21
+ m = stepdef(/I (\w+) (\d+) (\w+) this (\w+)/).step_match("I bob 1 bo this bobs", nil)
22
+ m.format_args("<span>%s</span>").should == "I <span>bob</span> <span>1</span> <span>bo</span> this <span>bobs</span>"
23
+ end
24
+
25
+ it "should format groups with block" do
26
+ m = stepdef(/I (\w+) (\d+) (\w+) this (\w+)/).step_match("I ate 1 egg this morning", nil)
27
+ m.format_args(&lambda{|m| "<span>#{m}</span>"}).should == "I <span>ate</span> <span>1</span> <span>egg</span> this <span>morning</span>"
28
+ end
29
+
30
+ it "should format groups with proc object" do
31
+ m = stepdef(/I (\w+) (\d+) (\w+) this (\w+)/).step_match("I ate 1 egg this morning", nil)
32
+ m.format_args(lambda{|m| "<span>#{m}</span>"}).should == "I <span>ate</span> <span>1</span> <span>egg</span> this <span>morning</span>"
33
+ end
34
+
35
+ it "should format groups even when first group is optional and not matched" do
36
+ m = stepdef(/should( not)? be flashed '([^']*?)'$/).step_match("I should be flashed 'Login failed.'", nil)
37
+ m.format_args("<span>%s</span>").should == "I should be flashed '<span>Login failed.</span>'"
38
+ end
39
+ end
40
+ end