capybara 0.4.0 → 0.4.1.rc

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 (46) hide show
  1. data/History.txt +35 -0
  2. data/README.rdoc +60 -19
  3. data/lib/capybara.rb +81 -5
  4. data/lib/capybara/driver/base.rb +1 -6
  5. data/lib/capybara/driver/celerity_driver.rb +19 -9
  6. data/lib/capybara/driver/node.rb +8 -0
  7. data/lib/capybara/driver/rack_test_driver.rb +42 -29
  8. data/lib/capybara/driver/selenium_driver.rb +11 -3
  9. data/lib/capybara/dsl.rb +11 -0
  10. data/lib/capybara/node/actions.rb +4 -14
  11. data/lib/capybara/node/base.rb +47 -0
  12. data/lib/capybara/node/document.rb +17 -0
  13. data/lib/capybara/node/element.rb +178 -0
  14. data/lib/capybara/node/finders.rb +78 -27
  15. data/lib/capybara/node/matchers.rb +40 -11
  16. data/lib/capybara/node/simple.rb +116 -0
  17. data/lib/capybara/rspec.rb +18 -0
  18. data/lib/capybara/server.rb +5 -10
  19. data/lib/capybara/session.rb +7 -16
  20. data/lib/capybara/spec/driver.rb +16 -1
  21. data/lib/capybara/spec/session.rb +1 -0
  22. data/lib/capybara/spec/session/all_spec.rb +5 -0
  23. data/lib/capybara/spec/session/attach_file_spec.rb +6 -0
  24. data/lib/capybara/spec/session/click_link_or_button_spec.rb +2 -3
  25. data/lib/capybara/spec/session/find_spec.rb +0 -6
  26. data/lib/capybara/spec/session/first_spec.rb +72 -0
  27. data/lib/capybara/spec/session/has_css_spec.rb +107 -1
  28. data/lib/capybara/spec/session/has_field_spec.rb +60 -0
  29. data/lib/capybara/spec/session/has_select_spec.rb +40 -0
  30. data/lib/capybara/spec/session/javascript.rb +4 -13
  31. data/lib/capybara/spec/session/within_spec.rb +10 -3
  32. data/lib/capybara/spec/test_app.rb +20 -1
  33. data/lib/capybara/spec/views/form.erb +27 -0
  34. data/lib/capybara/spec/views/with_html.erb +21 -5
  35. data/lib/capybara/util/save_and_open_page.rb +8 -5
  36. data/lib/capybara/version.rb +1 -1
  37. data/spec/basic_node_spec.rb +77 -0
  38. data/spec/capybara_spec.rb +18 -0
  39. data/spec/dsl_spec.rb +26 -0
  40. data/spec/rspec_spec.rb +47 -0
  41. data/spec/save_and_open_page_spec.rb +83 -7
  42. data/spec/server_spec.rb +20 -0
  43. data/spec/session/rack_test_session_spec.rb +10 -0
  44. data/spec/string_spec.rb +77 -0
  45. metadata +306 -295
  46. data/lib/capybara/node.rb +0 -221
@@ -22,13 +22,30 @@ shared_examples_for "has_css" do
22
22
  end
23
23
  end
24
24
 
25
+ context "with between" do
26
+ it "should be true if the content occurs within the range given" do
27
+ @session.should have_css("p", :between => 1..4)
28
+ @session.should have_css("p a#foo", :between => 1..3)
29
+ end
30
+
31
+ it "should be false if the content occurs more or fewer times than range" do
32
+ @session.should_not have_css("p", :between => 6..11 )
33
+ @session.should_not have_css("p a#foo", :between => 4..7)
34
+ end
35
+
36
+ it "should be false if the content isn't on the page at all" do
37
+ @session.should_not have_css("abbr", :between => 1..8)
38
+ @session.should_not have_css("p a.doesnotexist", :between => 3..8)
39
+ end
40
+ end
41
+
25
42
  context "with count" do
26
43
  it "should be true if the content is on the page the given number of times" do
27
44
  @session.should have_css("p", :count => 3)
28
45
  @session.should have_css("p a#foo", :count => 1)
29
46
  end
