capybara 2.0.3 → 2.1.0.beta1

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 (81) hide show
  1. data.tar.gz.sig +0 -0
  2. data/History.md +73 -0
  3. data/README.md +52 -5
  4. data/lib/capybara.rb +44 -62
  5. data/lib/capybara/cucumber.rb +4 -1
  6. data/lib/capybara/driver/base.rb +13 -9
  7. data/lib/capybara/driver/node.rb +18 -6
  8. data/lib/capybara/helpers.rb +111 -22
  9. data/lib/capybara/node/actions.rb +24 -19
  10. data/lib/capybara/node/base.rb +25 -32
  11. data/lib/capybara/node/document.rb +6 -2
  12. data/lib/capybara/node/element.rb +45 -7
  13. data/lib/capybara/node/finders.rb +48 -21
  14. data/lib/capybara/node/matchers.rb +38 -21
  15. data/lib/capybara/node/simple.rb +29 -7
  16. data/lib/capybara/query.rb +72 -26
  17. data/lib/capybara/rack_test/browser.rb +11 -3
  18. data/lib/capybara/rack_test/css_handlers.rb +8 -0
  19. data/lib/capybara/rack_test/driver.rb +11 -3
  20. data/lib/capybara/rack_test/form.rb +8 -1
  21. data/lib/capybara/rack_test/node.rb +92 -36
  22. data/lib/capybara/rails.rb +1 -2
  23. data/lib/capybara/result.rb +21 -37
  24. data/lib/capybara/rspec/matchers.rb +60 -31
  25. data/lib/capybara/selector.rb +46 -13
  26. data/lib/capybara/selenium/driver.rb +42 -6
  27. data/lib/capybara/selenium/node.rb +23 -5
  28. data/lib/capybara/session.rb +46 -11
  29. data/lib/capybara/spec/public/test.js +12 -0
  30. data/lib/capybara/spec/session/all_spec.rb +9 -8
  31. data/lib/capybara/spec/session/attach_file_spec.rb +14 -0
  32. data/lib/capybara/spec/session/check_spec.rb +14 -0
  33. data/lib/capybara/spec/session/choose_spec.rb +14 -0
  34. data/lib/capybara/spec/session/click_button_spec.rb +77 -1
  35. data/lib/capybara/spec/session/click_link_or_button_spec.rb +65 -0
  36. data/lib/capybara/spec/session/click_link_spec.rb +24 -0
  37. data/lib/capybara/spec/session/current_scope_spec.rb +29 -0
  38. data/lib/capybara/spec/session/fill_in_spec.rb +14 -0
  39. data/lib/capybara/spec/session/find_button_spec.rb +12 -0
  40. data/lib/capybara/spec/session/find_by_id_spec.rb +12 -1
  41. data/lib/capybara/spec/session/find_field_spec.rb +30 -0
  42. data/lib/capybara/spec/session/find_link_spec.rb +12 -0
  43. data/lib/capybara/spec/session/find_spec.rb +258 -16
  44. data/lib/capybara/spec/session/first_spec.rb +25 -8
  45. data/lib/capybara/spec/session/has_css_spec.rb +2 -2
  46. data/lib/capybara/spec/session/has_field_spec.rb +10 -2
  47. data/lib/capybara/spec/session/has_selector_spec.rb +9 -0
  48. data/lib/capybara/spec/session/has_text_spec.rb +96 -0
  49. data/lib/capybara/spec/session/has_title_spec.rb +47 -0
  50. data/lib/capybara/spec/session/node_spec.rb +43 -0
  51. data/lib/capybara/spec/session/reset_session_spec.rb +10 -2
  52. data/lib/capybara/spec/session/save_page_spec.rb +30 -0
  53. data/lib/capybara/spec/session/select_spec.rb +65 -0
  54. data/lib/capybara/spec/session/text_spec.rb +31 -0
  55. data/lib/capybara/spec/session/title_spec.rb +16 -0
  56. data/lib/capybara/spec/session/uncheck_spec.rb +14 -0
  57. data/lib/capybara/spec/session/unselect_spec.rb +42 -0
  58. data/lib/capybara/spec/session/visit_spec.rb +3 -3
  59. data/lib/capybara/spec/session/within_frame_spec.rb +14 -0
  60. data/lib/capybara/spec/session/within_spec.rb +3 -3
  61. data/lib/capybara/spec/spec_helper.rb +6 -1
  62. data/lib/capybara/spec/views/form.erb +39 -2
  63. data/lib/capybara/spec/views/frame_child.erb +9 -0
  64. data/lib/capybara/spec/views/frame_parent.erb +8 -0
  65. data/lib/capybara/spec/views/with_base_tag.erb +10 -0
  66. data/lib/capybara/spec/views/with_count.erb +7 -0
  67. data/lib/capybara/spec/views/with_hover.erb +17 -0
  68. data/lib/capybara/spec/views/with_html.erb +21 -2
  69. data/lib/capybara/spec/views/with_js.erb +5 -0
  70. data/lib/capybara/spec/views/with_scope.erb +6 -1
  71. data/lib/capybara/spec/views/with_title.erb +1 -0
  72. data/lib/capybara/spec/views/within_frames.erb +1 -0
  73. data/lib/capybara/version.rb +1 -1
  74. data/spec/basic_node_spec.rb +75 -24
  75. data/spec/dsl_spec.rb +2 -1
  76. data/spec/rack_test_spec.rb +4 -3
  77. data/spec/rspec/matchers_spec.rb +105 -17
  78. data/spec/server_spec.rb +8 -8
  79. data/spec/spec_helper.rb +2 -1
  80. metadata +83 -23
  81. metadata.gz.sig +0 -0
