Session#locate - return node identified by locator or raise ElementNotFound(using desc)

- Replaced usage of wait_for with locate.
- wait_until back to raising error instead of returning false (This is key)
- wait_for_condition removed

Capybara::Session with culerity driver#wait_until
- should wait for block to return true
- should raise Capybara::TimeoutError if block doesn't return true within timeout
- should accept custom timeout in seconds
- should default to Capybara.default_wait_time before timeout

Capybara::Session with culerity driver#locate
- should find the first element using the given locator
- should raise ElementNotFound with specified fail message if nothing was found
- should accept an XPath instance and respect the order of paths

Capybara::Session with culerity driver#locate within a scope
- should find the first element using the given locator

Capybara::Session with culerity driver#locate
- should wait for asynchronous load
This commit is contained in:
Lenny Marks 2009-12-31 14:04:38 -05:00
parent e41c757394
commit 8a0064cc1b
5 changed files with 89 additions and 87 deletions

View File

@ -1,3 +1,5 @@
require 'capybara/wait_until'
module Capybara
class Session
include Searchable
@ -38,65 +40,56 @@ module Capybara
end
def click(locator)
link = wait_for(XPath.link(locator).button(locator))
raise Capybara::ElementNotFound, "no link or button '#{locator}' found" unless link
link.click
msg = "no link or button '#{locator}' found"
locate(XPath.link(locator).button(locator), msg).click
end
def click_link(locator)
link = wait_for(XPath.link(locator))
raise Capybara::ElementNotFound, "no link with title, id or text '#{locator}' found" unless link
link.click
msg = "no link with title, id or text '#{locator}' found"
locate(XPath.link(locator), msg).click
end
def click_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
msg = "no button with value or id or text '#{locator}' found"
locate(XPath.button(locator)).click
end
def drag(source_locator, target_locator)
source = wait_for(source_locator)
raise Capybara::ElementNotFound, "drag source '#{source_locator}' not found on page" unless source
target = wait_for(target_locator)
raise Capybara::ElementNotFound, "drag target '#{target_locator}' not found on page" unless target
source = locate(source_locator, "drag source '#{source_locator}' not found on page")
target = locate(target_locator, "drag target '#{target_locator}' not found on page")
source.drag_to(target)
end
def fill_in(locator, options={})
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])
msg = "cannot fill in, no text field, text area or password field with id or label '#{locator}' found"
locate(XPath.fillable_field(locator), msg).set(options[:with])
end
def choose(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)
msg = "cannot choose field, no radio button with id or label '#{locator}' found"
locate(XPath.radio_button(locator), msg).set(true)
end
def check(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)
msg = "cannot check field, no checkbox with id or label '#{locator}' found"
locate(XPath.checkbox(locator), msg).set(true)
end
def uncheck(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)
msg = "cannot uncheck field, no checkbox with id or label '#{locator}' found"
locate(XPath.checkbox(locator), msg).set(false)
end
def select(value, options={})
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)
msg = "cannot select option, no select box with id or label '#{options[:from]}' found"
locate(XPath.select(options[:from])).select(value)
end
def attach_file(locator, path)
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)
msg = "cannot attach file, no file field with id or label '#{locator}' found"
locate(XPath.file_field(locator)).set(path)
end
def body
@ -106,7 +99,7 @@ module Capybara
def within(kind, scope=nil)
kind, scope = Capybara.default_selector, kind unless scope
scope = XPath.from_css(scope) if kind == :css
raise Capybara::ElementNotFound, "scope '#{scope}' not found on page" unless wait_for(scope)
locate(scope, "scope '#{scope}' not found on page")
scopes.push(scope)
yield
scopes.pop
@ -129,25 +122,29 @@ module Capybara
Capybara::SaveAndOpenPage.save_and_open_page(body)
end
def wait_for(locator)
wait_until { find(locator) }
#return node identified by locator or raise ElementNotFound(using desc)
def locate(locator, fail_msg = nil)
fail_msg ||= "Unable to locate '#{locator}'"
node = nil
begin
if driver.wait?
node = wait_until { find(locator) }
else
node = find(locator)
end
rescue Capybara::TimeoutError; end
raise Capybara::ElementNotFound, fail_msg unless node
node
end
def wait_for_condition(script)
wait_until { evaluate_script(script) }
def wait_until(timeout = Capybara.default_wait_time)
WaitUntil.timeout(timeout) { yield }
end
def wait_until
return yield unless driver.wait?
10.times do
if result = yield
return result
end
sleep(0.1)
end
nil
end
def evaluate_script(script)
driver.evaluate_script(script)
end