30
47
 
31
- it "should be false if the content is on the page the given number of times" do
48
+ it "should be false if the content occurs the given number of times" do
32
49
  @session.should_not have_css("p", :count => 6)
33
50
  @session.should_not have_css("p a#foo", :count => 2)
34
51
  end
@@ -39,6 +56,42 @@ shared_examples_for "has_css" do
39
56
  end
40
57
  end
41
58
 
59
+ context "with maximum" do
60
+ it "should be true when content occurs same or fewer times than given" do
61
+ @session.should have_css("h2.head", :maximum => 5) # edge case
62
+ @session.should have_css("h2", :maximum => 10)
63
+ end
64
+
65
+ it "should be false when content occurs more times than given" do
66
+ @session.should_not have_css("h2.head", :maximum => 4) # edge case
67
+ @session.should_not have_css("h2", :maximum => 6)
68
+ @session.should_not have_css("p", :maximum => 1)
69
+ end
70
+
71
+ it "should be false if the content isn't on the page at all" do
72
+ @session.should_not have_css("abbr", :maximum => 2)
73
+ @session.should_not have_css("p a.doesnotexist", :maximum => 1)
74
+ end
75
+ end
76
+
77
+ context "with minimum" do
78
+ it "should be true when content occurs same or more times than given" do
79
+ @session.should have_css("h2.head", :minimum => 5) # edge case
80
+ @session.should have_css("h2", :minimum => 3)
81
+ end
82
+
83
+ it "should be false when content occurs fewer times than given" do
84
+ @session.should_not have_css("h2.head", :minimum => 6) # edge case
85
+ @session.should_not have_css("h2", :minimum => 8)
86
+ @session.should_not have_css("p", :minimum => 10)
87
+ end
88
+
89
+ it "should be false if the content isn't on the page at all" do
90
+ @session.should_not have_css("abbr", :minimum => 2)
91
+ @session.should_not have_css("p a.doesnotexist", :minimum => 7)
92
+ end
93
+ end
94
+
42
95
  context "with text" do
43
96
  it "should discard all matches where the given string is not contained" do
44
97
  @session.should have_css("p a", :text => "Redirect", :count => 1)
@@ -75,6 +128,23 @@ shared_examples_for "has_css" do
75
128
  end
76
129
  end
77
130
 
131
+ context "with between" do
132
+ it "should be false if the content occurs within the range given" do
133
+ @session.should_not have_no_css("p", :between => 1..4)
134
+ @session.should_not have_no_css("p a#foo", :between => 1..3)
135
+ end
136
+
137
+ it "should be true if the content occurs more or fewer times than range" do
138
+ @session.should have_no_css("p", :between => 6..11 )
139
+ @session.should have_no_css("p a#foo", :between => 4..7)
140
+ end
141
+
142
+ it "should be true if the content isn't on the page at all" do
143
+ @session.should have_no_css("abbr", :between => 1..8)
144
+ @session.should have_no_css("p a.doesnotexist", :between => 3..8)
145
+ end
146
+ end
147
+
78
148
  context "with count" do
79
149
  it "should be false if the content is on the page the given number of times" do
80
150
  @session.should_not have_no_css("p", :count => 3)
@@ -92,6 +162,42 @@ shared_examples_for "has_css" do
92
162
  end
93
163
  end
94
164
 
