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.
@@ -1,4 +1,20 @@
1
- # Versiob 0.3.7
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
 
@@ -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)
@@ -30,6 +30,10 @@ class Capybara::Driver::Base
30
30
  raise NotImplementedError
31
31
  end
32
32
 
33
+ def within_frame(frame_id)
34
+ raise Capybara::NotSupportedByDriverError
35
+ end
36
+
33
37
  def source
34
38
  raise NotImplementedError
35
39
  end
@@ -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='#{self[:name]}']").each { |node| node.remove_attribute("checked") }
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
- else
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()='#{option}']").first ||
53
- node.xpath(".//option[contains(.,'#{option}')]").first
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()='#{option}']").first ||
67
- node.xpath(".//option[contains(.,'#{option}')]").first
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()='#{option}']") || node.find_element(:xpath, ".//option[contains(.,'#{option}')]")
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()='#{option}']") || node.find_element(:xpath, ".//option[contains(.,'#{option}')]")
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)
@@ -33,6 +33,7 @@ module Capybara
33
33
  results = all_unfiltered(locator)
34
34
 
35
35
  if options[:text]
36
+ options[:text] = Regexp.escape(options[:text]) unless options[:text].kind_of?(Regexp)
36
37
  results = results.select { |n| n.text.match(options[:text]) }
37
38
  end
38
39
 
@@ -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?, :has_no_button?,
14
- :has_field?, :has_no_field?, :has_checked_field?, :has_unchecked_field?, :has_no_table?, :has_table?, :unselect,
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)
@@ -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
 
@@ -0,0 +1,8 @@
1
+ <html>
2
+ <head>
3
+ <title>This is the title of frame one</title>
4
+ </head>
5
+ <body>
6
+ <div id="divInFrameOne">This is the text of divInFrameOne</div>
7
+ </body>
8
+ </html>
@@ -0,0 +1,8 @@
1
+ <html>
2
+ <head>
3
+ <title>This is the title of frame two</title>
4
+ </head>
5
+ <body>
6
+ <div id="divInFrameTwo">This is the text of divInFrameTwo</div>
7
+ </body>
8
+ </html>
@@ -0,0 +1,10 @@
1
+ <html>
2
+ <head>
3
+ <title>With Frames</title>
4
+ </head>
5
+ <body>
6
+ <div id="divInMainWindow">This is the text for divInMainWindow</div>
7
+ <iframe src="/frame_one" id="frameOne"></iframe>
8
+ <iframe src="/frame_two" id="frameTwo"></iframe>
9
+ </body>
10
+ </html>
@@ -1,3 +1,3 @@
1
1
  module Capybara
2
- VERSION = '0.3.7'
2
+ VERSION = '0.3.8'
3
3
  end
@@ -18,6 +18,8 @@ module Capybara
18
18
  end
19
19
 
20
20
  driver && driver.wait_until(delay)
21
+
22
+ sleep(0.05)
21
23
  end
22
24
  end
23
25
 
@@ -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
- if string.include?("'")
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
@@ -7,5 +7,5 @@ describe Capybara::Driver::Selenium do
7
7
 
8
8
  it_should_behave_like "driver"
9
9
  it_should_behave_like "driver with javascript support"
10
-
10
+ it_should_behave_like "driver with frame support"
11
11
  end
@@ -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
- - 7
9
- version: 0.3.7
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-04-09 00:00:00 +02:00
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