How can I test a rails 4 confirm dialog with Capybara and Poltergeist?
Asked Answered
Q

6

22

I'm trying to test that a link to a destroy action throws a native browser confirm box with the correct message.

The link is being generated using rails' link_to:

link_to 'Delete', user_path, method: :delete, data: { confirm: "Are you sure?" }

And generates the following html:

<a data-confirm="Are you sure?" data-method="delete" href="/users/6" rel="nofollow">Delete</a>

The functionality is working correctly in the browser, but I want to test for it in my rspec feature spec.

I'm trying to stub out the browser's confirm function as described here and in this gist, however I can't get it to work.

it 'requests confirmation', js: true do
  visit user_path(user)
  page.execute_script "
    window.confirmMsg = null;
    window.confirm = function(msg) { window.confirmMsg = msg; return true; };"
  click_link 'Delete'
  expect(page.evaluate_script('window.confirmMsg')).to eq('Are you sure?')
end

Gives the following error from rspec:

Failure/Error: expect(page.evaluate_script('window.confirmMsg')).to eq('Are you sure?')

       expected: "Are you sure?"
            got: nil

       (compared using ==)

However, if I call a confirm directly via page.execute_script:

it 'requests confirmation', js: true do
  visit user_path(user)
  page.execute_script "
    window.confirmMsg = null;
    window.confirm = function(msg) { window.confirmMsg = msg; return true; };
    window.confirm('Are you sure?');"
  expect(page.evaluate_script('window.confirmMsg')).to eq('Are you sure?')
end

Then the test passes.

Also clicking the Delete link will cause the test to fail, even if confirm has been called directly for page.execute_script:

it 'requests confirmation', js: true do
  visit user_path(user)
  page.execute_script "
    window.confirmMsg = null;
    window.confirm = function(msg) { window.confirmMsg = msg; return true; };
    window.confirm('Are you sure?');"
  click_link 'Delete'
  expect(page.evaluate_script('window.confirmMsg')).to eq('Are you sure?')
end

Gives the same error from rspec:

Failure/Error: expect(page.evaluate_script('window.confirmMsg')).to eq('Are you sure?')

       expected: "Are you sure?"
            got: nil

       (compared using ==)

Why is the test failing? And, how can I test confirm dialogues correctly?


Context:

I'm running my tests from a Vagrant virtual machine, which is Ubuntu 12.04.4 LTS and running ruby 2.1.2p95.

My Gemfile.lock shows that I have the following versions:

rails (4.1.4)
poltergeist (1.5.1)
capybara (2.4.1)
Quorum answered 13/8, 2014 at 17:40 Comment(0)
S
33

page.driver.browser.accept_js_confirms is deprecated. Instead use

page.accept_confirm do
  click_link 'Delete'
end
Spurrier answered 19/1, 2016 at 22:45 Comment(1)
Documentation: github.com/teamcapybara/capybara#modals, which includes examples for accept_alert, dismiss_confirm, accept_prompt.Guthrie
K
7

Unfortunately, you cannot do this, because Poltergeist does work only in one window.

For that specific test you will need to use Selenium and this API:

page.driver.browser.switch_to.alert.accept

If you are concerned about wanting to run your tests headless, you can use Xvfb (X Virtual Framebuffer) like this:

Xvfb :1 -screen 0 1024x768x24+32

Alternatively you can also use capybara-webkit:

page.driver.browser.accept_js_confirms
page.driver.browser.reject_js_confirms

However, I have made the best experience using a mixture of (mostly) Poltergeist and Selenium where necessary.

Kenzie answered 13/8, 2014 at 17:50 Comment(1)
Thanks for taking the time to help. I'm not trying to accept the confirm, I'm trying to assert that it's thrown. This issue thread suggests that it should be possible: github.com/teampoltergeist/poltergeist/issues/… - but I can't seem to get it to work. Can you explain the significance of Poltegeist working in only one window? Why does the test I outlined work when I call window.confirm() directly from page.execute_script, but not when I click_link('Delete'). Thanks, Tom.Quorum
C
1

To expand on the above, when using Selenium you can test the actual text of the confirm dialog using the following:

    click_link 'Delete'
    a = page.driver.browser.switch_to.alert
    expect(a.text).to eq("Are you sure?")
    a.accept

Also, just found a good test for whether the alert is present here: selenium 2.4.0, how to check for presence of an alert I slightly modified it, put in my spec_helper file as:

def alert_present?
  begin
    page.driver.browser.switch_to.alert
    return true
  rescue
    return false
  end
end

And then in your test just do:

click_link 'Delete'
expect(alert_present?).to eq(true)
Concupiscent answered 18/5, 2015 at 4:35 Comment(0)
E
1

Given this Javascript:

confirm('You have unsaved changes, do you want to continue?')

For Poltergiest I found the following to work:

expect(page.driver.browser.modal_message).eq 'You have unsaved changes, do you want to contine?'

page.driver.browser.dismiss_confirm
page.driver.browser.accept_confirm
Engross answered 23/11, 2017 at 17:2 Comment(1)
When I run your code, I get NoMethodError Exception: undefined method 'modal_message' for #<Selenium::WebDriver::Firefox::Driver:.....Saransk
D
1

This is how I am doing in Rails 3.2 and capybara (~> 2.18.0)

context 'when `All listing` overlaps with listing 1' do
  it 'displays warning' do
    set_weekday_times('.show_window','10:00 AM', '02:00 PM', listing1.address)
    set_weekday_times('.show_window:last-child', '11:00 AM', '03:00 PM', 'All Listing')

    # button click event that triggers the confirm to appear
    submit_weekdays_form

    # Get the message in the confirm dialog
    confirm_text = page.driver.browser.switch_to.alert.text
    expect(confirm_text).to include('overlapping show windows on Sunday')
  end
end 
Dominickdominie answered 12/6, 2020 at 17:24 Comment(0)
B
0

It's tough to test JavaScript behavior. But if you want to check confirmation message, it might be okay to test link attribute only without Poltergeist:

it 'requests confirmation' do
  visit user_path(user)
  delete_link = find_link 'Delete', href: user_path(user)
  expect(delete_link['data-confirm']).to eq 'Are you sure?'
end

Here is the alternative:

it 'requests confirmation' do
  visit user_path(user)
  expect(page).to have_selector "a[data-confirm='Are you sure?'][href='#{user_path(user)}']", text: 'Delete'
end

This test cannot check if JS is working correctly, but it might be enough for the most of cases. (And fast!)

Baxie answered 11/6, 2015 at 22:42 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.