aslakhellesoy-cucumber 0.1.9 → 0.1.10

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. data/History.txt +36 -3
  2. data/Manifest.txt +15 -0
  3. data/bin/cucumber +2 -1
  4. data/config/hoe.rb +2 -1
  5. data/examples/calculator_ruby_features/features/addition.rb +1 -1
  6. data/examples/i18n/ar/features/step_definitons/calculator_steps.rb +1 -0
  7. data/examples/i18n/de/Rakefile +6 -0
  8. data/examples/i18n/de/features/addition.feature +17 -0
  9. data/examples/i18n/de/features/division.feature +10 -0
  10. data/examples/i18n/de/features/step_definitons/calculator_steps.rb +30 -0
  11. data/examples/i18n/de/lib/calculator.rb +14 -0
  12. data/examples/i18n/en/Rakefile +1 -0
  13. data/examples/i18n/lt/Rakefile +6 -0
  14. data/examples/i18n/lt/features/addition.feature +17 -0
  15. data/examples/i18n/lt/features/division.feature +10 -0
  16. data/examples/i18n/lt/features/step_definitons/calculator_steps.rb +31 -0
  17. data/examples/i18n/lt/lib/calculator.rb +14 -0
  18. data/examples/test_unit/Rakefile +6 -0
  19. data/examples/test_unit/features/step_definitions/test_unit_steps.rb +26 -0
  20. data/examples/test_unit/features/test_unit.feature +9 -0
  21. data/examples/tickets/features/tickets.feature +4 -2
  22. data/lib/autotest/discover.rb +1 -1
  23. data/lib/cucumber.rb +3 -3
  24. data/lib/cucumber/cli.rb +51 -17
  25. data/lib/cucumber/core_ext/proc.rb +31 -16
  26. data/lib/cucumber/executor.rb +35 -15
  27. data/lib/cucumber/formatters/ansicolor.rb +11 -13
  28. data/lib/cucumber/languages.yml +24 -1
  29. data/lib/cucumber/platform.rb +12 -0
  30. data/lib/cucumber/step_mother.rb +7 -1
  31. data/lib/cucumber/tree/feature.rb +3 -1
  32. data/lib/cucumber/tree/scenario.rb +17 -1
  33. data/lib/cucumber/treetop_parser/feature_de.rb +8 -8
  34. data/lib/cucumber/treetop_parser/feature_lt.rb +1591 -0
  35. data/rails_generators/cucumber/templates/webrat_steps.rb +49 -0
  36. data/rails_generators/feature/templates/feature.erb +3 -3
  37. data/spec/cucumber/cli_spec.rb +172 -2
  38. data/spec/cucumber/executor_spec.rb +104 -28
  39. data/spec/cucumber/step_mother_spec.rb +7 -7
  40. data/spec/cucumber/tree/feature_spec.rb +31 -0
  41. data/spec/cucumber/tree/row_scenario_spec.rb +30 -0
  42. data/spec/spec_helper.rb +1 -0
  43. metadata +21 -6
@@ -1,6 +1,8 @@
1
1
  # Commonly used webrat steps
2
2
  # http://github.com/brynary/webrat
3
3
 
4
+ require 'webrat' if !defined?(Webrat) # Because some people have it installed as a Gem
5
+
4
6
  When /^I press "(.*)"$/ do |button|
5
7
  clicks_button(button)
6
8
  end
@@ -17,6 +19,53 @@ When /^I select "(.*)" from "(.*)"$/ do |value, field|
17
19
  selects(value, :from => field)
18
20
  end
19
21
 
