Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

chromedriver headless alerts

I have this issue with selenium webdriver tests with chromedriver. Although I can run tests succesfully when using Chrome browser I can't run the same tests in headless mode.

I cannot handle the Js alerts. Actually when taking a screenshot it seems that the alert won't even pop-up.

Alert screenshot

I have tried several workarounds:

1) driver.window_handles --> No other window seems to be present

2) driver.execute_script("window.confirm = function(){return true;}") --> Nothing changed with that script

3) element = WebDriverWait(driver, 20).until(EC.alert_is_present()) and of course an explicit wait

In browser mode I use a plain:

try:
    print driver.switch_to.alert.text
    driver.switch_to.alert.accept()
except NoAlertPresentException as e: 
    print("no alert")

Anyone else having this issue with alerts in headless mode?

  • chromedriver v.2.30.477691
  • Chrome Version 59.0.3071.115
like image 765
Alex Pas Avatar asked Jul 21 '17 16:07

Alex Pas


People also ask

What is Chromedriver headless?

The Headless mode is a feature which allows the execution of a full version of the Chrome Browser. It provides the ability to control Chrome via external programs. The headless mode can run on servers without the need for dedicated display or graphics.

What is difference between Chrome and Chrome headless?

Headless mode is a functionality that allows the execution of a full version of the latest Chrome browser while controlling it programmatically. It can be used on servers without dedicated graphics or display, meaning that it runs without its “head”, the Graphical User Interface (GUI).

How do I run a Chrome headless driver?

How to run Chrome in headless mode. In order to run your tests in headless mode, you will need to use the ChromeOptions as follows. ChromeOptions options = new ChromeOptions(); options. addArguments("--headless");

How do I run Chrome headless mode in Selenium?

You can run Google Chrome in headless mode simply by setting the headless property of the chromeOptions object to True. Or, you can use the add_argument() method of the chromeOptions object to add the –headless command-line argument to run Google Chrome in headless mode using the Selenium Chrome web driver.


3 Answers

Since Chrome headless doesn't (currently) support alerts, you have to monkeypatch the alert() and confirm() methods. This is the approach I've used (in C#):

    /// <summary>
    /// The Chrome Headless driver doesn't support alerts, so we need to override the window.alert method to get the expected behavior.
    /// </summary>
    /// <param name="driver">The active IWebDriver instance</param>
    /// <param name="result">The result that the alert should return, i.e., true if we want it "accepted", false if we don't</param>
    public static void SetupAlert(this IWebDriver driver, bool result)
    {
        // ks 7/27/17 - The Chrome Headless driver doesn't support alerts, so override the various window.alert methods to just set 
        const string scriptTemplate = @"
window.alertHandlerCalled = false;
window.alertMessage = null;
window.alert = window.confirm = function(str) {
    window.alertHandlerCalled = true;
    window.alertMessage = str;
    return {{result}};
};";

        var script = scriptTemplate.Replace("{{result}}", result.ToString().ToLower());
        var js = (IJavaScriptExecutor)driver;
        js.ExecuteScript(script);
    }

    /// <summary>
    /// This is an optional accompaniment to the <see cref="SetupAlert"/> method, which checks to see
    /// if the alert was, in fact, called. If you don't want to bother to check, don't worry about calling it.
    /// Note that this doesn't reset anything, so you need to call <see cref="SetupAlert"/> each time before calling
    /// this method.
    /// </summary>
    public static void WaitForAlert(this IWebDriver driver, TimeSpan? timeout = null)
    {
        const string script = @"return window.alertHandlerCalled";
        var js = (IJavaScriptExecutor)driver;
        var timeToBail = DateTime.Now.Add(timeout ?? TimeSpan.FromMilliseconds(500));
        while (DateTime.Now < timeToBail)
        {
            var result = (bool)js.ExecuteScript(script);
            if (result) return;
            Thread.Sleep(100);
        }
        throw new InvalidOperationException("The alert was not called.");
    }

I use it like this:

        Driver.SetupAlert(true);
        this.ClickElement(ResetButton);
        Driver.WaitForAlert();
like image 188
Ken Smith Avatar answered Oct 10 '22 06:10

Ken Smith


Still having this problem as of Chrome 61, so I spent a while looking for a different solution. My favorite because of it's simplicity is injecting javascript before the alert is shown in order to automatically accept the alert.

Just put the following line of code before the line that causes the alert to be shown:

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

Works with both headless chrome and PhantomJS.

like image 42
Ruben van Kruistum Avatar answered Oct 10 '22 06:10

Ruben van Kruistum


It seems that I have the same issue when running headless chrome. The alert window does not pop up base on the screen shots. It works fine on chrome but not headless chrome.

I am running on chrome 60.0.3112.72 and chrome driver 2.30

Because the headless chrome automatically discards alerts. check this: https://bugs.chromium.org/p/chromium/issues/detail?id=718235


BTW, how come you can screen shot in chrome 59 in headless mode? chrome 59 has a bug that makes every screen shot a 1x1 pixel image in headless mode, so I upgraded to chrome 60.

like image 29
Luyao Zhou Avatar answered Oct 10 '22 06:10

Luyao Zhou