Skip to content

Commit

Permalink
Add modal API
Browse files Browse the repository at this point in the history
  • Loading branch information
mikepack committed Apr 24, 2014
1 parent 59f751f commit 505c0ce
Show file tree
Hide file tree
Showing 14 changed files with 296 additions and 1 deletion.
38 changes: 38 additions & 0 deletions README.md
Expand Up @@ -482,6 +482,44 @@ that this may break with more complicated expressions:
result = page.evaluate_script('4 + 4');
```

### Modals

In drivers which support it, you can accept, dismiss and respond to alerts, confirms and prompts.

You can accept or dismiss alert messages by wrapping the code that produces an alert in a block:

```ruby
accept_alert do
click_link('Show Alert')
end
```

You can accept or dismiss a confirmation by wrapping it in a block, as well:

```ruby
dismiss_confirm do
click_link('Show Confirm')
end
```

You can accept or dismiss prompts as well. Additionally, you can respond to a prompt:

```ruby
respond_to_prompt 'Linus Torvalds' do
click_link('Show Prompt About Linux')
end
```

All modal methods return the message that was presented. So, you can access the prompt message
by assigning the return to a variable:

```ruby
message = respond_to_prompt 'Linus Torvalds' do
click_link('Show Prompt About Linux')
end
expect(message).to eq('Who is the chief architect of Linux?')
```

### Debugging

It can be useful to take a snapshot of the page as it currently is and take a
Expand Down
8 changes: 8 additions & 0 deletions lib/capybara/driver/base.rb
Expand Up @@ -55,6 +55,14 @@ def within_window(handle)
raise Capybara::NotSupportedByDriverError, 'Capybara::Driver::Base#within_window'
end

def accept_modal(type, options={}, &blk)
raise Capybara::NotSupportedByDriverError, 'Capybara::Driver::Base#accept_modal'
end

def dismiss_modal(type, &blk)
raise Capybara::NotSupportedByDriverError, 'Capybara::Driver::Base#dismiss_modal'
end

def invalid_element_errors
[]
end
Expand Down
21 changes: 21 additions & 0 deletions lib/capybara/selenium/driver.rb
Expand Up @@ -146,6 +146,21 @@ def within_window(selector, &blk)
browser.switch_to.window(handle, &blk)
end

def accept_modal(type, options={}, &blk)
yield
modal.send_keys options[:response] if options[:response]
message = modal.text
modal.accept
message
end

def dismiss_modal(type, &blk)
yield
message = modal.text
modal.dismiss
message
end

def quit
@browser.quit if @browser
rescue Errno::ECONNREFUSED
Expand All @@ -158,4 +173,10 @@ def invalid_element_errors
[Selenium::WebDriver::Error::StaleElementReferenceError, Selenium::WebDriver::Error::UnhandledError, Selenium::WebDriver::Error::ElementNotVisibleError]
end

private

def modal
@browser.switch_to.alert
end

end
56 changes: 55 additions & 1 deletion lib/capybara/session.rb
Expand Up @@ -45,7 +45,11 @@ class Session
:save_and_open_screenshot, :reset_session!, :response_headers,
:status_code, :title, :has_title?, :has_no_title?, :current_scope
]
DSL_METHODS = NODE_METHODS + SESSION_METHODS
MODAL_METHODS = [
:accept_alert, :accept_confirm, :dismiss_confirm, :accept_prompt,
:dismiss_prompt, :respond_to_prompt
]
DSL_METHODS = NODE_METHODS + SESSION_METHODS + MODAL_METHODS

attr_reader :mode, :app, :server
attr_accessor :synchronized
Expand Down Expand Up @@ -367,6 +371,56 @@ def evaluate_script(script)
driver.evaluate_script(script)
end

##
#
# Execute the block, accepting a alert.
#
def accept_alert(&blk)
driver.accept_modal(:alert, &blk)
end

##
#
# Execute the block, accepting a confirm.
#
def accept_confirm(&blk)
driver.accept_modal(:confirm, &blk)
end

##
#
# Execute the block, dismissing a confirm.
#
def dismiss_confirm(&blk)
driver.dismiss_modal(:confirm, &blk)
end

##
#
# Execute the block, accepting a prompt.
#
def accept_prompt(&blk)
driver.accept_modal(:prompt, &blk)
end

##
#
# Execute the block, dismissing a prompt.
#
def dismiss_prompt(&blk)
driver.dismiss_modal(:prompt, &blk)
end

##
#
# Execute the block, responding with the provided value.
#
# @param [String] response Response to provide to the prompt
#
def respond_to_prompt(response, &blk)
driver.accept_modal(:prompt, {response: response}, &blk)
end

##
#
# Save a snapshot of the page.
Expand Down
26 changes: 26 additions & 0 deletions lib/capybara/spec/public/test.js
Expand Up @@ -67,4 +67,30 @@ $(function() {
e.preventDefault();
$(this).after('<a id="has-been-right-clicked" href="#">Has been right clicked</a>');
});
$('#open-alert').click(function() {
alert('Alert opened');
$(this).attr('opened', 'true');
});
$('#open-delayed-alert').click(function() {
var link = this;
setTimeout(function() {
alert('Delayed alert opened');
$(link).attr('opened', 'true');
}, 250);
});
$('#open-confirm').click(function() {
if(confirm('Confirm opened')) {
$(this).attr('confirmed', 'true');
} else {
$(this).attr('confirmed', 'false');
}
});
$('#open-prompt').click(function() {
var response = prompt('Prompt opened');
if(response === null) {
$(this).attr('response', 'dismissed');
} else {
$(this).attr('response', response);
}
});
});
35 changes: 35 additions & 0 deletions lib/capybara/spec/session/accept_alert_spec.rb
@@ -0,0 +1,35 @@
Capybara::SpecHelper.spec '#accept_alert', :requires => [:modals] do
before do
@session.visit('/with_js')
end

it "should accept the alert" do
@session.accept_alert do
@session.click_link('Open alert')
end
expect(@session).to have_xpath("//a[@id='open-alert' and @opened='true']")
end

it "should return the message presented" do
message = @session.accept_alert do
@session.click_link('Open alert')
end
expect(message).to eq('Alert opened')
end

context "with an asynchronous alert" do
it "should accept the alert" do
@session.accept_alert do
@session.click_link('Open delayed alert')
end
expect(@session).to have_xpath("//a[@id='open-delayed-alert' and @opened='true']")
end

it "should return the message presented" do
message = @session.accept_alert do
@session.click_link('Open delayed alert')
end
expect(message).to eq('Delayed alert opened')
end
end
end
19 changes: 19 additions & 0 deletions lib/capybara/spec/session/accept_confirm_spec.rb
@@ -0,0 +1,19 @@
Capybara::SpecHelper.spec '#accept_confirm', :requires => [:modals] do
before do
@session.visit('/with_js')
end

it "should accept the confirm" do
@session.accept_confirm do
@session.click_link('Open confirm')
end
expect(@session).to have_xpath("//a[@id='open-confirm' and @confirmed='true']")
end

it "should return the message presented" do
message = @session.accept_confirm do
@session.click_link('Open confirm')
end
expect(message).to eq('Confirm opened')
end
end
19 changes: 19 additions & 0 deletions lib/capybara/spec/session/accept_prompt_spec.rb
@@ -0,0 +1,19 @@
Capybara::SpecHelper.spec '#accept_prompt', :requires => [:modals] do
before do
@session.visit('/with_js')
end

it "should accept the prompt with no message" do
@session.accept_prompt do
@session.click_link('Open prompt')
end
expect(@session).to have_xpath("//a[@id='open-prompt' and @response='']")
end

it "should return the message presented" do
message = @session.accept_prompt do
@session.click_link('Open prompt')
end
expect(message).to eq('Prompt opened')
end
end
19 changes: 19 additions & 0 deletions lib/capybara/spec/session/dismiss_confirm_spec.rb
@@ -0,0 +1,19 @@
Capybara::SpecHelper.spec '#dismiss_confirm', :requires => [:modals] do
before do
@session.visit('/with_js')
end

it "should dismiss the confirm" do
@session.dismiss_confirm do
@session.click_link('Open confirm')
end
expect(@session).to have_xpath("//a[@id='open-confirm' and @confirmed='false']")
end

it "should return the message presented" do
message = @session.dismiss_confirm do
@session.click_link('Open confirm')
end
expect(message).to eq('Confirm opened')
end
end
19 changes: 19 additions & 0 deletions lib/capybara/spec/session/dismiss_prompt_spec.rb
@@ -0,0 +1,19 @@
Capybara::SpecHelper.spec '#dismiss_prompt', :requires => [:modals] do
before do
@session.visit('/with_js')
end

it "should dismiss the prompt" do
@session.dismiss_prompt do
@session.click_link('Open prompt')
end
expect(@session).to have_xpath("//a[@id='open-prompt' and @response='dismissed']")
end

it "should return the message presented" do
message = @session.dismiss_prompt do
@session.click_link('Open prompt')
end
expect(message).to eq('Prompt opened')
end
end
19 changes: 19 additions & 0 deletions lib/capybara/spec/session/respond_to_prompt_spec.rb
@@ -0,0 +1,19 @@
Capybara::SpecHelper.spec '#respond_to_prompt', :requires => [:modals] do
before do
@session.visit('/with_js')
end

it "should accept the prompt" do
@session.respond_to_prompt 'the response' do
@session.click_link('Open prompt')
end
expect(@session).to have_xpath("//a[@id='open-prompt' and @response='the response']")
end

it "should return the message presented" do
message = @session.respond_to_prompt 'the response' do
@session.click_link('Open prompt')
end
expect(message).to eq('Prompt opened')
end
end
16 changes: 16 additions & 0 deletions lib/capybara/spec/views/with_js.erb
Expand Up @@ -72,6 +72,22 @@

<p id="click-test">Click me</p>

<p>
<a href="#" id="open-alert">Open alert</a>
</p>

<p>
<a href="#" id="open-delayed-alert">Open delayed alert</a>
</p>

<p>
<a href="#" id="open-confirm">Open confirm</a>
</p>

<p>
<a href="#" id="open-prompt">Open prompt</a>
</p>

<script type="text/javascript">
// a javascript comment
var aVar = 123;
Expand Down
1 change: 1 addition & 0 deletions spec/dsl_spec.rb
Expand Up @@ -7,6 +7,7 @@ class TestClass

Capybara::SpecHelper.run_specs TestClass.new, "DSL", :capybara_skip => [
:js,
:modals,
:screenshot,
:frames,
:windows,
Expand Down
1 change: 1 addition & 0 deletions spec/rack_test_spec.rb
Expand Up @@ -6,6 +6,7 @@ module TestSessions

Capybara::SpecHelper.run_specs TestSessions::RackTest, "RackTest", :capybara_skip => [
:js,
:modals,
:screenshot,
:frames,
:windows,
Expand Down

0 comments on commit 505c0ce

Please sign in to comment.