Skip to content
This repository has been archived by the owner on Mar 3, 2020. It is now read-only.

Accept or Decline Javascript Confirmation #84

Closed
NickClark opened this issue Jun 21, 2011 · 23 comments
Closed

Accept or Decline Javascript Confirmation #84

NickClark opened this issue Jun 21, 2011 · 23 comments

Comments

@NickClark
Copy link

It would be nice if there was a way to accept or deny confirmation or alert dialogs. For instance, in Rails, the default way to delete something is to hide the action as a JS call behind a link. This method requires the user to also accept a deletion confirmation dialog to actually execute the action.

Currently I have to fallback to selenium for those scenarios. This is done using the following code:

page.driver.browser.switch_to.alert.deny
#or
page.driver.browser.switch_to.alert.accept

It's also possible that capybara-webkit does this already, I just couldn't find it documented anywhere and my quick scan through the code didn't reveal such functionality.

@sobrinho
Copy link

maybe stubbing javascript would help:

page.execute_script 'window.confirm = function () { return true }'

I didn't tested, I guess this should work

@jc00ke
Copy link
Contributor

jc00ke commented Jun 29, 2011

def handle_js_confirm(accept=true)
  page.evaluate_script "window.original_confirm_function = window.confirm"
  page.evaluate_script "window.confirm = function(msg) { return #{!!accept}; }"
  yield
  page.evaluate_script "window.confirm = window.original_confirm_function"
end

I had seen something like this around & I use it w/capybara-webkit in a few projects.

@metaskills
Copy link

That's awesome, works for me too. I just changed it slightly to use ensure to make sure the function is always replaced, even if the context of the block raises and error.

def handle_js_confirm(accept=true)
  page.evaluate_script "window.original_confirm_function = window.confirm"
  page.evaluate_script "window.confirm = function(msg) { return #{!!accept}; }"
  yield
ensure
  page.evaluate_script "window.confirm = window.original_confirm_function"
end

@jc00ke
Copy link
Contributor

jc00ke commented Jul 25, 2011

@metaskills good idea, will have to use ensure in the future.

@NickClark
Copy link
Author

Thanks. This works fine. Although I wish I didn't have to wrap steps with this. Maybe in the future we'll have a way to access any dialogs that do popup in capybara-webkit; something like what can be done in selenium.

@pisaruk
Copy link

pisaruk commented Sep 8, 2011

Thanks for sharing these solutions.

@cibernox
Copy link

Awesome hack! Now i can say goodbye to selenium every time I want to test something a delete action

@leesmith
Copy link

What if you want to test for content inside the confirmation dialog (like how selenium provides dialog.text)? Any ideas on how that would work? Thanks in advance.

@niklasb
Copy link
Contributor

niklasb commented Jan 23, 2012

@leesmith: You could try something like this:

def handle_js_confirm(accept=true)
  page.execute_script "window.original_confirm_function = window.confirm"
  page.execute_script "window.confirmMsg = null"
  page.execute_script "window.confirm = function(msg) { window.confirmMsg = msg; return #{!!accept}; }"
  yield
ensure
  page.execute_script "window.confirm = window.original_confirm_function"
end

def get_confirm_text
  page.evaluate_script "window.confirmMsg"
end

Within the block, you can then call get_confirm_text to get the message passed to the confirm function.

@leesmith
Copy link

@niklasb Thank you very much...I'll give that a shot.

@brendon
Copy link

brendon commented Feb 16, 2012

Has there been any movement on this? Where would be the best place to put these methods? I was just getting empty strings for the text confirmMsg value.

@jc00ke
Copy link
Contributor

jc00ke commented Feb 16, 2012

@brendon
Copy link

brendon commented Feb 17, 2012

Lol just saw this in Ruby Weekly, very handy :) Thanks for the heads up :)

On Fri, Feb 17, 2012 at 5:21 AM, Jesse Cooke <
reply@reply.github.com

wrote:

Checkout https://github.com/ExtractMethod/prickle


Reply to this email directly or view it on GitHub:

#84 (comment)

@brendon
Copy link

brendon commented Feb 20, 2012

Prickle just make a nice wrapper for the selenium approach, so no go in
this situation.

On Fri, Feb 17, 2012 at 2:54 PM, Brendon Muir brendon@spike.net.nz wrote:

Lol just saw this in Ruby Weekly, very handy :) Thanks for the heads up :)

On Fri, Feb 17, 2012 at 5:21 AM, Jesse Cooke <
reply@reply.github.com

wrote:

Checkout https://github.com/ExtractMethod/prickle


Reply to this email directly or view it on GitHub:

#84 (comment)

@shakerlxxv
Copy link

@niklasb : I like your solution. I've applied in a cucumber step defined as:

  When /^(.*) and (\S*) popup(?: containing "([^"]*)")?$/ do |step,confirm_dismiss,text|
    handle_js_confirm(confirm_dismiss == "confirm") do
      When step
      if text
        _text = get_confirm_text
        if _text.respond_to? :should
          _text.should =~ /#{text}/
        else
          assert_match(/#{text}/,_text)
        end
      end
    end
  end

Which would be pretty cool using steps like:

    When I follow "Delete" and confirm popup containing "Are you sure"

However, I've got two problems:

  • Seems like the action is always being take regardless of whether I use true or false for accept.
  • And get_confirm_text is returning nothing

Does anyone have this approach working?

@niklasb
Copy link
Contributor

niklasb commented Feb 23, 2012

@shakerlxxv: Sorry, I don't see why this isn't working right now. You should do some JS debugging to figure out why it doesn't :) Maybe set it to a value different from null and try if get_confirm_text returns that value afterwards.

@shakerlxxv
Copy link

@niklasb Yup. I had the same thought, if I set confirmMsg='hello' then get_confirm_text returns 'hello'.

@niklasb
Copy link
Contributor

niklasb commented Feb 23, 2012

@shakerlxxv: But the replaced confirm function doesn't change the value? That's strange.

@thoughtless
Copy link

@shakerlxxv I know this is probably way too late to help you, but in case anyone else has the same problem and finds this (like I did), make sure you are using confirm('whatever'); and not alert('whatever');. If you want to capture alert messages, the above code won't work.

@mcbsys
Copy link

mcbsys commented Jun 12, 2015

Just came across a "gotcha" with this webkit method after upgrading to Rails 4.2.1: it silently succeeds even if no confirmation popup is displayed.

Rails 4 requires that the :confirm message be created in a :data hash in order to display the popup:

http://stackoverflow.com/a/19588187/550712

so my code wasn't working but the tests were succeeding.

Is there a way to get the webkit to fail if no popup is present? For now I've switched back to Selenium, which displays "Selenium::WebDriver::Error::NoAlertPresentError:" if the popup is missing.

@nritholtz
Copy link
Contributor

@mcbsys, you might be interested in b411f53. You can call an accept_confirm with a block for the action that should prompt the confirmation window.

If the confirmation window doesn't appear, it raises a Capybara::ModalNotFound.

@mcbsys
Copy link

mcbsys commented Jun 12, 2015

@nritholtz Awesome, thanks very much for that tip!
page.accept_confirm { click_link "Delete" } works well.

@nritholtz
Copy link
Contributor

No problem. For future reference, all methods related to modal dialogs are documented in Capybara's README.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests