aslakhellesoy-cucumber 0.3.0 → 0.3.0.1

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 (49) hide show
  1. data/History.txt +18 -1
  2. data/Manifest.txt +15 -1
  3. data/config/hoe.rb +5 -4
  4. data/examples/i18n/hu/Rakefile +6 -0
  5. data/examples/i18n/hu/features/addition.feature +16 -0
  6. data/examples/i18n/hu/features/division.feature +9 -0
  7. data/examples/i18n/hu/features/step_definitons/calculator_steps.rb +25 -0
  8. data/examples/i18n/hu/lib/calculator.rb +14 -0
  9. data/examples/i18n/lv/Rakefile +6 -0
  10. data/examples/i18n/lv/features/addition.feature +16 -0
  11. data/examples/i18n/lv/features/division.feature +9 -0
  12. data/examples/i18n/lv/features/step_definitons/calculator_steps.rb +24 -0
  13. data/examples/i18n/lv/lib/calculator.rb +14 -0
  14. data/examples/self_test/features/multiline_name.feature +27 -0
  15. data/examples/tickets/Rakefile +3 -3
  16. data/examples/tickets/features/272/hooks.feature +26 -0
  17. data/examples/tickets/features/272/hooks_steps.rb +53 -0
  18. data/features/cucumber_cli.feature +32 -2
  19. data/features/multiline_names.feature +43 -0
  20. data/features/report_called_undefined_steps.feature +1 -1
  21. data/features/usage.feature +4 -0
  22. data/lib/cucumber/ast/background.rb +3 -6
  23. data/lib/cucumber/ast/feature_element.rb +18 -9
  24. data/lib/cucumber/ast/outline_table.rb +10 -0
  25. data/lib/cucumber/ast/scenario.rb +16 -1
  26. data/lib/cucumber/ast/scenario_outline.rb +1 -1
  27. data/lib/cucumber/ast/step.rb +4 -2
  28. data/lib/cucumber/ast/step_collection.rb +9 -1
  29. data/lib/cucumber/ast/table.rb +4 -0
  30. data/lib/cucumber/formatter/console.rb +1 -1
  31. data/lib/cucumber/formatter/html.rb +1 -1
  32. data/lib/cucumber/formatter/pretty.rb +7 -8
  33. data/lib/cucumber/languages.yml +30 -0
  34. data/lib/cucumber/parser/feature.rb +196 -10
  35. data/lib/cucumber/parser/feature.tt +26 -10
  36. data/lib/cucumber/rails/world.rb +6 -0
  37. data/lib/cucumber/step_mother.rb +2 -1
  38. data/lib/cucumber/version.rb +1 -1
  39. data/lib/cucumber/world.rb +2 -2
  40. data/rails_generators/cucumber/templates/paths.rb +11 -13
  41. data/rails_generators/feature/feature_generator.rb +1 -1
  42. data/spec/cucumber/ast/feature_element_spec.rb +35 -0
  43. data/spec/cucumber/ast/table_spec.rb +6 -2
  44. data/spec/cucumber/cli/configuration_spec.rb +0 -9
  45. data/spec/cucumber/cli/main_spec.rb +55 -153
  46. data/spec/cucumber/parser/feature_parser_spec.rb +79 -0
  47. data/spec/cucumber/step_mother_spec.rb +12 -5
  48. metadata +17 -13
  49. data/spec/cucumber/formatters/profile_formatter_spec.rb +0 -198
@@ -76,13 +76,13 @@ module Cucumber
76
76
  end
77
77
 
78
78
  rule background