22
+ # Use this step in conjunction with Rail's datetime_select helper. For example:
23
+ # When I select "December 25, 2008 10:00" as the date and time
24
+ When /^I select "(.*)" as the date and time$/ do |time|
25
+ selects_datetime(time)
26
+ end
27
+
28
+ # Use this step when using multiple datetime_select helpers on a page or
29
+ # you want to specify which datetime to select. Given the following view:
30
+ # <%= f.label :preferred %><br />
31
+ # <%= f.datetime_select :preferred %>
32
+ # <%= f.label :alternative %><br />
33
+ # <%= f.datetime_select :alternative %>
34
+ # The following steps would fill out the form:
35
+ # When I select "November 23, 2004 11:20" as the "Preferred" data and time
36
+ # And I select "November 25, 2004 10:30" as the "Alternative" data and time
37
+ When /^I select "(.*)" as the "(.*)" date and time$/ do |datetime, datetime_label|
38
+ selects_datetime(datetime, :from => datetime_label)
39
+ end
40
+
41
+ # Use this step in conjuction with Rail's time_select helper. For example:
42
+ # When I select "2:20PM" as the time
43
+ # Note: Rail's default time helper provides 24-hour time-- not 12 hour time. Webrat
44
+ # will convert the 2:20PM to 14:20 and then select it.
45
+ When /^I select "(.*)" as the time$/ do |time|
46
+ selects_time(time)
47
+ end
48
+
49
+ # Use this step when using multiple time_select helpers on a page or you want to
50
+ # specify the name of the time on the form. For example:
51
+ # When I select "7:30AM" as the "Gym" time
52
+ When /^I select "(.*)" as the "(.*)" time$/ do |time, time_label|
53
+ selects_time(time, :from => time_label)
54
+ end
55
+
56
+ # Use this step in conjuction with Rail's date_select helper. For example:
57
+ # When I select "February 20, 1981" as the date
58
+ When /^I select "(.*)" as the date$/ do |date|
59
+ selects_date(date)
60
+ end
61
+
62
+ # Use this step when using multiple date_select helpers on one page or
63
+ # you want to specify the name of the date on the form. For example:
64
+ # When I select "April 26, 1982" as the "Date of Birth" date
65
+ When /^I select "(.*)" as the "(.*)" date$/ do |date, date_label|
66
+ selects_date(date, :from => date_label)
67
+ end
68
+
20
69
  When /^I check "(.*)"$/ do |field|
21
70
  checks(field)
22
71
  end
@@ -1,7 +1,7 @@
1
1
  Feature: Manage <%= plural_name %>
2
- In order to keep track of <%= plural_name %>
3
- A <%= singular_name %> mechanic
4
- Should be able to manage several <%= plural_name %>
2
+ In order to [goal]
3
+ [stakeholder]
4
+ wants [behaviour]
5
5
 
6
6
  Scenario: Register new <%= singular_name %>
7
7
  Given I am on the new <%= singular_name %> page
@@ -5,13 +5,17 @@ module Cucumber
5
5
  describe CLI do
6
6
 
7
7
  def mock_executor(stubs = {})
8
- stub('executor', {:visit_features => nil, :failed => false, :formatters= => nil}.merge(stubs))
8
+ stub('executor', {:visit_features => nil, :lines_for_features= => nil, :failed => false, :formatters= => nil}.merge(stubs))
9
9
  end
10
10
 
11
11
  def mock_broadcaster(stubs = {})
12
12
  stub(Broadcaster, {:register => nil}.merge(stubs))
13
13
  end
14
14
 
15
+ def mock_features(stubs ={})
16
+ stub('features', {:<< => nil}.merge(stubs))
17
+ end
18
+
15
19
  before(:each) do
16
20
  Kernel.stub!(:exit)
17
21
  end
@@ -101,6 +105,40 @@ Defined profiles in cucumber.yml:
101
105
  cli.options[:source].should be_false
102
106
  end
103
107
 
108
+ it "should accept --verbose option" do
109
+ cli = CLI.new
110
+ cli.parse_options!(%w{--verbose})
111
+
112
+ cli.options[:verbose].should be_true
113
+ end
114
+
115
+ describe "verbose mode" do
116
+
117
+ before(:each) do
118
+ @out = StringIO.new
119
+ @cli = CLI.new(@out)
120
+ @cli.stub!(:require)
121
+ Dir.stub!(:[])
122
+ end
123
+
124
+ it "should show ruby files required" do
125
+ @cli.parse_options!(%w{--verbose --require example.rb})
126
+ @cli.execute!(stub('step mother'), mock_executor, mock_features)
127
+
128
+ @out.string.should include('example.rb')
129
+ end
130
+
131
+ it "should show feature files parsed" do
132
+ TreetopParser::FeatureParser.stub!(:new).and_return(mock("feature parser", :parse_feature => nil))
133
+
134
+ @cli.parse_options!(%w{--verbose example.feature})
135
+ @cli.execute!(stub('step mother'), mock_executor, mock_features)
136
+
137
+ @out.string.should include('example.feature')
138
+ end
139
+
140
+ end
141
+
104
142
  it "should accept --out option" do
