Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I handle an alert with GhostDriver via Python?

Problem: The GhostDriver API does not yet support alert handling. There is an acceptable workaround for the time being, which is to inject your own javascript into the page that will handle the alert and store it's text for you.

I'm having trouble using this workaround via the python webdriver bindings. It might be related to my novice level understanding of javascript.

Here is an example of the workaround I am trying to utilize: https://github.com/detro/ghostdriver/issues/20#issuecomment-15641983

I'm using a public site that demonstrates an alert to make this more straightforward: http://www.tizag.com/javascriptT/javascriptalert.php

Here is my code:

from selenium import webdriver

button_xpath = "/html/body/table[3]/tbody/tr/td[2]/table/tbody/tr/td/div[4]/form/input"

js = """
(function () {
var lastAlert = undefined;
window.alert = function (message) {
    lastAlert = message;
};
window.getLastAlert = function () {
    var result = lastAlert;
    lastAlert = undefined;
    return result;
};
}());
"""

driver = webdriver.PhantomJS()
driver.get('http://www.tizag.com/javascriptT/javascriptalert.php')
driver.execute_script("window.alert = %s" % js)
driver.find_element_by_xpath(button_xpath).click()
#exception just occured
driver.execute_script("return window.getLastAlert && window.getLastAlert();")

The exception is:

WebDriverException: Message: u'Error Message => \'Click failed: TypeError: \'undefined\' is not a function (evaluating \'alert(\'Are you sure you want to give us the deed to your house?\')\')\'\n caused by Request => {"headers":{"Accept":"application/json","Accept-Encoding":"identity","Connection":"close","Content-Length":"81","Content-Type":"application/json;charset=UTF-8","Host":"127.0.0.1:41752","User-Agent":"Python-urllib/2.7"},"httpVersion":"1.1","method":"POST","post":"{\\"sessionId\\": \\"0eaf7680-9897-11e2-b375-55b9cb6ceb0f\\", \\"id\\": \\":wdc:1364578560610\\"}","url":"/click","urlParsed":{"anchor":"","query":"","file":"click","directory":"/","path":"/click","relative":"/click","port":"","host":"","password":"","user":"","userInfo":"","authority":"","protocol":"","source":"/click","queryKey":{},"chunks":["click"]},"urlOriginal":"/session/0eaf7680-9897-11e2-b375-55b9cb6ceb0f/element/%3Awdc%3A1364578560610/click"}' ; Screenshot: available via screen 

I'm a JS noob. I'm hoping somebody can point me in the right direction.

like image 304
brma Avatar asked Mar 29 '13 17:03

brma


2 Answers

A simple solution is to rewrite the window.alert method to output the argument to a global variable.

Define the js injection variable with your override function:

js = """
window.alert = function(message) {
lastAlert = message;
}
"""

And then just pass the js variable through the execute_script call in python like this:

driver.execute_script("%s" % js)

Then when it's all been run you can execute a return on the global lastAlert:

driver.execute_script("return lastAlert")
like image 75
alexss3 Avatar answered Nov 04 '22 10:11

alexss3


This is some workaround.

Use this for every reloaded page that would have an alert later.

driver.execute_script("window.confirm = function(){return true;}");

This works for PhantomJS within Selenium/Splinter.

See more reference here.

like image 44
Yuxiang Avatar answered Nov 04 '22 10:11

Yuxiang