165
+ context "with maximum" do
166
+ it "should be false when content occurs same or fewer times than given" do
167
+ @session.should_not have_no_css("h2.head", :maximum => 5) # edge case
168
+ @session.should_not have_no_css("h2", :maximum => 10)
169
+ end
170
+
171
+ it "should be true when content occurs more times than given" do
172
+ @session.should have_no_css("h2.head", :maximum => 4) # edge case
173
+ @session.should have_no_css("h2", :maximum => 6)
174
+ @session.should have_no_css("p", :maximum => 1)
175
+ end
176
+
177
+ it "should be true if the content isn't on the page at all" do
178
+ @session.should have_no_css("abbr", :maximum => 5)
179
+ @session.should have_no_css("p a.doesnotexist", :maximum => 10)
180
+ end
181
+ end
182
+
183
+ context "with minimum" do
184
+ it "should be false when content occurs more times than given" do
185
+ @session.should_not have_no_css("h2.head", :minimum => 4) # edge case
186
+ @session.should_not have_no_css("h2", :minimum => 3)
187
+ end
188
+
189
+ it "should be true when content occurs fewer times than given" do
190
+ @session.should have_no_css("h2.head", :minimum => 6) # edge case
191
+ @session.should have_no_css("h2", :minimum => 8)
192
+ @session.should have_no_css("p", :minimum => 15)
193
+ end
194
+
195
+ it "should be true if the content isn't on the page at all" do
196
+ @session.should have_no_css("abbr", :minimum => 5)
197
+ @session.should have_no_css("p a.doesnotexist", :minimum => 10)
198
+ end
199
+ end
200
+
95
201
  context "with text" do
96
202
  it "should discard all matches where the given string is not contained" do
97
203
  @session.should_not have_no_css("p a", :text => "Redirect", :count => 1)
@@ -25,6 +25,16 @@ shared_examples_for "has_field" do
25
25
  @session.should_not have_field('Wrong Name', :with => 'John')
26
26
  @session.should_not have_field('Description', :with => 'Monkey')
27
27
  end
28
+
29
+ it "should be true after the field has been filled in with the given value" do
30
+ @session.fill_in('First Name', :with => 'Jonas')
31
+ @session.should have_field('First Name', :with => 'Jonas')
32
+ end
33
+
34
+ it "should be false after the field has been filled in with a different value" do
35
+ @session.fill_in('First Name', :with => 'Jonas')
36
+ @session.should_not have_field('First Name', :with => 'John')
37
+ end
28
38
  end
29
39
  end
30
40
 
@@ -54,6 +64,16 @@ shared_examples_for "has_field" do
54
64
  @session.should have_no_field('Wrong Name', :with => 'John')
55
65
  @session.should have_no_field('Description', :with => 'Monkey')
56
66
  end
67
+
68
+ it "should be false after the field has been filled in with the given value" do
69
+ @session.fill_in('First Name', :with => 'Jonas')
70
+ @session.should_not have_no_field('First Name', :with => 'Jonas')
71
+ end
72
+
73
+ it "should be true after the field has been filled in with a different value" do
74
+ @session.fill_in('First Name', :with => 'Jonas')
75
+ @session.should have_no_field('First Name', :with => 'John')
76
+ end
57
77
  end
58
78
  end
59
79
 
@@ -73,6 +93,26 @@ shared_examples_for "has_field" do
73
93
  it "should be false if no field is on the page" do
74
94
  @session.should_not have_checked_field('Does Not Exist')
75
95
  end
96
+
97
+ it "should be true after an unchecked checkbox is checked" do
98
+ @session.check('form_pets_cat')
99
+ @session.should have_checked_field('form_pets_cat')
100
+ end
101
+
102
+ it "should be false after a checked checkbox is unchecked" do
103
+ @session.uncheck('form_pets_dog')
104
+ @session.should_not have_checked_field('form_pets_dog')
105
+ end
106
+
107
+ it "should be true after an unchecked radio button is chosen" do
108
+ @session.choose('gender_male')
109
+ @session.should have_checked_field('gender_male')
110
+ end
111
+
112
+ it "should be false after another radio button in the group is chosen" do
113
+ @session.choose('gender_male')
114
+ @session.should_not have_checked_field('gender_female')
115
+ end
76
116
  end
77
117
 
78
118
  describe '#has_unchecked_field?' do
@@ -91,6 +131,26 @@ shared_examples_for "has_field" do
91
131
  it "should be false if no field is on the page" do
92
132
  @session.should_not have_unchecked_field('Does Not Exist')
93
133
  end