79
- comment white background_keyword space* name:line_to_eol? (eol+ / eof) steps {
79
+ comment white background_keyword space* name:lines_to_keyword? (eol+ / eof) steps {
80
80
  def build
81
81
  Ast::Background.new(
82
82
  comment.build,
83
83
  background_keyword.line,
84
84
  background_keyword.text_value,
85
- name.text_value,
85
+ name.build,
86
86
  steps.build
87
87
  )
88
88
  end
@@ -106,7 +106,7 @@ module Cucumber
106
106
  end
107
107
 
108
108
  rule scenario
109
- comment tags white scenario_keyword space* name:line_to_eol white steps white {
109
+ comment tags white scenario_keyword space* name:lines_to_keyword white steps white {
110
110
  def at_line?(line)
111
111
  scenario_keyword.line == line ||
112
112
  steps.at_line?(line) ||
@@ -119,7 +119,7 @@ module Cucumber
119
119
  end
120
120
 
121
121
  def matches_name?(name_to_match)
122
- name.text_value == name_to_match
122
+ name.build == name_to_match
123
123
  end
124
124
 
125
125
  def build(background, filter)
@@ -129,7 +129,7 @@ module Cucumber
129
129
  tags.build,
130
130
  scenario_keyword.line,
131
131
  scenario_keyword.text_value,
132
- name.text_value,
132
+ name.build,
133
133
  steps.build
134
134
  )
135
135
  end
@@ -137,7 +137,7 @@ module Cucumber
137
137
  end
138
138
 
139
139
  rule scenario_outline
140
- comment tags white scenario_outline_keyword space* name:line_to_eol white steps examples_sections white {
140
+ comment tags white scenario_outline_keyword space* name:lines_to_keyword white steps examples_sections white {
141
141
  def at_line?(line)
142
142
  outline_at_line?(line) ||
143
143
  examples_sections.at_line?(line) ||
@@ -155,7 +155,7 @@ module Cucumber
155
155
  end
156
156
 
157
157
  def matches_name?(name_to_match)
158
- name.text_value == name_to_match
158
+ name.build == name_to_match
159
159
  end
160
160
 
161
161
  def build(background, filter)
@@ -165,7 +165,7 @@ module Cucumber
165
165
  tags.build,
166
166
  scenario_outline_keyword.line,
167
167
  scenario_outline_keyword.text_value,
168
- name.text_value,
168
+ name.build,
169
169
  steps.build,
170
170
  examples_sections.build(filter, self)
171
171
  )
@@ -219,7 +219,7 @@ module Cucumber
219
219
  end
220
220
 
221
221
  rule examples
222
- space* examples_keyword space* name:line_to_eol? eol table white {
222
+ space* examples_keyword space* name:lines_to_keyword? eol table white {
223
223
  def at_line?(line)
224
224
  examples_keyword.line == line ||
225
225
  table.at_line?(line)
@@ -234,7 +234,7 @@ module Cucumber
234
234
  end
235
235
 
236
236
  def build(filter, scenario_outline)
237
- [examples_keyword.line, examples_keyword.text_value, name.text_value, table.raw(filter, scenario_outline)]
237
+ [examples_keyword.line, examples_keyword.text_value, name.build, table.raw(filter, scenario_outline)]
238
238
  end
239
239
  }
240
240
  end
@@ -247,6 +247,22 @@ module Cucumber
247
247
  (!eol .)*
248
248
  end
249
249
 
250
+ rule line_to_keyword
251
+ white text:(!step_keyword !scenario_keyword !scenario_outline_keyword !table !tag !comment_line !eol .)+ {
252
+ def build
253
+ text.text_value.strip
254
+ end
255
+ }
256
+ end
257
+
258
+ rule lines_to_keyword
259
+ (line_to_keyword)* {
260
+ def build
261
+ elements.map{|s| s.build}.join("\n")
262
+ end
263
+ }
264
+ end
265
+
250
266
  rule py_string
251
267
  open_py_string s:(!close_py_string .)* close_py_string {
252
268
  def at_line?(line)
@@ -9,6 +9,7 @@ else
9
9
  end
10
10
  require 'test/unit/testresult'
11
11
 
12
+
12
13
  # So that Test::Unit doesn't launch at the end - makes it think it has already been run.
13
14
  Test::Unit.run = true if Test::Unit.respond_to?(:run=)
14
15
 
@@ -30,6 +31,11 @@ module Cucumber #:nodoc:
30
31
  end
31
32
 
32
33
  def self.use_transactional_fixtures
34
+
35
+ unless ::Rails.configuration.cache_classes
36
+ warn "WARNING: You have set Rail's config.cache_classes to false (most likely in config/environments/test.rb). This setting is known to break Cucumber's use_transactional_fixtures method. Set config.cache_classes to true if you want to use transactional fixtures. For more information see https://rspec.lighthouseapp.com/projects/16211/tickets/165."
37
+ end
38
+
33
39
  World.use_transactional_fixtures = true
34
40
  if defined?(ActiveRecord::Base)
35
41
  $__cucumber_toplevel.Before do
@@ -57,7 +57,8 @@ module Cucumber
57
57
  message << "in 2 places:\n\n"
58
58
  message << first_proc.backtrace_line('World') << "\n"
59
59
  message << second_proc.backtrace_line('World') << "\n\n"
60
- message << "Use Ruby modules instead to extend your worlds. See the #World RDoc.\n\n"
60
+ message << "Use Ruby modules instead to extend your worlds. See the Cucumber::StepMother#World RDoc\n"
61
+ message << "or http://wiki.github.com/aslakhellesoy/cucumber/a-whole-new-world.\n\n"
61
62
  super(message)
62
63
  end
63
64
  end
@@ -3,7 +3,7 @@ module Cucumber #:nodoc:
3
3
  MAJOR = 0
4
4
  MINOR = 3
5
5
  TINY = 0
6
- PATCH = nil # Set to nil for official release
6
+ PATCH = 1 # Set to nil for official release
7
7
 
8
8
  STRING = [MAJOR, MINOR, TINY, PATCH].compact.join('.')
9
9
  end
@@ -16,7 +16,7 @@ module Cucumber
16
16
  step_match.invoke(self, multiline_argument)
17
17
  rescue Exception => e
18
18
  e.nested! if Undefined === e
19
- @__cucumber_current_step.exception = e
19
+ @__cucumber_current_step.exception = e if @__cucumber_current_step
20
20
  raise e
21
21
  end
22
22
  end
@@ -50,4 +50,4 @@ module Cucumber
50
50
  end
51
51
  end
52
52
  end
53
- end
53
+ end
@@ -1,27 +1,25 @@
1
1
  module NavigationHelpers
2
- # Maps a static name to a static route.
2
+ # Maps a name to a path. Used by the
3
3
  #
4
- # This method is *not* designed to map from a dynamic name to a
5
- # dynamic route like <tt>post_comments_path(post)</tt>. For dynamic
6
- # routes like this you should *not* rely on #path_to, but write
7
- # your own step definitions instead. Example:
4
+ # When /^I go to (.+)$/ do |page_name|
8
5
  #
9
- # Given /I am on the comments page for the "(.+)" post/ |name|
10
- # post = Post.find_by_name(name)
11
- # visit post_comments_path(post)
12
- # end
6
+ # step definition in webrat_steps.rb
13
7
  #
14
8
  def path_to(page_name)
15
9
  case page_name
16
10
 
17
11
  when /the homepage/
18
- root_path
19
-
20
- # Add more page name => path mappings here
12
+ '/'
21
13
 
14
+ # Add more mappings here.
15
+ # Here is a more fancy example:
16
+ #
17
+ # when /^(.*)'s profile page$/i
18
+ # user_profile_path(User.find_by_login($1))
19
+
22
20
  else
23
21
  raise "Can't find mapping from \"#{page_name}\" to a path.\n" +
24
- "Now, go and add a mapping in features/support/paths.rb"
22
+ "Now, go and add a mapping in #{__FILE__}"
25
23
  end
26
24
  end
27
25
  end
@@ -6,7 +6,7 @@ class FeatureGenerator < Rails::Generator::NamedBase
6
6
  m.template 'feature.erb', "features/manage_#{plural_name}.feature"
7
7
  m.template 'steps.erb', "features/step_definitions/#{singular_name}_steps.rb"
8
8
 
9
- m.gsub_file 'features/support/paths.rb', /root_path/mi do |match|
9
+ m.gsub_file 'features/support/paths.rb', /'\/'/mi do |match|
10
10
  "#{match}\n when /the new #{singular_name} page/\n new_#{singular_name}_path\n"
11
11
  end
12
12
  end
@@ -0,0 +1,35 @@
1
+ require File.dirname(__FILE__) + '/../../spec_helper'
2
+ require 'cucumber/step_mother'
3
+ require 'cucumber/ast'
4
+
5
+ module Cucumber
6
+ describe FeatureElement do
7
+ include FeatureElement
8
+
9
+ describe "with multiline names" do
10
+ it "should select the longest line as the text length" do
11
+ @keyword = "key"
12
+ @name = "short\nvery longer\ntiny"
13
+ text_length.should == 11 + Ast::Step::INDENT - 1
14
+ end
15
+
16
+ it "should add keyword to first lines length" do
17
+ @keyword = "key"
18
+ @name = "short\nvery longer\ntiny"
19
+
20
+ first_line_length.should == (@keyword.jlength) + (first_line_name_length = 5)
21
+ end
22
+ end
23
+
24
+ describe "with empty name" do
25
+ it "should only return the length of the keyword" do
26
+ @name = ""
27
+ @keyword = "key"
28
+
29
+ text_length.should == 3
30
+ end
31
+ end
32
+
33
+ end
34
+ end
35
+
@@ -21,6 +21,10 @@ module Cucumber
21
21
  @table.columns[1].map{|cell| cell.value}.should == %w{four 55555}
22
22
  end
23
23
 
24
+ it "should have headers" do
25
+ @table.headers.should == %w{one four seven}
26
+ end
27
+
24
28
  it "should have same cell objects in rows and columns" do
25
29
  # 666666
26
30
  @table.cells_rows[1].__send__(:[], 2).should equal(@table.columns[2].__send__(:[], 1))
@@ -57,7 +61,7 @@ module Cucumber
57
61
  }.should raise_error('The column named "two" does not exist')
58
62
  end
59
63
 
60
- describe ".transpose" do
64
+ describe "#transpose" do
61
65
  before(:each) do
62
66
  @table = Table.new([
63
67
  %w{one 1111},
@@ -70,7 +74,7 @@ module Cucumber
70
74
  end
71
75
  end
72
76
 
73
- describe ".rows_hash" do
77
+ describe "#rows_hash" do
74
78
 
75
79
  it "should return a hash of the rows" do
76
80
  table = Table.new([
@@ -234,15 +234,6 @@ END_OF_MESSAGE
234
234
  end
235
235
  end
236
236
 
237
- xit "should strip gems when --backtrace is absent" do
238
- config = Main.new(['--'])
239
- begin
240
- "x".should == "y"
241
- rescue => e
242
- e.backtrace[0].should == "#{__FILE__}:#{__LINE__ - 2}"
243
- end
244
- end
245
-
246
237
  after do
247
238
  Exception.cucumber_full_backtrace = false
248
239
  end
@@ -7,189 +7,91 @@ rescue ::LoadError
7
7
  end
8
8
 
9
9
  module Cucumber
10
- module Cli
11
- describe Main do
12
- before(:each) do
13
- @out = StringIO.new
14
- Kernel.stub!(:exit).and_return(nil)
15
- end
16
-
17
- describe "verbose mode" do
18
-
10
+ module Cli
11
+ describe Main do
19
12
  before(:each) do
20
- @empty_feature = Ast::Feature.new(nil, Ast::Comment.new(''), Ast::Tags.new(2, []), "Feature", [])
21
- Dir.stub!(:[])
13
+ @out = StringIO.new
14
+ Kernel.stub!(:exit).and_return(nil)
22
15
  end
23
16
 
24
- it "should show ruby files required" do
25
- @cli = Main.new(%w{--verbose --require example.rb}, @out)
26
- @cli.stub!(:require)
17
+ describe "verbose mode" do
18
+
19
+ before(:each) do
20
+ @empty_feature = Ast::Feature.new(nil, Ast::Comment.new(''), Ast::Tags.new(2, []), "Feature", [])
21
+ Dir.stub!(:[])
22
+ end
23
+
24
+ it "should show ruby files required" do
25
+ @cli = Main.new(%w{--verbose --require example.rb}, @out)
26
+ @cli.stub!(:require)
27
27
 
28
- @cli.execute!(Object.new.extend(StepMother))
28
+ @cli.execute!(Object.new.extend(StepMother))
29
29
 
30
- @out.string.should include('example.rb')
31
- end
30
+ @out.string.should include('example.rb')
31
+ end
32
32
 
33
- it "should show feature files parsed" do
34
- @cli = Main.new(%w{--verbose example.feature}, @out)
35
- @cli.stub!(:require)
33
+ it "should show feature files parsed" do
34
+ @cli = Main.new(%w{--verbose example.feature}, @out)
35
+ @cli.stub!(:require)
36
36
 
37
- Parser::FeatureParser.stub!(:new).and_return(mock("feature parser", :parse_file => @empty_feature))
37
+ Parser::FeatureParser.stub!(:new).and_return(mock("feature parser", :parse_file => @empty_feature))
38
38
 
39
- @cli.execute!(Object.new.extend(StepMother))
39
+ @cli.execute!(Object.new.extend(StepMother))
40
40
 
41
- @out.string.should include('example.feature')
42
- end
41
+ @out.string.should include('example.feature')
42
+ end
43
43
 
44
- end
44
+ end
45
45
 
46
- describe "diffing" do
46
+ describe "diffing" do
47
47
 
48
- before :each do
49
- @configuration = mock('Configuration', :null_object => true)
50
- Configuration.should_receive(:new).and_return(@configuration)
51
-
52
- @step_mother = mock('StepMother', :null_object => true)
48
+ before :each do
49
+ @configuration = mock('Configuration', :null_object => true)
50
+ Configuration.should_receive(:new).and_return(@configuration)
53
51
 
54
- @cli = Main.new(nil, @out)
55
- end
56
-
57
- it "uses Spec Differ::Default when diff is enabled" do
58
- @configuration.should_receive(:diff_enabled?).and_return(true)
52
+ @step_mother = mock('StepMother', :null_object => true)
59
53
 
60
- ::Spec::Expectations::Differs::Default.should_receive(:new)
61
-
62
- @cli.execute!(@step_mother)
63
- end
64
-
65
- it "does not use Spec Differ::Default when diff is disabled" do
66
- @configuration.should_receive(:diff_enabled?).and_return(false)
67
-
68
- ::Spec::Expectations::Differs::Default.should_not_receive(:new)
69
-
70
- @cli.execute!(@step_mother)
71
- end
72
-
73
- end
74
-
75
- describe "--format with class" do
76
-
77
- describe "in module" do
78
-
79
- it "should resolve each module until it gets Formatter class" do
80
- cli = Main.new(%w{--format ZooModule::MonkeyFormatterClass}, nil)
81
- mock_module = mock('module')
82
- Object.stub!(:const_defined?).and_return(true)
83
- mock_module.stub!(:const_defined?).and_return(true)
84
-
85
- f = stub('formatter', :null_object => true)
86
-
87
- Object.should_receive(:const_get).with('ZooModule').and_return(mock_module)
88
- mock_module.should_receive(:const_get).with('MonkeyFormatterClass').and_return(mock('formatter class', :new => f))
89
-
90
- cli.execute!(Object.new.extend(StepMother))
91
- end
92
-
93
- end
94
-
95
- describe "exists and valid constructor" do
96
-
97
- before(:each) do
98
- @mock_formatter_class = mock('formatter class')
99
- Object.stub!(:const_get).and_return(@mock_formatter_class)
100
- Object.stub!(:const_defined?).with('magical').and_return(true)
54
+ @cli = Main.new(nil, @out)
101
55
  end
56
+
57
+ it "uses Spec Differ::Default when diff is enabled" do
58
+ @configuration.should_receive(:diff_enabled?).and_return(true)
102
59
 
103
- xit "should create the formatter" do
104
- cli = Main.new
105
- mock_formatter = mock('magical formatter')
106
- cli.parse_options!(%w{--format magical})
107
-
108
- @mock_formatter_class.should_receive(:new)
109
-
110
- cli.execute!(stub('step mother'), mock_executor, stub('features'))
111
- end
112
-
113
- xit "should register the formatter with broadcaster" do
114
- cli = Main.new
115
- broadcaster = Broadcaster.new
116
- mock_formatter = mock('magical formatter')
117
- Broadcaster.stub!(:new).and_return(broadcaster, stub("output broadcaster", :register => nil))
118
- @mock_formatter_class.stub!(:new).and_return(mock_formatter)
119
- cli.parse_options!(%w{--format magical})
120
-
121
- broadcaster.should_receive(:register).with(mock_formatter)
60
+ ::Spec::Expectations::Differs::Default.should_receive(:new)
122
61
 
123
- cli.execute!(stub('step mother'), mock_executor, stub('features'))
62
+ @cli.execute!(@step_mother)
124
63
  end
125
64
 
126
- end
127
-
128
- describe "exists but invalid constructor" do
129
-
130
- before(:each) do
131
- @out = StringIO.new
132
- @error = StringIO.new
133
- @cli = Main.new(@out, @error)
134
-
135
- mock_formatter_class = stub('formatter class')
136
- mock_formatter_class.stub!(:new).and_raise("No such method")
137
- Object.stub!(:const_get).and_return(mock_formatter_class)
138
- Object.stub!(:const_defined?).with('exists_but_evil').and_return(true)
139
-
140
- @cli.parse_options!(%w{--format exists_but_evil})
141
- end
65
+ it "does not use Spec Differ::Default when diff is disabled" do
66
+ @configuration.should_receive(:diff_enabled?).and_return(false)
142
67
 
143
- xit "should show exception" do
144
- Kernel.stub!(:exit)
145
-
146
- @cli.execute!(stub('step mother'))
147
-
148
- @error.string.should include("No such method")
149
- end
68
+ ::Spec::Expectations::Differs::Default.should_not_receive(:new)
150
69
 
151
- xit "should exit" do
152
- Kernel.should_receive(:exit)
153
-
154
- @cli.execute!(stub('step mother'), mock_executor, stub('features'))
70
+ @cli.execute!(@step_mother)
155
71
  end
156
-
72
+
157
73
  end
158
-
159
- describe "non-existent" do
160
74
 
161
- before(:each) do
162
- @out = StringIO.new
163
- @error = StringIO.new
164
- @cli = Main.new(%w{--format invalid}, @out, @error)
165
- end
75
+ describe "--format with class" do
76
+
77
+ describe "in module" do
166
78
 
167
- xit "should display a format error" do
168
- Kernel.stub!(:exit)
79
+ it "should resolve each module until it gets Formatter class" do
80
+ cli = Main.new(%w{--format ZooModule::MonkeyFormatterClass}, nil)
81
+ mock_module = mock('module')
82
+ Object.stub!(:const_defined?).and_return(true)
83
+ mock_module.stub!(:const_defined?).and_return(true)
169
84
 
170
- @cli.execute!(stub('step mother'), mock_executor, stub('features'))
171
-
172
- @error.string.should include("Invalid format: invalid\n")
173
- end
174
-
175
- xit "should display --help" do
176
- Kernel.stub!(:exit)
85
+ f = stub('formatter', :null_object => true)
177
86
 
178
- @cli.execute!(Object.new.extend(StepMother))
179
-
180
- @out.string.should include("Usage: cucumber")
181
- end
87
+ Object.should_receive(:const_get).with('ZooModule').and_return(mock_module)
88
+ mock_module.should_receive(:const_get).with('MonkeyFormatterClass').and_return(mock('formatter class', :new => f))
182
89
 
183
- xit "should exit" do
184
- Kernel.should_receive(:exit)
90
+ cli.execute!(Object.new.extend(StepMother))
91
+ end
185
92
 
186
- @cli.execute!(stub('step mother'), mock_executor, stub('features'))
187
- end
188
-
93
+ end
189
94
  end
190
-
191
95
  end
192
-
193
96
  end
194
97
  end
195
- end