javascriptpythonseleniumwebdriverghostdriver

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.


Solution

  • 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")