Add adjustable wait time and text matching for modals

This commit is contained in:
Thomas Walpole 2014-06-03 12:18:14 -07:00
parent cda05a6206
commit 64b8ca62bd
6 changed files with 110 additions and 21 deletions

View File

@ -7,6 +7,7 @@ module Capybara
class DriverNotFoundError < CapybaraError; end
class FrozenInTime < CapybaraError; end
class ElementNotFound < CapybaraError; end
class ModalNotFound < CapybaraError; end
class Ambiguous < ElementNotFound; end
class ExpectationNotMet < ElementNotFound; end
class FileNotFound < CapybaraError; end

View File

@ -91,13 +91,26 @@ class Capybara::Selenium::Driver < Capybara::Driver::Base
def reset!
# Use instance variable directly so we avoid starting the browser just to reset the session
if @browser
begin @browser.manage.delete_all_cookies
rescue Selenium::WebDriver::Error::UnhandledError
# delete_all_cookies fails when we've previously gone
# to about:blank, so we rescue this error and do nothing
# instead.
begin
begin @browser.manage.delete_all_cookies
rescue Selenium::WebDriver::Error::UnhandledError
# delete_all_cookies fails when we've previously gone
# to about:blank, so we rescue this error and do nothing
# instead.
end
@browser.navigate.to("about:blank")
rescue Selenium::WebDriver::Error::UnhandledAlertError
# This error is thrown if an unhandled alert is on the page
# Firefox appears to automatically dismiss this alert, chrome does not
# We'll try to accept it
begin
@browser.switch_to.alert.accept
rescue Selenium::WebDriver::Error::NoAlertPresentError
# The alert is now gone - nothing to do
end
# try cleaning up the browser again
retry
end
@browser.navigate.to("about:blank")
end
end
@ -193,14 +206,16 @@ class Capybara::Selenium::Driver < Capybara::Driver::Base
def accept_modal(type, options={}, &blk)
yield
modal = find_modal(options)
modal.send_keys options[:response] if options[:response]
message = modal.text
modal.accept
message
end
def dismiss_modal(type, &blk)
def dismiss_modal(type, options={}, &blk)
yield
modal = find_modal(options)
message = modal.text
modal.dismiss
message
@ -236,8 +251,21 @@ class Capybara::Selenium::Driver < Capybara::Driver::Base
end
end
def modal
@browser.switch_to.alert
def find_modal(options={})
# Selenium has its own built in wait (2 seconds)for a modal to show up, so this wait is really the minimum time
# Actual wait time may be longer than specified
wait = Selenium::WebDriver::Wait.new(
timeout: (options[:wait] || Capybara.default_wait_time),
ignore: Selenium::WebDriver::Error::NoAlertPresentError)
begin
modal = wait.until do
alert = @browser.switch_to.alert
regexp = options[:text].is_a?(Regexp) ? options[:text] : Regexp.escape(options[:text].to_s)
alert.text.match(regexp) ? alert : nil
end
rescue Selenium::WebDriver::Error::TimeOutError
raise Capybara::ModalNotFound.new("Unable to find modal dialog#{" with #{options[:text]}" if options[:text]}")
end
end
end

View File

@ -531,40 +531,65 @@ module Capybara
#
# Execute the block, accepting a alert.
#
def accept_alert(&blk)
driver.accept_modal(:alert, &blk)
# @option options [Numeric] :wait How long to wait for the modal to appear after executing the block.
# @option options [String, Regexp] :text Text or regex to match against the text in the modal
# @return [String] the message shown in the modal
# @raise [Capybara::ModalNotFound] if modal dialog hasn't been found
#
def accept_alert(options={}, &blk)
driver.accept_modal(:alert, options, &blk)
end
##
#
# Execute the block, accepting a confirm.
#
def accept_confirm(&blk)
driver.accept_modal(:confirm, &blk)
# @option options [Numeric] :wait How long to wait for the modal to appear after executing the block.
# @option options [String, Regexp] :text Text or regex to match against the text in the modal
# @return [String] the message shown in the modal
# @raise [Capybara::ModalNotFound] if modal dialog hasn't been found
#
def accept_confirm(options={}, &blk)
driver.accept_modal(:confirm, options, &blk)
end
##
#
# Execute the block, dismissing a confirm.
#
def dismiss_confirm(&blk)
driver.dismiss_modal(:confirm, &blk)
# @option options [Numeric] :wait How long to wait for the modal to appear after executing the block.
# @option options [String, Regexp] :text Text or regex to match against the text in the modal
# @return [String] the message shown in the modal
# @raise [Capybara::ModalNotFound] if modal dialog hasn't been found
#
def dismiss_confirm(options={}, &blk)
driver.dismiss_modal(:confirm, options, &blk)
end
##
#
# Execute the block, accepting a prompt.
#
def accept_prompt(&blk)
driver.accept_modal(:prompt, &blk)
# @option options [Numeric] :wait How long to wait for the prompt to appear after executing the block.
# @option options [String, Regexp] :text Text or regex to match against the text in the prompt
# @return [String] the message shown in the modal
# @raise [Capybara::ModalNotFound] if modal dialog hasn't been found
#
def accept_prompt(options={}, &blk)
driver.accept_modal(:prompt, options, &blk)
end
##
#
# Execute the block, dismissing a prompt.
#
def dismiss_prompt(&blk)
driver.dismiss_modal(:prompt, &blk)
# @option options [Numeric] :wait How long to wait for the prompt to appear after executing the block.
# @option options [String, Regexp] :text Text or regex to match against the text in the prompt
# @return [String] the message shown in the modal
# @raise [Capybara::ModalNotFound] if modal dialog hasn't been found
#
def dismiss_prompt(options={}, &blk)
driver.dismiss_modal(:prompt, options, &blk)
end
##
@ -572,9 +597,13 @@ module Capybara
# Execute the block, responding with the provided value.
#
# @param [String] response Response to provide to the prompt
# @option options [Numeric] :wait How long to wait for the prompt to appear after executing the block.
# @option options [String, Regexp] :text Text or regex to match against the text in the prompt
# @return [String] the message shown in the modal
# @raise [Capybara::ModalNotFound] if modal dialog hasn't been found
#
def respond_to_prompt(response, &blk)
driver.accept_modal(:prompt, {response: response}, &blk)
def respond_to_prompt(response, options={}, &blk)
driver.accept_modal(:prompt, options.merge(response: response), &blk)
end
##

View File

@ -78,6 +78,13 @@ $(function() {
$(link).attr('opened', 'true');
}, 250);
});
$('#open-slow-alert').click(function() {
var link = this;
setTimeout(function() {
alert('Delayed alert opened');
$(link).attr('opened', 'true');
}, 3000);
});
$('#open-confirm').click(function() {
if(confirm('Confirm opened')) {
$(this).attr('confirmed', 'true');

View File

@ -9,6 +9,22 @@ Capybara::SpecHelper.spec '#accept_alert', :requires => [:modals] do
end
expect(@session).to have_xpath("//a[@id='open-alert' and @opened='true']")
end
it "should accept the alert if the text matches" do
@session.accept_alert(text: 'Alert opened') do
@session.click_link('Open alert')
end
expect(@session).to have_xpath("//a[@id='open-alert' and @opened='true']")
end
it "should not accept the alert if the text doesnt match" do
expect do
@session.accept_alert(text: 'Incorrect Text') do
@session.click_link('Open alert')
end
end.to raise_error(Capybara::ModalNotFound)
# @session.accept_alert {} # clear the alert so browser continues to function
end
it "should return the message presented" do
message = @session.accept_alert do
@ -31,5 +47,12 @@ Capybara::SpecHelper.spec '#accept_alert', :requires => [:modals] do
end
expect(message).to eq('Delayed alert opened')
end
it "should allow to adjust the delay" do
@session.accept_alert wait: 4 do
@session.click_link('Open slow alert')
end
expect(@session).to have_xpath("//a[@id='open-slow-alert' and @opened='true']")
end
end
end

View File

@ -78,6 +78,7 @@
<p>
<a href="#" id="open-delayed-alert">Open delayed alert</a>
<a href="#" id="open-slow-alert">Open slow alert</a>
</p>
<p>