@@ -66,6 +66,17 @@ Capybara::SpecHelper.spec '#click_link' do
66
66
  end
67
67
  end
68
68
 
69
+ context "with :href option given" do
70
+ it "should find links with valid href" do
71
+ @session.click_link('labore', :href => '/with_simple_html')
72
+ @session.should have_content('Bar')
73
+ end
74
+
75
+ it "should raise error if link wasn't found" do
76
+ expect { @session.click_link('labore', :href => 'invalid_href') }.to raise_error(Capybara::ElementNotFound)
77
+ end
78
+ end
79
+
69
80
  it "should follow relative links" do
70
81
  @session.visit('/')
71
82
  @session.click_link('Relative')
@@ -116,4 +127,17 @@ Capybara::SpecHelper.spec '#click_link' do
116
127
  @session.click_link('No Href')
117
128
  end.to raise_error(Capybara::ElementNotFound)
118
129
  end
130
+
131
+ context "with :exact option" do
132
+ it "should accept partial matches when false" do
133
+ @session.click_link('abo', :exact => false)
134
+ @session.should have_content('Bar')
135
+ end
136
+
137
+ it "should not accept partial matches when true" do
138
+ expect do
139
+ @session.click_link('abo', :exact => true)
140
+ end.to raise_error(Capybara::ElementNotFound)
141
+ end
142
+ end
119
143
  end
@@ -0,0 +1,29 @@
1
+ Capybara::SpecHelper.spec '#current_scope' do
2
+ before do
3
+ @session.visit('/with_scope')
4
+ end
5
+
6
+ context "when not in a #within block" do
7
+ it "should return the document" do
8
+ @session.current_scope.should be_kind_of Capybara::Node::Document
9
+ end
10
+ end
11
+
12
+ context "when in a #within block" do
13
+ it "should return the element in scope" do
14
+ @session.within(:css, "#simple_first_name") do
15
+ @session.current_scope[:name].should eq 'first_name'
16
+ end
17
+ end
18
+ end
19
+
20
+ context "when in a nested #within block" do
21
+ it "should return the element in scope" do
22
+ @session.within("//div[@id='for_bar']") do
23
+ @session.within(".//input[@value='Peter']") do
24
+ @session.current_scope[:name].should eq 'form[first_name]'
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -138,4 +138,18 @@ Capybara::SpecHelper.spec "#fill_in" do
138
138
  end.to raise_error(Capybara::ElementNotFound)
139
139
  end
140
140
  end