View File

@ -1,23 +1,25 @@
module WaitForSpec
shared_examples_for "wait_for" do
describe '#wait_for' do
module LocateSpec
shared_examples_for "locate" do
describe '#locate' 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'
@session.locate('//h1').text.should == 'This is a test'
@session.locate("//input[@id='test_field']")[:value].should == 'monkey'
end
it "should return nil when nothing was found" do
@session.wait_for('//div[@id="nosuchthing"]').should be_nil
it "should raise ElementNotFound with specified fail message if nothing was found" do
running do
@session.locate('//div[@id="nosuchthing"]', 'arghh').should be_nil
end.should raise_error(Capybara::ElementNotFound, "arghh")
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'
@session.locate(@xpath).value.should == 'John Smith'
end
context "within a scope" do
@ -27,7 +29,7 @@ module WaitForSpec
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/
@session.locate('//li').text.should =~ /With Simple HTML/
end
end
end

View File

@ -39,7 +39,7 @@ shared_examples_for "session" do
it_should_behave_like "has_xpath"
it_should_behave_like "select"
it_should_behave_like "uncheck"
it_should_behave_like "wait_for"
it_should_behave_like "locate"
it_should_behave_like "within"
it_should_behave_like "current_url"
end

View File

@ -10,17 +10,24 @@ shared_examples_for "session with javascript support" do
end
end
describe '#wait_for' do
describe '#locate' 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 == '#'
@session.locate("//a[contains(.,'Has been clicked')]")[:href].should == '#'
end
end
describe '#wait_until' do
before do
@default_timeout = Capybara.default_wait_time
end
it "should wait for block to return true" do
after do
Capybara.default_wait_time = @default_wait_time
end
it "should wait for block to return true" do
@session.visit('/with_js')
@session.select('My Waiting Option', :from => 'waiter')
@session.evaluate_script('activeRequests == 1').should be_true
@ -30,21 +37,31 @@ shared_examples_for "session with javascript support" do
@session.evaluate_script('activeRequests == 0').should be_true
end
it "should return false if block doesn't return true within timeout" do
it "should raise Capybara::TimeoutError if block doesn't return true within timeout" do
@session.visit('/with_html')
@session.wait_until { false }.should be_nil
Proc.new do
@session.wait_until(0.1) do
@session.find('//div[@id="nosuchthing"]')
end
end.should raise_error(::Capybara::TimeoutError)
end
it "should accept custom timeout in seconds" do
start = Time.now
Capybara.default_wait_time = 5
begin
@session.wait_until(0.1) { false }
rescue Capybara::TimeoutError; end
(Time.now - start).should be_close(0.1, 0.1)
end
end
describe '#wait_for_condition' do
it "should wait for condition to be true" do
@session.visit('/with_js')
@session.select('My Waiting Option', :from => 'waiter')
@session.evaluate_script('activeRequests == 1').should be_true
@session.wait_for_condition('activeRequests == 0').should be_true
@session.evaluate_script('activeRequests == 0').should be_true
it "should default to Capybara.default_wait_time before timeout" do
start = Time.now
Capybara.default_wait_time = 0.2
begin
@session.wait_until { false }
rescue Capybara::TimeoutError; end
(Time.now - start).should be_close(0.2, 0.1)
end
end

View File

@ -12,18 +12,4 @@ shared_examples_for "session without javascript support" do
end
end
describe '#wait_until' do
it "should not wait for asynchronous load" do
@session.visit('/with_html')
before_time = Time.new
@session.wait_until do
@session.find('//div[@id="nosuchthing"]')
end.should be_nil
(Time.now - before_time).should be < 2
end
end
end