mirror of
https://github.com/teamcapybara/capybara.git
synced 2022-11-09 12:08:07 -05:00
Moved waiting back into session where it belongs
Also expose the new wait_for method As an added bonus, find and all now accept XPath instances and handle them correctly
This commit is contained in:
parent
c33e17f326
commit
9c9f3684a9
8 changed files with 117 additions and 42 deletions
|
@ -11,10 +11,7 @@ class Capybara::Driver::Base
|
|||
raise "Not implemented"
|
||||
end
|
||||
|
||||
def fetch(*paths)
|
||||
paths.find do |path|
|
||||
result = find(path).first
|
||||
return result if result
|
||||
end
|
||||
def wait?
|
||||
false
|
||||
end
|
||||
end
|
|
@ -70,14 +70,7 @@ class Capybara::Driver::Culerity < Capybara::Driver::Base
|
|||
browser.elements_by_xpath(selector).map { |node| Node.new(self, node) }
|
||||
end
|
||||
|
||||
def fetch(*paths)
|
||||
8.times do
|
||||
result = super
|
||||
return result if result
|
||||
sleep(0.1)
|
||||
end
|
||||
nil
|
||||
end
|
||||
def wait?; true; end
|
||||
|
||||
private
|
||||
|
||||
|
|
|
@ -84,14 +84,7 @@ class Capybara::Driver::Selenium < Capybara::Driver::Base
|
|||
driver.find_elements(:xpath, selector).map { |node| Node.new(self, node) }
|
||||
end
|
||||
|
||||
def fetch(*paths)
|
||||
8.times do
|
||||
result = super
|
||||
return result if result
|
||||
sleep(0.1)
|
||||
end
|
||||
nil
|
||||
end
|
||||
def wait?; true; end
|
||||
|
||||
private
|
||||
|
||||
|
|
|
@ -50,7 +50,7 @@ module Capybara
|
|||
:visit, :body, :click_link, :click_button, :fill_in, :choose, :has_xpath?, :has_css?,
|
||||
:check, :uncheck, :attach_file, :select, :has_content?, :within, :within_fieldset,
|
||||
:within_table, :save_and_open_page, :find, :find_field, :find_link, :find_button,
|
||||
:field_labeled, :all
|
||||
:field_labeled, :all, :wait_for
|
||||
]
|
||||
SESSION_METHODS.each do |method|
|
||||
class_eval <<-RUBY, __FILE__, __LINE__+1
|
||||
|
|
|
@ -26,49 +26,49 @@ module Capybara
|
|||
end
|
||||
|
||||
def click_link(locator)
|
||||
link = find_link(locator)
|
||||
link = wait_for(XPath.link(locator))
|
||||
raise Capybara::ElementNotFound, "no link with title, id or text '#{locator}' found" unless link
|
||||
link.click
|
||||
end
|
||||
|
||||
def click_button(locator)
|
||||
button = find_button(locator)
|
||||
button = wait_for(XPath.button(locator))
|
||||
raise Capybara::ElementNotFound, "no button with value or id or text '#{locator}' found" unless button
|
||||
button.click
|
||||
end
|
||||
|
||||
def fill_in(locator, options={})
|
||||
field = fetch_xpath(XPath.fillable_field(locator))
|
||||
field = wait_for(XPath.fillable_field(locator))
|
||||
raise Capybara::ElementNotFound, "cannot fill in, no text field, text area or password field with id or label '#{locator}' found" unless field
|
||||
field.set(options[:with])
|
||||
end
|
||||
|
||||
def choose(locator)
|
||||
field = fetch_xpath(XPath.radio_button(locator))
|
||||
field = wait_for(XPath.radio_button(locator))
|
||||
raise Capybara::ElementNotFound, "cannot choose field, no radio button with id or label '#{locator}' found" unless field
|
||||
field.set(true)
|
||||
end
|
||||
|
||||
def check(locator)
|
||||
field = fetch_xpath(XPath.checkbox(locator))
|
||||
field = wait_for(XPath.checkbox(locator))
|
||||
raise Capybara::ElementNotFound, "cannot check field, no checkbox with id or label '#{locator}' found" unless field
|
||||
field.set(true)
|
||||
end
|
||||
|
||||
def uncheck(locator)
|
||||
field = fetch_xpath(XPath.checkbox(locator))
|
||||
field = wait_for(XPath.checkbox(locator))
|
||||
raise Capybara::ElementNotFound, "cannot uncheck field, no checkbox with id or label '#{locator}' found" unless field
|
||||
field.set(false)
|
||||
end
|
||||
|
||||
def select(value, options={})
|
||||
field = fetch_xpath(XPath.select(options[:from]))
|
||||
field = wait_for(XPath.select(options[:from]))
|
||||
raise Capybara::ElementNotFound, "cannot select option, no select box with id or label '#{options[:from]}' found" unless field
|
||||
field.select(value)
|
||||
end
|
||||
|
||||
def attach_file(locator, path)
|
||||
field = fetch_xpath(XPath.file_field(locator))
|
||||
field = wait_for(XPath.file_field(locator))
|
||||
raise Capybara::ElementNotFound, "cannot attach file, no file field with id or label '#{locator}' found" unless field
|
||||
field.set(path)
|
||||
end
|
||||
|
@ -100,7 +100,7 @@ module Capybara
|
|||
def within(kind, scope=nil)
|
||||
kind, scope = Capybara.default_selector, kind unless scope
|
||||
scope = css_to_xpath(scope) if kind == :css
|
||||
raise Capybara::ElementNotFound, "scope '#{scope}' not found on page" unless find(scope)
|
||||
raise Capybara::ElementNotFound, "scope '#{scope}' not found on page" unless wait_for(scope)
|
||||
scopes.push(scope)
|
||||
yield
|
||||
scopes.pop
|
||||
|
@ -124,33 +124,40 @@ module Capybara
|
|||
end
|
||||
|
||||
def all(locator)
|
||||
locator = current_scope.to_s + locator
|
||||
driver.find(locator)
|
||||
XPath.wrap(locator).scope(current_scope).paths.map do |path|
|
||||
driver.find(path)
|
||||
end.flatten
|
||||
end
|
||||
|
||||
def find(locator)
|
||||
all(locator.to_s).first
|
||||
all(locator).first
|
||||
end
|
||||
|
||||
def wait_for(locator)
|
||||
return find(locator) unless driver.wait?
|
||||
8.times do
|
||||
result = find(locator)
|
||||
return result if result
|
||||
sleep(0.1)
|
||||
end
|
||||
nil
|
||||
end
|
||||
|
||||
def find_field(locator)
|
||||
fetch_xpath(XPath.field(locator))
|
||||
find(XPath.field(locator))
|
||||
end
|
||||
alias_method :field_labeled, :find_field
|
||||
|
||||
def find_link(locator)
|
||||
fetch_xpath(XPath.link(locator))
|
||||
find(XPath.link(locator))
|
||||
end
|
||||
|
||||
def find_button(locator)
|
||||
fetch_xpath(XPath.button(locator))
|
||||
find(XPath.button(locator))
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def fetch_xpath(xpath)
|
||||
driver.fetch(*xpath.paths.map { |path| current_scope.to_s + path })
|
||||
end
|
||||
|
||||
def css_to_xpath(css)
|
||||
Nokogiri::CSS.xpath_for(css).first
|
||||
end
|
||||
|
|
|
@ -4,6 +4,14 @@ module Capybara
|
|||
# this will generate an XPath that matches either a text field or a link
|
||||
class XPath
|
||||
class << self
|
||||
def wrap(path)
|
||||
if path.is_a?(self)
|
||||
path
|
||||
else
|
||||
new(path.to_s)
|
||||
end
|
||||
end
|
||||
|
||||
def respond_to?(method)
|
||||
new.respond_to?(method)
|
||||
end
|
||||
|
@ -76,6 +84,10 @@ module Capybara
|
|||
add_field(locator) { |id| "//input[@type='file'][@id=#{id}]" }
|
||||
end
|
||||
|
||||
def scope(scope)
|
||||
XPath.new(*paths.map { |p| scope + p })
|
||||
end
|
||||
|
||||
def to_s
|
||||
@paths.join(' | ')
|
||||
end
|
||||
|
|
|
@ -607,6 +607,13 @@ shared_examples_for "session" do
|
|||
@session.all('//div').should be_empty
|
||||
end
|
||||
|
||||
it "should accept an XPath instance" do
|
||||
@session.visit('/form')
|
||||
@xpath = Capybara::XPath.text_field('Name')
|
||||
@result = @session.all(@xpath)
|
||||
@result.map(&:value).should include('Smith', 'John', 'John Smith')
|
||||
end
|
||||
|
||||
context "within a scope" do
|
||||
before do
|
||||
@session.visit('/with_scope')
|
||||
|
@ -634,6 +641,12 @@ shared_examples_for "session" do
|
|||
@session.find('//div').should be_nil
|
||||
end
|
||||
|
||||
it "should accept an XPath instance and respect the order of paths" do
|
||||
@session.visit('/form')
|
||||
@xpath = Capybara::XPath.text_field('Name')
|
||||
@session.find(@xpath).value.should == 'John Smith'
|
||||
end
|
||||
|
||||
context "within a scope" do
|
||||
before do
|
||||
@session.visit('/with_scope')
|
||||
|
@ -647,6 +660,39 @@ shared_examples_for "session" do
|
|||
end
|
||||
end
|
||||
|
||||
describe '#wait_for' do
|
||||
before do
|
||||
@session.visit('/with_html')
|
||||
end
|
||||
|
||||
it "should find the first element using the given locator" do
|
||||
@session.wait_for('//h1').text.should == 'This is a test'
|
||||
@session.wait_for("//input[@id='test_field']")[:value].should == 'monkey'
|
||||
end
|
||||
|
||||
it "should return nil when nothing was found" do
|
||||
@session.wait_for('//div').should be_nil
|
||||
end
|
||||
|
||||
it "should accept an XPath instance and respect the order of paths" do
|
||||
@session.visit('/form')
|
||||
@xpath = Capybara::XPath.text_field('Name')
|
||||
@session.wait_for(@xpath).value.should == 'John Smith'
|
||||
end
|
||||
|
||||
context "within a scope" do
|
||||
before do
|
||||
@session.visit('/with_scope')
|
||||
end
|
||||
|
||||
it "should find the first element using the given locator" do
|
||||
@session.within(:xpath, "//div[@id='for_bar']") do
|
||||
@session.wait_for('//li').text.should =~ /With Simple HTML/
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#within' do
|
||||
before do
|
||||
@session.visit('/with_scope')
|
||||
|
@ -791,6 +837,14 @@ shared_examples_for "session" do
|
|||
end
|
||||
|
||||
shared_examples_for "session with javascript support" do
|
||||
describe '#wait_for' do
|
||||
it "should wait for asynchronous load" do
|
||||
@session.visit('/with_js')
|
||||
@session.click_link('Click me')
|
||||
@session.wait_for("//a[contains(.,'Has been clicked')]")[:href].should == '#'
|
||||
end
|
||||
end
|
||||
|
||||
describe '#click_link' do
|
||||
it "should wait for asynchronous load" do
|
||||
@session.visit('/with_js')
|
||||
|
|
|
@ -17,6 +17,25 @@ describe Capybara::XPath do
|
|||
Capybara::XPath.should respond_to(:fillable_field)
|
||||
end
|
||||
|
||||
describe '.wrap' do
|
||||
it "should return an XPath unmodified" do
|
||||
Capybara::XPath.wrap(@xpath).should == @xpath
|
||||
end
|
||||
|
||||
it "should wrap a string in an xpath object" do
|
||||
@xpath = Capybara::XPath.wrap('//foo/bar')
|
||||
@xpath.should be_an_instance_of(Capybara::XPath)
|
||||
@xpath.paths.should == ['//foo/bar']
|
||||
end
|
||||
end
|
||||
|
||||
describe '#scope' do
|
||||
it "should prepend the given scope to all paths" do
|
||||
@xpath = Capybara::XPath.new('//foo/bar', '//test[@blah=foo]').scope('//quox')
|
||||
@xpath.paths.should include('//quox//foo/bar', '//quox//test[@blah=foo]')
|
||||
end
|
||||
end
|
||||
|
||||
describe '#field' do
|
||||
it "should find any field by id or label" do
|
||||
@query = @xpath.field('First Name').to_s
|
||||
|
|
Loading…
Add table
Reference in a new issue