141
+
142
+ context "with :exact option" do
143
+ it "should accept partial matches when false" do
144
+ @session.fill_in("Explanation", :with => "Dude", :exact => false)
145
+ @session.click_button("awesome")
146
+ extract_results(@session)["name_explanation"].should == "Dude"
147
+ end
148
+
149
+ it "should not accept partial matches when true" do
150
+ expect do
151
+ @session.fill_in("Explanation", :with => "Dude", :exact => true)
152
+ end.to raise_error(Capybara::ElementNotFound)
153
+ end
154
+ end
141
155
  end
@@ -17,4 +17,16 @@ Capybara::SpecHelper.spec '#find_button' do
17
17
  @session.find_button('Does not exist')
18
18
  end.to raise_error(Capybara::ElementNotFound)
19
19
  end
20
+
21
+ context "with :exact option" do
22
+ it "should accept partial matches when false" do
23
+ @session.find_button('What an Awesome', :exact => false)[:value].should == "awesome"
24
+ end
25
+
26
+ it "should not accept partial matches when true" do
27
+ expect do
28
+ @session.find_button('What an Awesome', :exact => true)
29
+ end.to raise_error(Capybara::ElementNotFound)
30
+ end
31
+ end
20
32
  end
@@ -5,7 +5,6 @@ Capybara::SpecHelper.spec '#find_by_id' do
5
5
 
6
6
  it "should find any element by id" do
7
7
  @session.find_by_id('red').tag_name.should == 'a'
8
- @session.find_by_id('hidden_via_ancestor').tag_name.should == 'div'
9
8
  end
10
9
 
11
10
  it "casts to string" do
@@ -17,4 +16,16 @@ Capybara::SpecHelper.spec '#find_by_id' do
17
16
  @session.find_by_id('nothing_with_this_id')
18
17
  end.to raise_error(Capybara::ElementNotFound)
19
18
  end
19
+
20
+ context "with :visible option" do
21
+ it "finds invisible elements when `false`" do
22
+ @session.find_by_id("hidden_via_ancestor", :visible => false).text(:all).should =~ /with hidden ancestor/
23
+ end
24
+
25
+ it "finds invisible elements when `false`" do
26
+ expect do
27
+ @session.find_by_id("hidden_via_ancestor", :visible => true)
28
+ end.to raise_error(Capybara::ElementNotFound)
29
+ end
30
+ end
20
31
  end
@@ -25,4 +25,34 @@ Capybara::SpecHelper.spec '#find_field' do
25
25
  @session.field_labeled('Does not exist')
26
26
  end.to raise_error(Capybara::ElementNotFound)
27
27
  end
28
+
29
+ context "with :exact option" do
30
+ it "should accept partial matches when false" do
31
+ @session.find_field("Explanation", :exact => false)[:name].should == "form[name_explanation]"
32
+ end
33
+
34
+ it "should not accept partial matches when true" do
35
+ expect do
36
+ @session.find_field("Explanation", :exact => true)
37
+ end.to raise_error(Capybara::ElementNotFound)
38
+ end
39
+ end
40
+
41
+ context "with :disabled option" do
42
+ it "should find disabled fields when true" do
43
+ @session.find_field("Disabled Checkbox", :disabled => true)[:name].should == "form[disabled_checkbox]"
44
+ end
45
+
46
+ it "should not find disabled fields when false" do
47
+ expect do
48
+ @session.find_field("Disabled Checkbox", :disabled => false)
49
+ end.to raise_error(Capybara::ElementNotFound)
50
+ end
51
+
52
+ it "should not find disabled fields by default" do
53
+ expect do
54
+ @session.find_field("Disabled Checkbox")
55
+ end.to raise_error(Capybara::ElementNotFound)
56
+ end
57
+ end
28
58
  end
@@ -17,4 +17,16 @@ Capybara::SpecHelper.spec '#find_link' do
17
17
  @session.find_link('Does not exist')
18
18
  end.to raise_error(Capybara::ElementNotFound)
19
19
  end
20
+
21
+ context "with :exact option" do
22
+ it "should accept partial matches when false" do
23
+ @session.find_link('abo', :exact => false).text.should == "labore"
24
+ end
25
+
26
+ it "should not accept partial matches when true" do
27
+ expect do
28
+ @session.find_link('abo', :exact => true)
29
+ end.to raise_error(Capybara::ElementNotFound)
30
+ end
31
+ end
20
32
  end