105
143
  cli = CLI.new
106
144
  File.should_receive(:open).with('jalla.txt', 'w')
@@ -180,6 +218,106 @@ Defined profiles in cucumber.yml:
180
218
  cli.execute!(stub('step mother'), mock_executor, stub('features'))
181
219
  end
182
220
 
221
+ describe "external formatter" do
222
+
223
+ describe "exists and valid constructor" do
224
+
225
+ before(:each) do
226
+ @mock_formatter_class = mock('formatter class')
227
+ Kernel.stub!(:const_get).and_return(@mock_formatter_class)
228
+ end
229
+
230
+ it "should create the formatter" do
231
+ cli = CLI.new
232
+ mock_formatter = mock('magical formatter')
233
+ cli.parse_options!(%w{--format magical})
234
+
235
+ @mock_formatter_class.should_receive(:new)
236
+
237
+ cli.execute!(stub('step mother'), mock_executor, stub('features'))
238
+ end
239
+
240
+ it "should register the formatter with broadcaster" do
241
+ cli = CLI.new
242
+ broadcaster = Broadcaster.new
243
+ mock_formatter = mock('magical formatter')
244
+ Broadcaster.stub!(:new).and_return(broadcaster, stub("output broadcaster", :register => nil))
245
+ @mock_formatter_class.stub!(:new).and_return(mock_formatter)
246
+ cli.parse_options!(%w{--format magical})
247
+
248
+ broadcaster.should_receive(:register).with(mock_formatter)
249
+
250
+ cli.execute!(stub('step mother'), mock_executor, stub('features'))
251
+ end
252
+
253
+ end
254
+
255
+ describe "exists but invalid constructor" do
256
+
257
+ before(:each) do
258
+ @out = StringIO.new
259
+ @error = StringIO.new
260
+ @cli = CLI.new(@out, @error)
261
+
262
+ mock_formatter_class = stub('formatter class')
263
+ mock_formatter_class.stub!(:new).and_raise("No such method")
264
+ Kernel.stub!(:const_get).and_return(mock_formatter_class)
265
+
266
+ @cli.parse_options!(%w{--format exists_but_evil})
267
+ end
268
+
269
+ it "should show exception" do
270
+ Kernel.stub!(:exit)
271
+
272
+ @cli.execute!(stub('step mother'), mock_executor, stub('features'))
273
+
274
+ @error.string.should include("No such method")
275
+ end
276
+
277
+ it "should exit" do
278
+ Kernel.should_receive(:exit)
279
+
280
+ @cli.execute!(stub('step mother'), mock_executor, stub('features'))
281
+ end
282
+
283
+ end
284
+
285
+ describe "non-existent" do
286
+
287
+ before(:each) do
288
+ @out = StringIO.new
289
+ @error = StringIO.new
290
+ @cli = CLI.new(@out, @error)
291
+
292
+ @cli.parse_options!(%w{--format invalid})
293
+ end
294
+
295
+ it "should display a format error" do
296
+ Kernel.stub!(:exit)
297
+
298
+ @cli.execute!(stub('step mother'), mock_executor, stub('features'))
299
+
300
+ @error.string.should include("Invalid format: invalid\n")
301
+ end
302
+
303
+ it "should display --help" do
304
+ Kernel.stub!(:exit)
305
+
306
+ @cli.execute!(stub('step mother'), mock_executor, stub('features'))
307
+
308
+ @out.string.should include("Usage: cucumber")
309
+ end
310
+
311
+ it "should exit" do
312
+ Kernel.should_receive(:exit)
313
+
314
+ @cli.execute!(stub('step mother'), mock_executor, stub('features'))
315
+ end
316
+
317
+ end
318
+
319
+ end
320
+
183
321
  it "should accept multiple --scenario options" do
184
322
  cli = CLI.new
185
323
  cli.parse_options!(['--scenario', "User logs in", '--scenario', "User signs up"])
@@ -227,6 +365,38 @@ Defined profiles in cucumber.yml:
227
365
  cli.execute!(stub('step mother'), mock_executor, stub('features'))
228
366
  end
229
367
 
