cucumber 0.3.102 → 0.3.103
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +18 -0
- data/Manifest.txt +6 -2
- data/examples/java/README.textile +3 -3
- data/examples/self_test/features/sample.feature +1 -1
- data/examples/self_test/features/search_sample.feature +1 -1
- data/features/custom_formatter.feature +4 -4
- data/features/steps_formatter.feature +2 -1
- data/lib/cucumber/ast.rb +1 -0
- data/lib/cucumber/ast/table.rb +4 -4
- data/lib/cucumber/ast/tree_walker.rb +185 -0
- data/lib/cucumber/ast/visitor.rb +2 -106
- data/lib/cucumber/cli/configuration.rb +28 -28
- data/lib/cucumber/cli/language_help_formatter.rb +5 -7
- data/lib/cucumber/cli/main.rb +3 -3
- data/lib/cucumber/core_ext/string.rb +0 -22
- data/lib/cucumber/formatter/html.rb +203 -113
- data/lib/cucumber/formatter/junit.rb +29 -23
- data/lib/cucumber/formatter/pdf.rb +74 -69
- data/lib/cucumber/formatter/pretty.rb +93 -78
- data/lib/cucumber/formatter/profile.rb +2 -2
- data/lib/cucumber/formatter/progress.rb +16 -10
- data/lib/cucumber/formatter/rerun.rb +4 -5
- data/lib/cucumber/formatter/steps.rb +6 -7
- data/lib/cucumber/formatter/tag_cloud.rb +7 -6
- data/lib/cucumber/formatter/usage.rb +7 -10
- data/lib/cucumber/language_support/step_definition_methods.rb +4 -4
- data/lib/cucumber/rails/action_controller.rb +1 -1
- data/lib/cucumber/rails/active_record.rb +27 -14
- data/lib/cucumber/rb_support/rb_language.rb +5 -0
- data/lib/cucumber/rb_support/rb_step_definition.rb +9 -16
- data/lib/cucumber/rb_support/regexp_argument_matcher.rb +21 -0
- data/lib/cucumber/step_argument.rb +9 -0
- data/lib/cucumber/step_match.rb +24 -5
- data/lib/cucumber/version.rb +1 -1
- data/rails_generators/cucumber/templates/env.rb +14 -0
- data/spec/cucumber/ast/background_spec.rb +1 -2
- data/spec/cucumber/ast/scenario_outline_spec.rb +3 -2
- data/spec/cucumber/ast/scenario_spec.rb +1 -1
- data/spec/cucumber/ast/tree_walker_spec.rb +18 -0
- data/spec/cucumber/formatter/html_spec.rb +221 -2
- data/spec/cucumber/formatter/progress_spec.rb +9 -4
- data/spec/cucumber/parser/feature_parser_spec.rb +31 -27
- data/spec/cucumber/rb_support/regexp_argument_matcher_spec.rb +18 -0
- data/spec/cucumber/step_match_spec.rb +40 -0
- metadata +8 -4
- data/lib/cucumber/rb_support/rb_group.rb +0 -11
- data/spec/cucumber/core_ext/string_spec.rb +0 -41
data/lib/cucumber/version.rb
CHANGED
@@ -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
|
|
@@ -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 =
|
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
|
-
|
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
|
@@ -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
|
-
@
|
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 { @
|
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
|
-
|
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
|
-
@
|
17
|
-
|
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
|
-
@
|
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
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
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
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
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
|