@@ -27,6 +27,30 @@ Capybara::SpecHelper.spec '#find' do
27
27
  @session.find(:css, "a#has-been-clicked").text.should include('Has been clicked')
28
28
  end
29
29
 
30
+ context "with :wait option", :requires => [:js] do
31
+ it "should not wait for asynchronous load when `false` given" do
32
+ @session.visit('/with_js')
33
+ @session.click_link('Click me')
34
+ expect do
35
+ @session.find(:css, "a#has-been-clicked", :wait => false)
36
+ end.to raise_error(Capybara::ElementNotFound)
37
+ end
38
+
39
+ it "should not find element if it appears after given wait duration" do
40
+ @session.visit('/with_js')
41
+ @session.click_link('Slowly')
42
+ expect do
43
+ @session.find(:css, "a#slow-clicked", :wait => 0.2)
44
+ end.to raise_error(Capybara::ElementNotFound)
45
+ end
46
+
47
+ it "should find element if it appears before given wait duration" do
48
+ @session.visit('/with_js')
49
+ @session.click_link('Click me')
50
+ @session.find(:css, "a#has-been-clicked", :wait => 0.9).text.should include('Has been clicked')
51
+ end
52
+ end
53
+
30
54
  context "with frozen time", :requires => [:js] do
31
55
  it "raises an error suggesting that Capybara is stuck in time" do
32
56
  @session.visit('/with_js')
@@ -41,6 +65,10 @@ Capybara::SpecHelper.spec '#find' do
41
65
  @session.find(:css, 'h1').text.should == 'This is a test'
42
66
  @session.find(:css, "input[id='test_field']")[:value].should == 'monkey'
43
67
  end
68
+
69
+ it "should support pseudo selectors" do
70
+ @session.find(:css, 'input:disabled').value.should == 'This is disabled'
71
+ end
44
72
  end
45
73
 
46
74
  context "with xpath selectors" do
@@ -52,43 +80,72 @@ Capybara::SpecHelper.spec '#find' do
52
80
 
53
81
  context "with custom selector" do
54
82
  it "should use the custom selector" do
55
- Capybara.add_selector(:monkey) do
56
- xpath { |name| ".//*[@id='#{name}_monkey']" }
83
+ Capybara.add_selector(:beatle) do
84
+ xpath { |name| ".//*[@id='#{name}']" }
57
85
  end
58
- @session.find(:monkey, 'john').text.should == 'Monkey John'
59
- @session.find(:monkey, 'paul').text.should == 'Monkey Paul'
86
+ @session.find(:beatle, 'john').text.should == 'John'
87
+ @session.find(:beatle, 'paul').text.should == 'Paul'
60
88
  end
61
89
  end
62
90
 
63
91
  context "with custom selector with :for option" do
64
92
  it "should use the selector when it matches the :for option" do
65
- Capybara.add_selector(:monkey) do
66
- xpath { |num| ".//*[contains(@id, 'monkey')][#{num}]" }
93
+ Capybara.add_selector(:beatle) do
94
+ xpath { |num| ".//*[contains(@class, 'beatle')][#{num}]" }
67
95
  match { |value| value.is_a?(Fixnum) }
68
96
  end
69
- @session.find(:monkey, '2').text.should == 'Monkey Paul'
70
- @session.find(1).text.should == 'Monkey John'
71
- @session.find(2).text.should == 'Monkey Paul'
97
+ @session.find(:beatle, '2').text.should == 'Paul'
98
+ @session.find(1).text.should == 'John'
99
+ @session.find(2).text.should == 'Paul'
72
100
  @session.find('//h1').text.should == 'This is a test'
73
101
  end
74
102
  end
75
103
 
76
104
  context "with custom selector with custom filter" do
77
105
  before do
78
- Capybara.add_selector(:monkey) do
79
- xpath { |num| ".//*[contains(@id, 'monkey')][#{num}]" }
80
- filter(:name) { |node, name| node.text == name }
106
+ Capybara.add_selector(:beatle) do
107
+ xpath { |name| ".//li[contains(@class, 'beatle')][contains(text(), '#{name}')]" }
108
+ filter(:type) { |node, type| node[:class].split(/\s+/).include?(type) }
109
+ end
110
+ end
111
+
112
+ it "should find elements that match the filter" do
113
+ @session.find(:beatle, 'Paul', :type => 'drummer').text.should == 'Paul'
114
+ @session.find(:beatle, 'Ringo', :type => 'drummer').text.should == 'Ringo'
115
+ end
116
+
117
+ it "ignores filter when it is not given" do
118
+ @session.find(:beatle, 'Paul').text.should == 'Paul'
119
+ @session.find(:beatle, 'John').text.should == 'John'
120
+ end
121
+
122
+ it "should not find elements that don't match the filter" do
123
+ expect { @session.find(:beatle, 'John', :type => 'drummer') }.to raise_error(Capybara::ElementNotFound)
124
+ expect { @session.find(:beatle, 'George', :type => 'drummer') }.to raise_error(Capybara::ElementNotFound)
125
+ end
126
+ end
127
+
128
+ context "with custom selector with custom filter and default" do
129
+ before do
130
+ Capybara.add_selector(:beatle) do
131
+ xpath { |name| ".//li[contains(@class, 'beatle')][contains(text(), '#{name}')]" }
132
+ filter(:type, :default => "drummer") { |node, type| node[:class].split(/\s+/).include?(type) }
81
133
  end
82
134
  end
83
135
 
84
136
  it "should find elements that match the filter" do
85
- @session.find(:monkey, '1', :name => 'Monkey John').text.should == 'Monkey John'
86
- @session.find(:monkey, '2', :name => 'Monkey Paul').text.should == 'Monkey Paul'
137
+ @session.find(:beatle, 'Paul', :type => 'drummer').text.should == 'Paul'
138
+ @session.find(:beatle, 'Ringo', :type => 'drummer').text.should == 'Ringo'
139
+ end
140
+
141
+ it "should use default value when filter is not given" do
142
+ @session.find(:beatle, 'Paul').text.should == 'Paul'
143
+ expect { @session.find(:beatle, 'John') }.to raise_error(Capybara::ElementNotFound)
87
144
  end
88
145
 
89
146
  it "should not find elements that don't match the filter" do
90
- expect { @session.find(:monkey, '2', :name => 'Monkey John') }.to raise_error(Capybara::ElementNotFound)
91
- expect { @session.find(:monkey, '1', :name => 'Monkey Paul') }.to raise_error(Capybara::ElementNotFound)
147
+ expect { @session.find(:beatle, 'John', :type => 'drummer') }.to raise_error(Capybara::ElementNotFound)
148
+ expect { @session.find(:beatle, 'George', :type => 'drummer') }.to raise_error(Capybara::ElementNotFound)
92
149
  end
93
150
  end
94
151
 
@@ -113,6 +170,185 @@ Capybara::SpecHelper.spec '#find' do
113
170
  @session.find(@xpath).value.should == 'John'
114
171
  end
115
172
 