134
+
135
+ it "should be false after an unchecked checkbox is checked" do
136
+ @session.check('form_pets_cat')
137
+ @session.should_not have_unchecked_field('form_pets_cat')
138
+ end
139
+
140
+ it "should be true after a checked checkbox is unchecked" do
141
+ @session.uncheck('form_pets_dog')
142
+ @session.should have_unchecked_field('form_pets_dog')
143
+ end
144
+
145
+ it "should be false after an unchecked radio button is chosen" do
146
+ @session.choose('gender_male')
147
+ @session.should_not have_unchecked_field('gender_male')
148
+ end
149
+
150
+ it "should be true after another radio button in the group is chosen" do
151
+ @session.choose('gender_male')
152
+ @session.should have_unchecked_field('gender_female')
153
+ end
94
154
  end
95
155
  end
96
156
 
@@ -26,6 +26,26 @@ shared_examples_for "has_select" do
26
26
  @session.should_not have_select('Underwear', :selected => ['Briefs', 'Nonexistant'])
27
27
  @session.should_not have_select('Underwear', :selected => ['Briefs', 'Boxers'])
28
28
  end
29
+
30
+ it "should be true after the given value is selected" do
31
+ @session.select('Swedish', :from => 'Locale')
32
+ @session.should have_select('Locale', :selected => 'Swedish')
33
+ end
34
+
35
+ it "should be false after a different value is selected" do
36
+ @session.select('Swedish', :from => 'Locale')
37
+ @session.should_not have_select('Locale', :selected => 'English')
38
+ end
39
+
40
+ it "should be true after the given values are selected" do
41
+ @session.select('Boxers', :from => 'Underwear')
42
+ @session.should have_select('Underwear', :selected => ['Briefs', 'Boxers', 'Commando'])
43
+ end
44
+
45
+ it "should be false after one of the values is unselected" do
46
+ @session.unselect('Briefs', :from => 'Underwear')
47
+ @session.should_not have_select('Underwear', :selected => ['Briefs', 'Commando'])
48
+ end
29
49
  end
30
50
 
31
51
  context 'with options' do
@@ -69,6 +89,26 @@ shared_examples_for "has_select" do
69
89
  @session.should have_no_select('Underwear', :selected => ['Briefs', 'Nonexistant'])
70
90
  @session.should have_no_select('Underwear', :selected => ['Briefs', 'Boxers'])
71
91
  end
92
+
93
+ it "should be false after the given value is selected" do
94
+ @session.select('Swedish', :from => 'Locale')
95
+ @session.should_not have_no_select('Locale', :selected => 'Swedish')
96
+ end
97
+
98
+ it "should be true after a different value is selected" do
99
+ @session.select('Swedish', :from => 'Locale')
100
+ @session.should have_no_select('Locale', :selected => 'English')
101
+ end
102
+
103
+ it "should be false after the given values are selected" do
104
+ @session.select('Boxers', :from => 'Underwear')
105
+ @session.should_not have_no_select('Underwear', :selected => ['Briefs', 'Boxers', 'Commando'])
106
+ end
107
+
108
+ it "should be true after one of the values is unselected" do
109
+ @session.unselect('Briefs', :from => 'Underwear')
110
+ @session.should have_no_select('Underwear', :selected => ['Briefs', 'Commando'])
111
+ end
72
112
  end
73
113
 
74
114
  context 'with options' do
@@ -8,15 +8,6 @@ shared_examples_for "session with javascript support" do
8
8
  Capybara.default_wait_time = 0
9
9
  end
10
10
 
11
- describe '#drag' do
12
- it "should drag and drop an object" do
13
- pending "drag/drop is currently broken under celerity/culerity" if @session.driver.is_a?(Capybara::Driver::Celerity)
14
- @session.visit('/with_js')
15
- @session.drag('//div[@id="drag"]', '//div[@id="drop"]')
16
- @session.find('//div[contains(., "Dropped!")]').should_not be_nil
17
- end
18
- end
19
-
20
11
  describe 'Node#drag_to' do
21
12
  it "should drag and drop an object" do
22
13
  pending "drag/drop is currently broken under celerity/culerity" if @session.driver.is_a?(Capybara::Driver::Celerity)
@@ -27,7 +18,7 @@ shared_examples_for "session with javascript support" do
27
18
  @session.find('//div[contains(., "Dropped!")]').should_not be_nil
28
19
  end
29
20
  end
30
-
21
+
31
22
  describe '#find' do
32
23
  it "should allow triggering of custom JS events" do
