capybara 0.3.7 → 0.3.8

Sign up to get free protection for your applications and to get access to all the features.
@@ -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