【问题标题】:chromedriver headless alertschromedriver 无头警报
【发布时间】:2023-11-05 20:52:01
【问题描述】:

我在使用 chromedriver 进行 selenium webdriver 测试时遇到了这个问题。虽然我在使用 Chrome 浏览器时可以成功运行测试,但我无法在无头模式下运行相同的测试。

我无法处理 Js 警报。实际上在截屏时似乎甚至不会弹出警报。

Alert screenshot

我尝试了几种解决方法:

1) driver.window_handles --> 似乎没有其他窗口存在

2) driver.execute_script("window.confirm = function(){return true;}") --> 脚本没有改变

3) element = WebDriverWait(driver, 20).until(EC.alert_is_present()) 当然还有明确的等待

在浏览器模式下,我使用纯文本:

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

还有其他人在无头模式下遇到此问题吗?

  • chromedriver v.2.30.477691
  • Chrome 版本 59.0.3071.115

【问题讨论】:

    标签: selenium-webdriver selenium-chromedriver google-chrome-headless


    【解决方案1】:

    在 Chrome 61 中仍然存在这个问题,所以我花了一段时间寻找不同的解决方案。由于它的简单性,我最喜欢的是在显示警报之前注入 javascript,以便自动接受警报。

    只需将以下代码行放在导致显示警报的行之前:

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

    适用于 headless chrome 和 PhantomJS。

    【讨论】:

    • BEFORE 至关重要。所以大家把这行放在element.click() 之前,只是为了添加python do driver.execute_script("window.confirm = function(){return true;}");
    • 大家好,我有同样的情况,在无头模式下,无法识别弹出窗口。试图遵循上面的代码。但是使用“ExecuteJavaScript”会出错。难道我做错了什么?它是用户定义的函数吗?如果这正是我需要编写的代码。
    • 如果我这样跟随,我是否正确,((JavascriptExecutor) driver).executeScript("window.confirm = function(){return true;}");
    • 它应该完全像上面那样工作(使用 selenium 和 C#)。您第二条评论中的代码对我来说没有任何意义。也许您在某处缺少参考或使用?
    • 我遇到了这个问题,使用 NightwatchJS 稍作修改,这对我有用(在这种情况下 this.api 与 browser.perform() 相同): this.api.perform(function ( ) { this.confirm = function () { return true; }})
    【解决方案2】:

    运行 headless chrome 时似乎遇到了同样的问题。 警报窗口不会根据屏幕截图弹出。它在 chrome 上运行良好,但在无头 chrome 上运行良好。

    我在 chrome 60.0.3112.72 上运行 和 chrome 驱动程序 2.30

    因为 headless chrome 会自动丢弃警报。 检查这个: https://bugs.chromium.org/p/chromium/issues/detail?id=718235


    顺便说一句,你怎么能在无头模式下在 chrome 59 中截屏? chrome 59 有一个 bug,在 headless 模式下,每个屏幕截图都是 1x1 像素的图像,所以我升级到了 chrome 60。

    【讨论】:

    • 我不知道,但这对我有用.. driver.save_screenshot("ss.png") 但让我们继续讨论
    【解决方案3】:

    由于 Chrome 无头(当前)不支持警报,因此您必须对 alert()confirm() 方法进行猴子补丁。这是我使用的方法(在 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.");
        }
    

    我是这样使用的:

            Driver.SetupAlert(true);
            this.ClickElement(ResetButton);
            Driver.WaitForAlert();
    

    【讨论】:

      【解决方案4】:

      只是想添加这个,以防有人使用 NightwatchJS 遇到这个问题。

      上面接受的解决方案对我有用,但使用 JS 需要稍微修改

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

      我需要把它改成

      // this.api.perform() in my case is the same as browser.perform() 
      this.api.perform(function () { this.confirm = function () { return true; }})
      

      【讨论】: