capybara 0.3.7 → 0.3.8
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.
- data/History.txt +17 -1
- data/README.rdoc +2 -31
- data/lib/capybara/driver/base.rb +4 -0
- data/lib/capybara/driver/rack_test_driver.rb +7 -7
- data/lib/capybara/driver/selenium_driver.rb +11 -4
- data/lib/capybara/searchable.rb +1 -0
- data/lib/capybara/session.rb +10 -3
- data/lib/capybara/spec/driver.rb +31 -0
- data/lib/capybara/spec/session/check_spec.rb +28 -0
- data/lib/capybara/spec/session/fill_in_spec.rb +5 -1
- data/lib/capybara/spec/session/select_spec.rb +6 -0
- data/lib/capybara/spec/session/unselect_spec.rb +6 -0
- data/lib/capybara/spec/views/form.erb +2 -0
- data/lib/capybara/spec/views/frame_one.erb +8 -0
- data/lib/capybara/spec/views/frame_two.erb +8 -0
- data/lib/capybara/spec/views/within_frames.erb +10 -0
- data/lib/capybara/version.rb +1 -1
- data/lib/capybara/wait_until.rb +2 -0
- data/lib/capybara/xpath.rb +12 -9
- data/spec/driver/selenium_driver_spec.rb +1 -1
- data/spec/searchable_spec.rb +7 -2
- metadata +6 -3
data/History.txt
CHANGED
@@ -1,4 +1,20 @@
|
|
1
|
-
#
|
1
|
+
# Version 0.3.8
|
2
|
+
|
3
|
+
Release date: 2010-05-12
|
4
|
+
|
5
|
+
### Added
|
6
|
+
|
7
|
+
* Within_frame method to execute a block of code within a particular iframe (Selenium only!)
|
8
|
+
|
9
|
+
### Fixed
|
10
|
+
|
11
|
+
* Single quotes are properly escaped with `select` under rack-test and Selenium.
|
12
|
+
* The :text option for searches now escapes regexp special characters when a string is given.
|
13
|
+
* Selenium now correctly checks already checked checkboxes (same with uncheck)
|
14
|
+
* Timing issue which caused Selenium to hang under certain circumstances.
|
15
|
+
* Selenium now resolves attributes even if they are given as a Symbol
|
16
|
+
|
17
|
+
# Version 0.3.7
|
2
18
|
|
3
19
|
Release date: 2010-04-09
|
4
20
|
|
data/README.rdoc
CHANGED
@@ -27,7 +27,8 @@ On OSX you may have to install libffi, you can install it via MacPorts with:
|
|
27
27
|
* Report issues on {GitHub Issues}[http://github.com/jnicklas/capybara/issues]
|
28
28
|
|
29
29
|
Pull requests are very welcome! Make sure your patches are well tested, Capybara is
|
30
|
-
a testing tool after all.
|
30
|
+
a testing tool after all. Please create a topic branch for every separate change
|
31
|
+
you make.
|
31
32
|
|
32
33
|
== Using Capybara with Cucumber
|
33
34
|
|
@@ -362,36 +363,6 @@ moving from Webrat and used CSS a lot, or simply generally prefer CSS:
|
|
362
363
|
<tt><a href="/same/url#"></tt> instead. You can achieve this in Rails with
|
363
364
|
<tt>link_to('foo', :anchor => '')</tt>
|
364
365
|
|
365
|
-
== Contributors:
|
366
|
-
|
367
|
-
The following people have dedicated their time and effort to Capybara:
|
368
|
-
|
369
|
-
* Jonas Nicklas
|
370
|
-
* Dennis Rogenius
|
371
|
-
* Rob Holland
|
372
|
-
* Wincent Colaiuta
|
373
|
-
* Andrea Fazzi
|
374
|
-
* Aslak Hellesøy
|
375
|
-
* Andrew Brown
|
376
|
-
* Lenny Marks
|
377
|
-
* Aaron Patterson
|
378
|
-
* Dan Dofter
|
379
|
-
* Thorbjørn Hermansen
|
380
|
-
* Louis T.
|
381
|
-
* Stephan Hagemann
|
382
|
-
* Graham Ashton
|
383
|
-
* Joseph Wilk
|
384
|
-
* Matt Wynne
|
385
|
-
* Piotr Sarnacki
|
386
|
-
* Pavel Gabriel
|
387
|
-
* Bodaniel Jeanes
|
388
|
-
* Carl Porth
|
389
|
-
* Darrin Holst
|
390
|
-
* Steven Parkes
|
391
|
-
* Davide Marquês
|
392
|
-
* Lucas Prim
|
393
|
-
* José Valim
|
394
|
-
|
395
366
|
== License:
|
396
367
|
|
397
368
|
(The MIT License)
|
data/lib/capybara/driver/base.rb
CHANGED
@@ -29,12 +29,12 @@ class Capybara::Driver::RackTest < Capybara::Driver::Base
|
|
29
29
|
|
30
30
|
def set(value)
|
31
31
|
if tag_name == 'input' and type == 'radio'
|
32
|
-
driver.html.xpath("//input[@name
|
32
|
+
driver.html.xpath("//input[@name=#{Capybara::XPath.escape(self[:name])}]").each { |node| node.remove_attribute("checked") }
|
33
33
|
node['checked'] = 'checked'
|
34
34
|
elsif tag_name == 'input' and type == 'checkbox'
|
35
|
-
if value
|
35
|
+
if value && !node['checked']
|
36
36
|
node['checked'] = 'checked'
|
37
|
-
|
37
|
+
elsif !value && node['checked']
|
38
38
|
node.remove_attribute('checked')
|
39
39
|
end
|
40
40
|
elsif tag_name == 'input'
|
@@ -49,8 +49,8 @@ class Capybara::Driver::RackTest < Capybara::Driver::Base
|
|
49
49
|
node.xpath(".//option[@selected]").each { |node| node.remove_attribute("selected") }
|
50
50
|
end
|
51
51
|
|
52
|
-
if option_node = node.xpath(".//option[text()
|
53
|
-
node.xpath(".//option[contains(
|
52
|
+
if option_node = node.xpath(".//option[text()=#{Capybara::XPath.escape(option)}]").first ||
|
53
|
+
node.xpath(".//option[contains(.,#{Capybara::XPath.escape(option)})]").first
|
54
54
|
option_node["selected"] = 'selected'
|
55
55
|
else
|
56
56
|
options = node.xpath(".//option").map { |o| "'#{o.text}'" }.join(', ')
|
@@ -63,8 +63,8 @@ class Capybara::Driver::RackTest < Capybara::Driver::Base
|
|
63
63
|
raise Capybara::UnselectNotAllowed, "Cannot unselect option '#{option}' from single select box."
|
64
64
|
end
|
65
65
|
|
66
|
-
if option_node = node.xpath(".//option[text()
|
67
|
-
node.xpath(".//option[contains(
|
66
|
+
if option_node = node.xpath(".//option[text()=#{Capybara::XPath.escape(option)}]").first ||
|
67
|
+
node.xpath(".//option[contains(.,#{Capybara::XPath.escape(option)})]").first
|
68
68
|
option_node.remove_attribute('selected')
|
69
69
|
else
|
70
70
|
options = node.xpath(".//option").map { |o| "'#{o.text}'" }.join(', ')
|
@@ -10,7 +10,7 @@ class Capybara::Driver::Selenium < Capybara::Driver::Base
|
|
10
10
|
if name == :value
|
11
11
|
node.value
|
12
12
|
else
|
13
|
-
node.attribute(name)
|
13
|
+
node.attribute(name.to_s)
|
14
14
|
end
|
15
15
|
rescue Selenium::WebDriver::Error::WebDriverError
|
16
16
|
nil
|
@@ -31,12 +31,12 @@ class Capybara::Driver::Selenium < Capybara::Driver::Base
|
|
31
31
|
elsif tag_name == 'input' and type == 'radio'
|
32
32
|
node.click
|
33
33
|
elsif tag_name == 'input' and type == 'checkbox'
|
34
|
-
node.click
|
34
|
+
node.click if node.attribute('checked') != value
|
35
35
|
end
|
36
36
|
end
|
37
37
|
|
38
38
|
def select(option)
|
39
|
-
option_node = node.find_element(:xpath, ".//option[text()
|
39
|
+
option_node = node.find_element(:xpath, ".//option[text()=#{Capybara::XPath.escape(option)}]") || node.find_element(:xpath, ".//option[contains(.,#{Capybara::XPath.escape(option)})]")
|
40
40
|
option_node.select
|
41
41
|
rescue
|
42
42
|
options = node.find_elements(:xpath, "//option").map { |o| "'#{o.text}'" }.join(', ')
|
@@ -49,7 +49,7 @@ class Capybara::Driver::Selenium < Capybara::Driver::Base
|
|
49
49
|
end
|
50
50
|
|
51
51
|
begin
|
52
|
-
option_node = node.find_element(:xpath, ".//option[text()
|
52
|
+
option_node = node.find_element(:xpath, ".//option[text()=#{Capybara::XPath.escape(option)}]") || node.find_element(:xpath, ".//option[contains(.,#{Capybara::XPath.escape(option)})]")
|
53
53
|
option_node.clear
|
54
54
|
rescue
|
55
55
|
options = node.find_elements(:xpath, "//option").map { |o| "'#{o.text}'" }.join(', ')
|
@@ -140,6 +140,13 @@ class Capybara::Driver::Selenium < Capybara::Driver::Base
|
|
140
140
|
browser.manage.delete_all_cookies
|
141
141
|
end
|
142
142
|
|
143
|
+
def within_frame(frame_id)
|
144
|
+
old_window = browser.window_handle
|
145
|
+
browser.switch_to.frame(frame_id)
|
146
|
+
yield
|
147
|
+
browser.switch_to.window old_window
|
148
|
+
end
|
149
|
+
|
143
150
|
private
|
144
151
|
|
145
152
|
def url(path)
|
data/lib/capybara/searchable.rb
CHANGED
data/lib/capybara/session.rb
CHANGED
@@ -10,9 +10,9 @@ module Capybara
|
|
10
10
|
:all, :attach_file, :body, :check, :choose, :click, :click_button, :click_link, :current_url, :drag, :evaluate_script,
|
11
11
|
:field_labeled, :fill_in, :find, :find_button, :find_by_id, :find_field, :find_link, :has_content?, :has_css?,
|
12
12
|
:has_no_content?, :has_no_css?, :has_no_xpath?, :has_xpath?, :locate, :save_and_open_page, :select, :source, :uncheck,
|
13
|
-
:visit, :wait_until, :within, :within_fieldset, :within_table, :has_link?, :has_no_link?, :has_button?,
|
14
|
-
:has_field?, :has_no_field?, :has_checked_field?, :has_unchecked_field?, :has_no_table?, :has_table?,
|
15
|
-
:has_select?, :has_no_select?
|
13
|
+
:visit, :wait_until, :within, :within_fieldset, :within_table, :within_frame, :has_link?, :has_no_link?, :has_button?,
|
14
|
+
:has_no_button?, :has_field?, :has_no_field?, :has_checked_field?, :has_unchecked_field?, :has_no_table?, :has_table?,
|
15
|
+
:unselect, :has_select?, :has_no_select?
|
16
16
|
]
|
17
17
|
|
18
18
|
attr_reader :mode, :app
|
@@ -62,6 +62,7 @@ module Capybara
|
|
62
62
|
|
63
63
|
def fill_in(locator, options={})
|
64
64
|
msg = "cannot fill in, no text field, text area or password field with id, name, or label '#{locator}' found"
|
65
|
+
raise "Must pass a hash containing 'with'" if not options.is_a?(Hash) or not options.has_key?(:with)
|
65
66
|
locate(:xpath, XPath.fillable_field(locator), msg).set(options[:with])
|
66
67
|
end
|
67
68
|
|
@@ -119,6 +120,12 @@ module Capybara
|
|
119
120
|
end
|
120
121
|
end
|
121
122
|
|
123
|
+
def within_frame(frame_id)
|
124
|
+
driver.within_frame(frame_id) do
|
125
|
+
yield
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
122
129
|
def has_xpath?(path, options={})
|
123
130
|
wait_conditionally_until do
|
124
131
|
results = all(:xpath, path, options)
|
data/lib/capybara/spec/driver.rb
CHANGED
@@ -129,3 +129,34 @@ shared_examples_for "driver with header support" do
|
|
129
129
|
@driver.response_headers['Content-Type'].should == 'text/html'
|
130
130
|
end
|
131
131
|
end
|
132
|
+
|
133
|
+
shared_examples_for "driver with frame support" do
|
134
|
+
describe '#within_frame' do
|
135
|
+
before(:each) do
|
136
|
+
@driver.visit('/within_frames')
|
137
|
+
end
|
138
|
+
|
139
|
+
it "should find the div in frameOne" do
|
140
|
+
@driver.within_frame("frameOne") do
|
141
|
+
@driver.find("//*[@id='divInFrameOne']")[0].text.should eql 'This is the text of divInFrameOne'
|
142
|
+
end
|
143
|
+
end
|
144
|
+
it "should find the div in FrameTwo" do
|
145
|
+
@driver.within_frame("frameTwo") do
|
146
|
+
@driver.find("//*[@id='divInFrameTwo']")[0].text.should eql 'This is the text of divInFrameTwo'
|
147
|
+
end
|
148
|
+
end
|
149
|
+
it "should find the text div in the main window after finding text in frameOne" do
|
150
|
+
@driver.within_frame("frameOne") do
|
151
|
+
@driver.find("//*[@id='divInFrameOne']")[0].text.should eql 'This is the text of divInFrameOne'
|
152
|
+
end
|
153
|
+
@driver.find("//*[@id='divInMainWindow']")[0].text.should eql 'This is the text for divInMainWindow'
|
154
|
+
end
|
155
|
+
it "should find the text div in the main window after finding text in frameTwo" do
|
156
|
+
@driver.within_frame("frameTwo") do
|
157
|
+
@driver.find("//*[@id='divInFrameTwo']")[0].text.should eql 'This is the text of divInFrameTwo'
|
158
|
+
end
|
159
|
+
@driver.find("//*[@id='divInMainWindow']")[0].text.should eql 'This is the text for divInMainWindow'
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
@@ -17,6 +17,34 @@ module CheckSpec
|
|
17
17
|
end
|
18
18
|
end
|
19
19
|
|
20
|
+
describe "checking" do
|
21
|
+
it "should not change an already checked checkbox" do
|
22
|
+
@session.find(:xpath, "//input[@id='form_pets_dog']")['checked'].should be_true
|
23
|
+
@session.check('form_pets_dog')
|
24
|
+
@session.find(:xpath, "//input[@id='form_pets_dog']")['checked'].should be_true
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should check an unchecked checkbox" do
|
28
|
+
@session.find(:xpath, "//input[@id='form_pets_cat']")['checked'].should be_false
|
29
|
+
@session.check('form_pets_cat')
|
30
|
+
@session.find(:xpath, "//input[@id='form_pets_cat']")['checked'].should be_true
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
describe "unchecking" do
|
35
|
+
it "should not change an already unchecked checkbox" do
|
36
|
+
@session.find(:xpath, "//input[@id='form_pets_cat']")['checked'].should be_false
|
37
|
+
@session.uncheck('form_pets_cat')
|
38
|
+
@session.find(:xpath, "//input[@id='form_pets_cat']")['checked'].should be_false
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should uncheck a checked checkbox" do
|
42
|
+
@session.find(:xpath, "//input[@id='form_pets_dog']")['checked'].should be_true
|
43
|
+
@session.uncheck('form_pets_dog')
|
44
|
+
@session.find(:xpath, "//input[@id='form_pets_dog']")['checked'].should be_false
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
20
48
|
it "should check a checkbox by id" do
|
21
49
|
@session.check("form_pets_cat")
|
22
50
|
@session.click_button('awesome')
|
@@ -82,7 +82,11 @@ shared_examples_for "fill_in" do
|
|
82
82
|
@session.click_button('awesome')
|
83
83
|
extract_results(@session)['name'].should == 'Ford Prefect'
|
84
84
|
end
|
85
|
-
|
85
|
+
|
86
|
+
it "should throw an exception if a hash containing 'with' is not provided" do
|
87
|
+
lambda{@session.fill_in 'Name', 'ignu'}.should raise_error
|
88
|
+
end
|
89
|
+
|
86
90
|
context "with ignore_hidden_fields" do
|
87
91
|
before { Capybara.ignore_hidden_elements = true }
|
88
92
|
after { Capybara.ignore_hidden_elements = false }
|
@@ -31,6 +31,12 @@ shared_examples_for "select" do
|
|
31
31
|
extract_results(@session)['title'].should == 'Mr'
|
32
32
|
end
|
33
33
|
|
34
|
+
it "should escape quotes" do
|
35
|
+
@session.select("John's made-up language", :from => 'Locale')
|
36
|
+
@session.click_button('awesome')
|
37
|
+
extract_results(@session)['locale'].should == 'jo'
|
38
|
+
end
|
39
|
+
|
34
40
|
context "with a locator that doesn't exist" do
|
35
41
|
it "should raise an error" do
|
36
42
|
running { @session.select('foo', :from => 'does not exist') }.should raise_error(Capybara::ElementNotFound)
|
@@ -25,6 +25,12 @@ shared_examples_for "unselect" do
|
|
25
25
|
extract_results(@session)['underwear'].should include('Commando', 'Boxer Briefs')
|
26
26
|
extract_results(@session)['underwear'].should_not include('Briefs')
|
27
27
|
end
|
28
|
+
|
29
|
+
it "should escape quotes" do
|
30
|
+
@session.unselect("Frenchman's Pantalons", :from => 'Underwear')
|
31
|
+
@session.click_button('awesome')
|
32
|
+
extract_results(@session)['underwear'].should_not include("Frenchman's Pantalons")
|
33
|
+
end
|
28
34
|
end
|
29
35
|
|
30
36
|
context "with single select" do
|
@@ -76,6 +76,7 @@
|
|
76
76
|
<option selected="selected" value="en">English</option>
|
77
77
|
<option value="fi">Finish</option>
|
78
78
|
<option value="no">Norwegian</option>
|
79
|
+
<option value="jo">John's made-up language</option>
|
79
80
|
</select>
|
80
81
|
</p>
|
81
82
|
|
@@ -142,6 +143,7 @@
|
|
142
143
|
<option>Boxers</option>
|
143
144
|
<option selected="selected">Briefs</option>
|
144
145
|
<option selected="selected">Commando</option>
|
146
|
+
<option selected="selected">Frenchman's Pantalons</option>
|
145
147
|
</select>
|
146
148
|
</p>
|
147
149
|
|
data/lib/capybara/version.rb
CHANGED
data/lib/capybara/wait_until.rb
CHANGED
data/lib/capybara/xpath.rb
CHANGED
@@ -5,6 +5,17 @@ module Capybara
|
|
5
5
|
class XPath
|
6
6
|
|
7
7
|
class << self
|
8
|
+
def escape(string)
|
9
|
+
if string.include?("'")
|
10
|
+
string = string.split("'", -1).map do |substr|
|
11
|
+
"'#{substr}'"
|
12
|
+
end.join(%q{,"'",})
|
13
|
+
"concat(#{string})"
|
14
|
+
else
|
15
|
+
"'#{string}'"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
8
19
|
def wrap(path)
|
9
20
|
if path.is_a?(self)
|
10
21
|
path
|
@@ -161,15 +172,7 @@ module Capybara
|
|
161
172
|
|
162
173
|
# Sanitize a String for putting it into an xpath query
|
163
174
|
def s(string)
|
164
|
-
|
165
|
-
string = string.split("'", -1).map do |substr|
|
166
|
-
"'#{substr}'"
|
167
|
-
end.join(%q{,"'",})
|
168
|
-
"concat(#{string})"
|
169
|
-
else
|
170
|
-
"'#{string}'"
|
171
|
-
end
|
172
|
-
|
175
|
+
XPath.escape(string)
|
173
176
|
end
|
174
177
|
|
175
178
|
end
|
data/spec/searchable_spec.rb
CHANGED
@@ -26,8 +26,8 @@ module Capybara
|
|
26
26
|
|
27
27
|
context "with :text filter" do
|
28
28
|
before do
|
29
|
-
@node1 = stub(Node, :text => 'node one text')
|
30
|
-
@node2 = stub(Node, :text => 'node two text')
|
29
|
+
@node1 = stub(Node, :text => 'node one text (with parens)')
|
30
|
+
@node2 = stub(Node, :text => 'node two text [-]')
|
31
31
|
@searchable.stub(:all_unfiltered).and_return([@node1, @node2])
|
32
32
|
end
|
33
33
|
|
@@ -40,6 +40,11 @@ module Capybara
|
|
40
40
|
@searchable.all('//x', :text => "node one").should == [@node1]
|
41
41
|
@searchable.all('//x', :text => "node two").should == [@node2]
|
42
42
|
end
|
43
|
+
|
44
|
+
it "should allow Regexp reserved words in text" do
|
45
|
+
@searchable.all('//x', :text => "node one text (with parens)").should == [@node1]
|
46
|
+
@searchable.all('//x', :text => "node two text [-]").should == [@node2]
|
47
|
+
end
|
43
48
|
end
|
44
49
|
|
45
50
|
context "with :visible filter" do
|
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 3
|
8
|
-
-
|
9
|
-
version: 0.3.
|
8
|
+
- 8
|
9
|
+
version: 0.3.8
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Jonas Nicklas
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2010-
|
17
|
+
date: 2010-05-12 00:00:00 +02:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
@@ -191,12 +191,15 @@ files:
|
|
191
191
|
- lib/capybara/spec/views/buttons.erb
|
192
192
|
- lib/capybara/spec/views/fieldsets.erb
|
193
193
|
- lib/capybara/spec/views/form.erb
|
194
|
+
- lib/capybara/spec/views/frame_one.erb
|
195
|
+
- lib/capybara/spec/views/frame_two.erb
|
194
196
|
- lib/capybara/spec/views/postback.erb
|
195
197
|
- lib/capybara/spec/views/tables.erb
|
196
198
|
- lib/capybara/spec/views/with_html.erb
|
197
199
|
- lib/capybara/spec/views/with_js.erb
|
198
200
|
- lib/capybara/spec/views/with_scope.erb
|
199
201
|
- lib/capybara/spec/views/with_simple_html.erb
|
202
|
+
- lib/capybara/spec/views/within_frames.erb
|
200
203
|
- lib/capybara/version.rb
|
201
204
|
- lib/capybara/wait_until.rb
|
202
205
|
- lib/capybara/xpath.rb
|