368
+ describe "example.feature:line file arguments" do
369
+
370
+ it "should extract line numbers" do
371
+ cli = CLI.new
372
+ cli.parse_options!(%w{example.feature:10})
373
+
374
+ cli.options[:lines_for_features]['example.feature'].should == [10]
375
+ end
376
+
377
+ it "should remove line numbers" do
378
+ cli = CLI.new
379
+ cli.parse_options!(%w{example.feature:10})
380
+
381
+ cli.paths.should == ["example.feature"]
382
+ end
383
+
384
+ it "should support multiple feature:line numbers" do
385
+ cli = CLI.new
386
+ cli.parse_options!(%w{example.feature:11 another_example.feature:12})
387
+
388
+ cli.options[:lines_for_features].should == {'another_example.feature' => [12], 'example.feature' => [11]}
389
+ end
390
+
391
+ it "should accept multiple line numbers for a single feature" do
392
+ cli = CLI.new
393
+ cli.parse_options!(%w{example.feature:11:12})
394
+
395
+ cli.options[:lines_for_features].should == {'example.feature' => [11, 12]}
396
+ end
397
+
398
+ end
399
+
230
400
  it "should search for all features in the specified directory" do
231
401
  cli = CLI.new
232
402
 
@@ -235,7 +405,7 @@ Defined profiles in cucumber.yml:
235
405
 
236
406
  Dir.should_receive(:[]).with("feature_directory/**/*.feature").any_number_of_times.and_return([])
237
407
 
238
- cli.execute!(stub('step mother'), mock_executor, stub('features', :<< => nil))
408
+ cli.execute!(stub('step mother'), mock_executor, mock_features)
239
409
  end
240
410
 
241
411
  end
@@ -3,6 +3,17 @@ require 'stringio'
3
3
 
4
4
  module Cucumber
5
5
  describe Executor do
6
+
7
+ def mock_scenario(stubs = {})
8
+ @scenario ||= stub("scenario", {
9
+ :row? => false,
10
+ :name => 'test',
11
+ :accept => nil,
12
+ :steps => [],
13
+ :pending? => true
14
+ }.merge(stubs))
15
+ end
16
+
6
17
  before do # TODO: Way more setup and duplication of lib code. Use lib code!
7
18
  @io = StringIO.new
8
19
  @step_mother = StepMother.new
@@ -35,19 +46,47 @@ module Cucumber
35
46
 
36
47
  1)
37
48
  dang
38
- #{__FILE__}:32:in `Then /I should owe (\\d*) cucumbers/'
49
+ #{__FILE__}:43:in `Then /I should owe (\\d*) cucumbers/'
39
50
  #{@feature_file}:9:in `Then I should owe 7 cucumbers'
40
51
  })
41
52
  end
42
53
 
43
- # it "should allow calling of other steps from steps" do
44
- # @executor.register_step_proc("call me please") { @x = 1 }
45
- # @executor.register_step_proc("I will call you") { @executor.register_step_proc("call me please") }
46
- # @executor.register_step_proc(/I should owe (\d*) cucumbers/) { |n| @n.should == -n.to_i }
47
- # @feature.accept(@executor)
48
- # @formatters.each { |formatter| formatter.dump }
49
- # @io.string.should == "...\n"
50
- # end
54
+ describe "creating a world" do
55
+ module DoitExtension
56
+ def doit
57
+ "dunit"
58
+ end
59
+ end
60
+
61
+ module BeatitExtension
62
+ def beatit
63
+ "beatenit"
64
+ end
65
+ end
66
+
67
+ it "should yield an Object to the world proc" do
68
+ @executor.register_world_proc do |world|
69
+ world.extend(DoitExtension)
70
+ end
71
+ @executor.register_world_proc do |world|
72
+ world.extend(BeatitExtension)
73
+ end
74
+ world = @executor.create_world
75
+ world.doit.should == "dunit"
76
+ world.beatit.should == "beatenit"
77
+ end
78
+ end
79
+
80
+ describe "visiting feature" do
81
+
82
+ it "should set the feature file being visited" do
83
+ mock_feature = mock('feature', :file => 'womble.feature', :scenarios => [])
84
+ @executor.visit_feature(mock_feature)
85
+
86
+ @executor.instance_variable_get('@feature_file').should == 'womble.feature'
87
+ end
88
+
89
+ end
51
90
 