173
+ context "with :exact option" do
174
+ it "matches exactly when true" do
175
+ @session.find(:xpath, XPath.descendant(:input)[XPath.attr(:id).is("test_field")], :exact => true).value.should == "monkey"
176
+ expect do
177
+ @session.find(:xpath, XPath.descendant(:input)[XPath.attr(:id).is("est_fiel")], :exact => true)
178
+ end.to raise_error(Capybara::ElementNotFound)
179
+ end
180
+
181
+ it "matches loosely when false" do
182
+ @session.find(:xpath, XPath.descendant(:input)[XPath.attr(:id).is("test_field")], :exact => false).value.should == "monkey"
183
+ @session.find(:xpath, XPath.descendant(:input)[XPath.attr(:id).is("est_fiel")], :exact => false).value.should == "monkey"
184
+ end
185
+
186
+ it "defaults to `Capybara.exact`" do
187
+ Capybara.exact = true
188
+ expect do
189
+ @session.find(:xpath, XPath.descendant(:input)[XPath.attr(:id).is("est_fiel")])
190
+ end.to raise_error(Capybara::ElementNotFound)
191
+ Capybara.exact = false
192
+ @session.find(:xpath, XPath.descendant(:input)[XPath.attr(:id).is("est_fiel")])
193
+ end
194
+ end
195
+
196
+ context "with :match option" do
197
+ context "when set to `one`" do
198
+ it "raises an error when multiple matches exist" do
199
+ expect do
200
+ @session.find(:css, ".multiple", :match => :one)
201
+ end.to raise_error(Capybara::Ambiguous)
202
+ end
203
+ it "raises an error even if there the match is exact and the others are inexact" do
204
+ expect do
205
+ @session.find(:xpath, XPath.descendant[XPath.attr(:class).is("almost_singular")], :exact => false, :match => :one)
206
+ end.to raise_error(Capybara::Ambiguous)
207
+ end
208
+ it "returns the element if there is only one" do
209
+ @session.find(:css, ".singular", :match => :one).text.should == "singular"
210
+ end
211
+ it "raises an error if there is no match" do
212
+ expect do
213
+ @session.find(:css, ".does-not-exist", :match => :one)
214
+ end.to raise_error(Capybara::ElementNotFound)
215
+ end
216
+ end
217
+
218
+ context "when set to `first`" do
219
+ it "returns the first matched element" do
220
+ @session.find(:css, ".multiple", :match => :first).text.should == "multiple one"
221
+ end
222
+ it "raises an error if there is no match" do
223
+ expect do
224
+ @session.find(:css, ".does-not-exist", :match => :first)
225
+ end.to raise_error(Capybara::ElementNotFound)
226
+ end
227
+ end
228
+
229
+ context "when set to `smart`" do
230
+ context "and `exact` set to `false`" do
231
+ it "raises an error when there are multiple exact matches" do
232
+ expect do
233
+ @session.find(:xpath, XPath.descendant[XPath.attr(:class).is("multiple")], :match => :smart, :exact => false)
234
+ end.to raise_error(Capybara::Ambiguous)
235
+ end
236
+ it "finds a single exact match when there also are inexact matches" do
237
+ result = @session.find(:xpath, XPath.descendant[XPath.attr(:class).is("almost_singular")], :match => :smart, :exact => false)
238
+ result.text.should == "almost singular"
239
+ end
240
+ it "raises an error when there are multiple inexact matches" do
241
+ expect do
242
+ @session.find(:xpath, XPath.descendant[XPath.attr(:class).is("almost_singul")], :match => :smart, :exact => false)
243
+ end.to raise_error(Capybara::Ambiguous)
244
+ end
245
+ it "finds a single inexact match" do
246
+ result = @session.find(:xpath, XPath.descendant[XPath.attr(:class).is("almost_singular but")], :match => :smart, :exact => false)
247
+ result.text.should == "almost singular but not quite"
248
+ end
249
+ it "raises an error if there is no match" do
250
+ expect do
251
+ @session.find(:css, ".does-not-exist", :match => :smart, :exact => false)
252
+ end.to raise_error(Capybara::ElementNotFound)
253
+ end
254
+ end
255
+
256
+ context "with `exact` set to `true`" do
257
+ it "raises an error when there are multiple exact matches" do
258
+ expect do
259
+ @session.find(:xpath, XPath.descendant[XPath.attr(:class).is("multiple")], :match => :smart, :exact => true)
260
+ end.to raise_error(Capybara::Ambiguous)
261
+ end
262
+ it "finds a single exact match when there also are inexact matches" do
263
+ result = @session.find(:xpath, XPath.descendant[XPath.attr(:class).is("almost_singular")], :match => :smart, :exact => true)
264
+ result.text.should == "almost singular"
265
+ end
266
+ it "raises an error when there are multiple inexact matches" do
267
+ expect do
268
+ @session.find(:xpath, XPath.descendant[XPath.attr(:class).is("almost_singul")], :match => :smart, :exact => true)
269
+ end.to raise_error(Capybara::ElementNotFound)
270
+ end
271
+ it "raises an error when there is a single inexact matches" do
272
+ expect do
273
+ result = @session.find(:xpath, XPath.descendant[XPath.attr(:class).is("almost_singular but")], :match => :smart, :exact => true)
274
+ end.to raise_error(Capybara::ElementNotFound)
275
+ end
276
+ it "raises an error if there is no match" do
277
+ expect do
278
+ @session.find(:css, ".does-not-exist", :match => :smart, :exact => true)
279
+ end.to raise_error(Capybara::ElementNotFound)
280
+ end
281
+ end
282
+ end
283
+
284
+ context "when set to `prefer_exact`" do
285
+ context "and `exact` set to `false`" do
286
+ it "picks the first one when there are multiple exact matches" do
287
+ result = @session.find(:xpath, XPath.descendant[XPath.attr(:class).is("multiple")], :match => :prefer_exact, :exact => false)
288
+ result.text.should == "multiple one"
289
+ end
290
+ it "finds a single exact match when there also are inexact matches" do
291
+ result = @session.find(:xpath, XPath.descendant[XPath.attr(:class).is("almost_singular")], :match => :prefer_exact, :exact => false)
292
+ result.text.should == "almost singular"
293
+ end
294
+ it "picks the first one when there are multiple inexact matches" do
295
+ result = @session.find(:xpath, XPath.descendant[XPath.attr(:class).is("almost_singul")], :match => :prefer_exact, :exact => false)
296
+ result.text.should == "almost singular but not quite"
297
+ end
298
+ it "finds a single inexact match" do
299
+ result = @session.find(:xpath, XPath.descendant[XPath.attr(:class).is("almost_singular but")], :match => :prefer_exact, :exact => false)
300
+ result.text.should == "almost singular but not quite"
301
+ end
302
+ it "raises an error if there is no match" do
303
+ expect do
304
+ @session.find(:css, ".does-not-exist", :match => :prefer_exact, :exact => false)
305
+ end.to raise_error(Capybara::ElementNotFound)
306
+ end
307
+ end
308
+
309
+ context "with `exact` set to `true`" do
310
+ it "picks the first one when there are multiple exact matches" do
311
+ result = @session.find(:xpath, XPath.descendant[XPath.attr(:class).is("multiple")], :match => :prefer_exact, :exact => true)
312
+ result.text.should == "multiple one"
313
+ end
314
+ it "finds a single exact match when there also are inexact matches" do
315
+ result = @session.find(:xpath, XPath.descendant[XPath.attr(:class).is("almost_singular")], :match => :prefer_exact, :exact => true)
316
+ result.text.should == "almost singular"
317
+ end
318
+ it "raises an error if there are multiple inexact matches" do
319
+ expect do
320
+ @session.find(:xpath, XPath.descendant[XPath.attr(:class).is("almost_singul")], :match => :prefer_exact, :exact => true)
321
+ end.to raise_error(Capybara::ElementNotFound)
322
+ end
323
+ it "raises an error if there is a single inexact match" do
324
+ expect do
325
+ @session.find(:xpath, XPath.descendant[XPath.attr(:class).is("almost_singular but")], :match => :prefer_exact, :exact => true)
326
+ end.to raise_error(Capybara::ElementNotFound)
327
+ end
328
+ it "raises an error if there is no match" do
329
+ expect do
330
+ @session.find(:css, ".does-not-exist", :match => :prefer_exact, :exact => true)
331
+ end.to raise_error(Capybara::ElementNotFound)
332
+ end
333
+ end
334
+ end
335
+
336
+ it "defaults to `Capybara.match`" do
337
+ Capybara.match = :one
338
+ expect do
339
+ @session.find(:css, ".multiple")
340
+ end.to raise_error(Capybara::Ambiguous)
341
+ Capybara.match = :first
342
+ @session.find(:css, ".multiple").text.should == "multiple one"
343
+ end
344
+
345
+ it "raises an error when unknown option given" do
346
+ expect do
347
+ @session.find(:css, ".singular", :match => :schmoo)
348
+ end.to raise_error(ArgumentError)
349
+ end
350
+ end
351
+
116
352
  context "within a scope" do
117
353
  before do
118
354
  @session.visit('/with_scope')
@@ -123,5 +359,11 @@ Capybara::SpecHelper.spec '#find' do
123
359
  @session.find('.//li[1]').text.should =~ /With Simple HTML/
124
360
  end
125
361
  end
362
+
363
+ it "should support pseudo selectors" do
364
+ @session.within(:xpath, "//div[@id='for_bar']") do
365
+ @session.find(:css, 'input:disabled').value.should == 'James'
366
+ end
367
+ end
126
368
  end
127
369
  end