33
24
  pending "cannot figure out how to do this with selenium" if @session.mode == :selenium
@@ -111,7 +102,7 @@ shared_examples_for "session with javascript support" do
111
102
  begin
112
103
  @session.wait_until(0.1) { false }
113
104
  rescue Capybara::TimeoutError; end
114
- (Time.now - start).should be_close(0.1, 0.1)
105
+ (Time.now - start).should be_within(0.1).of(0.1)
115
106
  end
116
107
 
117
108
  it "should default to Capybara.default_wait_time before timeout" do
@@ -122,9 +113,9 @@ shared_examples_for "session with javascript support" do
122
113
  @session.wait_until { false }
123
114
  rescue Capybara::TimeoutError; end
124
115
  if @session.driver.has_shortcircuit_timeout?
125
- (Time.now - start).should be_close(0, 0.1)
116
+ (Time.now - start).should be_within(0.1).of(0)
126
117
  else
127
- (Time.now - start).should be_close(0.2, 0.1)
118
+ (Time.now - start).should be_within(0.1).of(0.2)
128
119
  end
129
120
  end
130
121
  end
@@ -1,4 +1,4 @@
1
- shared_examples_for "within" do
1
+ shared_examples_for "within" do
2
2
  describe '#within' do
3
3
  before do
4
4
  @session.visit('/with_scope')
@@ -11,6 +11,13 @@ shared_examples_for "within" do
11
11
  end
12
12
  @session.body.should include('Bar')
13
13
  end
14
+
15
+ it "should accept additional options" do
16
+ @session.within(:css, "ul li", :text => 'With Simple HTML') do
17
+ @session.click_link('Go')
18
+ end
19
+ @session.body.should include('Bar')
20
+ end
14
21
  end
15
22
 
16
23
  context "with XPath selector" do
@@ -32,14 +39,14 @@ shared_examples_for "within" do
32
39
  end
33
40
 
34
41
  context "with the default selector set to CSS" do
35
- before { Capybara.default_selector = :css }
42
+ before { Capybara.default_selector = :css }
36
43
  it "should use CSS" do
37
44
  @session.within("ul li[contains('With Simple HTML')]") do
38
45
  @session.click_link('Go')
39
46
  end
40
47
  @session.body.should include('Bar')
41
48
  end
42
- after { Capybara.default_selector = :xpath }
49
+ after { Capybara.default_selector = :xpath }
43
50
  end
44
51
 
45
52
  context "with click_link" do
@@ -77,6 +77,14 @@ class TestApp < Sinatra::Base
77
77
  '<pre id="results">' + params[:form].to_yaml + '</pre>'
78
78
  end
79
79
 
80
+ post '/upload_empty' do
81
+ if params[:form][:file].nil?
82
+ 'Successfully ignored empty file field.'
83
+ else
84
+ 'Something went wrong.'
85
+ end
86
+ end
87
+
80
88
  post '/upload' do
81
89
  begin
82
90
  buffer = []
@@ -87,8 +95,19 @@ class TestApp < Sinatra::Base
87
95
  'No file uploaded'
88
96
  end
89
97
  end
98
+
99
+ post '/upload_multiple' do
100
+ begin
101
+ buffer = []
102
+ buffer << "Content-type: #{params[:form][:multiple_documents][0][:type]}"
103
+ buffer << "File content: #{params[:form][:multiple_documents][0][:tempfile].read}"
104
+ buffer.join(' | ')
105
+ rescue
106
+ 'No files uploaded'
107
+ end
108
+ end
90
109
  end
91
110
 
92
111
  if __FILE__ == $0
93
- Rack::Handler::Mongrel.run TestApp, :Port => 8070
112
+ Rack::Handler::WEBrick.run TestApp, :Port => 8070
94
113
  end
@@ -250,6 +250,17 @@
250
250
  <p>
251
251
  </form>
252
252
 
253
+ <form action="/upload_empty" method="post" enctype="multipart/form-data">
254
+ <p>
255
+ <label for="form_file_name">File Name</label>
256
+ <input type="file" name="form[file]" id="form_file"/>
257
+ </p>
258
+
259
+ <p>
260
+ <input type="submit" value="Upload Empty"/>
261
+ <p>
262
+ </form>
263
+
253
264
  <form action="/upload" method="post" enctype="multipart/form-data">