52
91
  describe "visiting steps" do
53
92
  def make_regex(a,b,c)
@@ -139,21 +178,22 @@ dang
139
178
  describe "without having first run the matching regular scenario" do
140
179
 
141
180
  before(:each) do
142
- @scenario = Tree::Scenario.new(nil, 'test', 1)
143
- @executor.line=5
144
- @executor.visit_regular_scenario(@scenario)
181
+ @regular_scenario = Tree::Scenario.new(nil, 'test', 1)
182
+ @executor.lines_for_features = Hash.new([5])
183
+ @executor.visit_regular_scenario(@regular_scenario)
145
184
  end
146
185
 
147
186
  it "should run the regular scenario before the row scenario" do
148
- @scenario.should_receive(:accept)
149
-
150
- @executor.visit_row_scenario(mock_row_scenario(:name => 'test', :at_line? => true, :accept => nil))
187
+ @regular_scenario.should_receive(:accept)
188
+ row_scenario = mock_row_scenario(:name => 'test', :at_line? => true)
189
+ row_scenario.should_receive(:accept)
190
+ @executor.visit_row_scenario(row_scenario)
151
191
  end
152
192
 
153
193
  it "should run the row scenario after running the regular scenario" do
154
- mock_row_scenario(:at_line? => true).should_receive(:accept)
155
-
156
- @executor.visit_row_scenario(mock_row_scenario)
194
+ row_scenario = mock_row_scenario(:at_line? => true)
195
+ row_scenario.should_receive(:accept)
196
+ @executor.visit_row_scenario(row_scenario)
157
197
  end
158
198
 
159
199
  end
@@ -172,18 +212,53 @@ dang
172
212
  end
173
213
  end
174
214
 
175
- describe "caching visited scenarios" do
215
+ describe "visiting scenarios" do
216
+
217
+ it "should check if a scenario is at the specified line number" do
218
+ mock_scenario = mock('scenario', :null_object => true)
219
+ @executor.lines_for_features = Hash.new([1])
176
220
 
177
- def mock_scenario(stubs = {})
178
- @scenario ||= stub("scenario", {
179
- :row? => false,
180
- :name => 'test',
181
- :accept => nil,
182
- :steps => [],
183
- :pending? => true
184
- }.merge(stubs))
221
+ mock_scenario.should_receive(:at_line?).with(1)
222
+
223
+ @executor.visit_scenario(mock_scenario)
185
224
  end
186
-
225
+
226
+ describe "with specific features and lines" do
227
+
228
+ it "should check if a scenario is at the specified feature line number" do
229
+ @executor.instance_variable_set('@feature_file', 'sell_cucumbers.feature')
230
+ @executor.lines_for_features = {'sell_cucumbers.feature' => [11]}
231
+
232
+ mock_scenario.should_receive(:at_line?).with(11).and_return(false)
233
+
234
+ @executor.visit_scenario(mock_scenario)
235
+ end
236
+
237
+ it "should not check feature line numbers if --line is already set" do
238
+ @executor.instance_variable_set('@feature_file', 'sell_cucumbers.feature')
239
+ @executor.lines_for_features = {'sell_cucumbers.feature' => [11]}
240
+ @executor.lines_for_features = Hash.new([5])
241
+
242
+ mock_scenario.should_not_receive(:at_line?).with(11).and_return(false)
243
+
244
+ @executor.visit_scenario(mock_scenario)
245
+ end
246
+
247
+ it "should not check feature line numbers if the current feature file does not have lines specified" do
248
+ @executor.instance_variable_set('@feature_file', 'beetlejuice.feature')
249
+ @executor.lines_for_features = {'sell_cucumbers.feature' => [11]}
250
+
251
+ mock_scenario.should_not_receive(:at_line?).with(11).and_return(false)
252
+
253
+ @executor.visit_scenario(mock_scenario)
254
+ end
255
+
256
+ end
257
+
258
+ end
259
+
260
+ describe "caching visited scenarios" do
261
+
187
262
  it "should reset cache after each feature visit" do
188
263
  Tree::Scenario.stub!(:new).and_return(mock_scenario)
189
264
 
@@ -218,5 +293,6 @@ dang
218
293
  @executor.visit_features(@features)
219
294
  end
220
295
  end
296
+
221
297
  end
222
298
  end