254
265
  <p>
255
266
  <label for="form_file_name">File Name</label>
@@ -266,6 +277,22 @@
266
277
  <p>
267
278
  </form>
268
279
 
280
+ <form action="/upload_multiple" method="post" enctype="multipart/form-data">
281
+ <p>
282
+ <label for="form_multiple_file_name">File Name</label>
283
+ <input type="file" name="form[multiple_file_name]" id="form_multiple_file_name"/>
284
+ </p>
285
+
286
+ <p>
287
+ <label for="form_multiple_documents">Multiple Documents</label>
288
+ <input type="file" name="form[multiple_documents][]" id="form_multiple_documents" multiple />
289
+ </p>
290
+
291
+ <p>
292
+ <input type="submit" value="Upload Multiple"/>
293
+ <p>
294
+ </form>
295
+
269
296
  <form action="/redirect" method="post">
270
297
  <p>
271
298
  <input type="submit" value="Go FAR"/>
@@ -1,15 +1,23 @@
1
1
  <h1>This is a test</h1>
2
2
 
3
- <p id="first">
3
+ <h2 class="no text"></h2>
4
+ <h2 class="no text"></h2>
5
+ <h2 class="head" id="h2one">Header Class Test One</h2>
6
+ <h2 class="head" id="h2two">Header Class Test Two</h2>
7
+ <h2 class="head">Header Class Test Three</h2>
8
+ <h2 class="head">Header Class Test Four</h2>
9
+ <h2 class="head">Header Class Test Five</h2>
10
+
11
+ <p class="para" id="first">
4
12
  Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
5
13
  tempor incididunt ut <a href="/with_simple_html" title="awesome title" class="simple">labore</a>
6
14
  et dolore magna aliqua. Ut enim ad minim veniam,
7
15
  quis nostrud exercitation <a href="/foo" id="foo">ullamco</a> laboris nisi
8
16
  ut aliquip ex ea commodo consequat.
9
- <a href="/with_simple_html"><img src="http://www.foobar.sun/dummy_image.jpg" width="20" height="20" alt="awesome image" /></a>
17
+ <a href="/with_simple_html"><img width="20" height="20" alt="awesome image" /></a>
10
18
  </p>
11
19
 
12
- <p id="second">
20
+ <p class="para" id="second">
13
21
  Duis aute irure dolor in reprehenderit in voluptate velit esse cillum
14
22
  dolore eu fugiat <a href="/redirect" id="red">Redirect</a> pariatur. Excepteur sint occaecat cupidatat non proident,
15
23
  sunt in culpa qui officia
@@ -33,8 +41,8 @@
33
41
  <a href="/with_html#anchor">Anchor on same page</a>
34
42
  <input type="text" value="" id="test_field">
35
43
  <input type="text" checked="checked" id="checked_field">
36
- <a href="/redirect"><img src="http://www.foobar.sun/dummy_image.jpg" width="20" height="20" alt="very fine image" /></a>
37
- <a href="/with_simple_html"><img src="http://www.foobar.sun/dummy_image.jpg" width="20" height="20" alt="fine image" /></a>
44
+ <a href="/redirect"><img width="20" height="20" alt="very fine image" /></a>
45
+ <a href="/with_simple_html"><img width="20" height="20" alt="fine image" /></a>
38
46
 
39
47
  <a href="?query_string=true">Naked Query String</a>
40
48
  <% if params[:query_string] %>
@@ -47,6 +55,14 @@
47
55
  <a href="/with_simple_html" title="awesome title" class="simple">hidden link</a>
48
56
  </div>
49
57
 
58
+ <div style="display: none;">
59
+ <a class="visibility">hidden link</a>
60
+ </div>
61
+
62
+ <div>
63
+ <a class="visibility">visible link</a>
64
+ </div>
65
+
50
66
  <ul>
51
67
  <li id="john_monkey">Monkey John</li>
52
68
  <li id="paul_monkey">Monkey Paul</li>