如何处理 Selenium 中的打印对话框?

Posted

技术标签:

【中文标题】如何处理 Selenium 中的打印对话框?【英文标题】:How to handle print dialog in Selenium? 【发布时间】:2012-07-17 05:40:33 【问题描述】:

我必须处理打印对话框(与在浏览器中单击 ctrl-p 时出现的相同)。我试过了:

Alert printDialog = driver.switchTo().alert();
printDialog.dismiss();

但它没有用。我也抓不到它的窗口句柄,因为它不是一个窗口......

是否可以处理这些对象以及如何处理?

【问题讨论】:

您能解释一下为什么需要这个吗?特别是,如何以及为什么触发打印对话框?通常在测试期间触发打印是没有意义的。 (我知道这个问题很老,但它仍然相关,我也许可以贡献)。 我正在开发的电子商务应用程序有一个案例,您完成交易并自动打开打印对话框(对于需要完成他人交易的店员来说就是这种情况) 啊,谢谢。所以我想该应用程序以某种方式在javascript中自动调用window.print()?我会尝试为那个案例写一个答案。 【参考方案1】:

很遗憾,WebDriver 无法处理这些(或任何其他浏览器或操作系统对话框)。此外,它们在浏览器/系统/语言设置中往往看起来不同,因此可能没有明确的答案。您需要检测并处理所有可能的情况,以使其在任何地方都能正常工作。您的选择包括:

Robot 类,它允许您以编程方式“按”键盘上的任何内容(或盲目单击),从而摆脱对话框,例如按 Enter Esc。但是,如上所述,任何高级交互都依赖于操作系统/语言/打印机。

// press Escape programatically - the print dialog must have focus, obviously
Robot r = new Robot();
r.keyPress(KeyEvent.VK_ESCAPE);
r.keyRelease(KeyEvent.VK_ESCAPE);

AutoIt。它是一个 Windows 程序,可用于处理任何系统级自动化。与上述相同的依赖关系。

差不多就是这样。如果可以避免打印对话框,请尝试截取页面并打印using standard Java tools。

【讨论】:

Robot 实际上可以很好地满足我的需要。我想我不能使用“等到”来确保对话框真的出现了? @zorglub76 不,我不知道有什么办法。如果你有什么想法,我会很高兴听到的! 静态变量VK_ESCAPE报错,通过导入import java.awt.event.KeyEvent;即可解决 Robot 类可能不起作用,因为 WebDriver 打开的浏览器窗口通常没有(窗口)焦点。在这种情况下,打印对话框也没有焦点,因此机器人模拟的按键没有到达它。您可以先尝试聚焦窗口(例如使用 Javascript),但这意味着如果某些事情改变了窗口焦点,您的测试可能会失败。【参考方案2】:

在 Chrome 中使用 Selenium 处理一个 CAN 处理打印对话框。不确定其他浏览器。

在 ChromeDriver-2.17 中添加了“访问打印”对话框。详细信息可以在这里找到: https://bugs.chromium.org/p/chromedriver/issues/detail?id=1087

右键单击打印对话框 -> 检查元素。因此,打印对话框的 DOM 将在单独的窗口中打开。现在您可以为对话框中的任何元素生成定位器并在测试中使用它们。

要关闭“打印”对话框,可以执行以下操作:

//Switch to Print dialog
Set<String> windowHandles = driver.getWindowHandles();
if (!windowHandles.isEmpty()) 
    driver.switchTo().window((String) windowHandles.toArray()[windowHandles.size() - 1]);

//Now work with the dialog as with an ordinary page:  
driver.findElement(By.className("cancel")).click();

【讨论】:

如果选择“ok”,打印出来的pdf会出现在哪里? 我假设,您的意思是“打印”按钮(至少在 Chrome 中,打印弹出窗口上没有确定按钮)。如果您单击“打印”按钮,打印的 PDF 的目的地将由弹出窗口的目的地字段中的值定义。这可以是硬件或 PDF 打印机(如 Foxit Reader PDF 打印机)。我 链接中提到,window.print()需要从setTimeout调用,包括如果被页面本身调用,否则会阻塞进一步处理。例如。如果页面上的按钮触发打印,则使用setTimeout(() =&gt; window.print(), 0) 另外,打印对话框现在使用 shadow dom,所以 findElement 不起作用,但是使用 sendKeysESCAPEENTER 是一个简单的解决方法(在切换到对话框的窗口之后句柄)。 XPATH 不起作用【参考方案3】:

我可以通过添加完全绕过打印对话框的--kiosk-printing 来解决此问题。我将默认打印设置为 pdf,所以我的下载文件夹中最终有一个 pdf,但至少 selenium 不会挂起。代码如下所示:

        ChromeOptions cOptions = new ChromeOptions();
        cOptions.addArguments("kiosk-printing");
        RemoteWebDriver driver = new RemoteWebDriver(hostUrl, cOptions);

【讨论】:

另见***.com/questions/47007720/…。【参考方案4】:

Slanec 的回答是正确的 - WebDriver 对此没有本机功能。我在 Windows 中解决这个问题的方法是使用 System.Windows.Forms.SendKeys 对象:

    SendKeys.SendWait("^p");
    System.Threading.Thread.Sleep(500);
    SendKeys.SendWait("~");

    // give it a minute to spool onto the printer
    System.Threading.Thread.Sleep(5000);

我实际上已经在一个循环中打印了一堆语句。像魅力一样工作。

【讨论】:

【参考方案5】:

您可以在打印对话框出现后简单地关闭浏览器。诚然,这是一个有点过激的措施,但优点是:

很简单 它不需要任何外部工具 它适用于操作系统和浏览器

只要打电话:

myWebDriver.quit();

通常,您会运行测试,并像往常一样检查要打印的页面上的元素。即使打印对话框打开,WebDriver 也可以检查页面元素。

完成后,退出浏览器(并为下一次测试启动一个新浏览器)。


我们已经在一个项目中成功地使用了它。为了让事情变得更简单,我们编写了一个跟踪“当前 WebDriver 实例”的包装类。我有方法来检索这个实例(根据需要创建一个)并关闭它。这样,您始终可以调用getCurrentWebDriver() 并获得一个有效的实例(重用或新创建的)。

【讨论】:

这感觉有点矫枉过正。 @Kermit_ice_tea:正如我所说,它有点激烈,但具有实际工作的优势 - 并且跨平台,并且没有其他工具。如果您有其他解决方案,请随时发布答案:-)。 "即使打印对话框打开,WebDriver 也可以检查页面元素。"这是我需要的部分。【参考方案6】:

另一种选择是编辑 Windows 注册表以供 Chrome 禁用打印窗口。

--disable-print-preview - 告诉 Chrome 禁用打印预览的标志

    进入注册表编辑器 导航到“计算机\HKEY_CLASSES_ROOT\ChromeBhtml\shell\open\command” 设置值为: "C:\Program Files (x86)\Google\Chrome Beta\Application\chrome.exe" --disable-print-preview

此解决方案适用于我的具体情况。

【讨论】:

【参考方案7】:

将 Selenium 和 Facebook WebDriver 与 Codeception 结合使用时,我遇到了同样的问题 - 测试场景将停止运行,因为打印对话框阻止了与页面的任何交互。

我最终没有在test 环境中打开打印对话框(使用 Symfony 和 Twig 的示例):

# Selenium can't interact with the OS native print dialog. #
# Therefore, it's disabled in the test environment. #
% if app.environment != 'test' %
    $(document).ready(function () 
        var orderShouldBePrinted = window.location.href.indexOf(
            'print=true'
        ) !== -1;

        if (orderShouldBePrinted) 
            window.print();
        
    );
% endif %

这样做的好处是不会停止测试。但是,它不允许测试打印对话框是否实际出现。

作为冒烟测试,我添加了$I-&gt;seeInCurrentUrl('print=true');(因为这个URL参数触发了window.print())。

【讨论】:

【参考方案8】:

我试图从一个不允许“全部打印”的网站上的模式列表中打印 100 多页。所以理论上硒会自动帮助我解决这个问题。 我想出了一个完全非正统的打印对话窗口解决方案。

##Python code
import time
import threading
from pynput.mouse import Button, Controller
mouse = Controller()

##selenium starting up website stuff here

def website_print_button():
    browser.find_element_by_id('printButton').click()

def push():
    time.sleep(4)    #4 second delay to give the computer time to open print dialog
    mouse.position = [1131, 733] #where my print button is located
    mouse.click(Button.left, 1)

def letsgo():

    for x in range(printing_amount):
        browser.find_element_by_xpath('/html/body/div[1]/form/table[4]/tbody/tr['+str(x+1)+']/td[1]/a/b').click()
        browser.find_element_by_css_selector('ul.light-green.button').click()
        browser.switch_to.window(browser.window_handles[1])
        t2 = threading.Thread(target=push)
        t2.start()
        t1 = threading.Thread(target=website_print_button)
        t1.start()
        time.sleep(5)
        browser.close()
        browser.switch_to.window(browser.window_handles[0])
        browser.find_element_by_class_name('c').click()

当打印对话框窗口打开时,Selenium 通常会卡住等待发生的事情。我使用了我最近学到的一种叫做“线程”的东西,这让我在技术上可以同时做两件事。我会要求在 4 秒内单击以启动(推送功能),然后立即,Selenium 将单击网站打印按钮。当 Selenium 打开打印对话框窗口时,它卡住了等待,但延迟点击仍在运行,并在硒打开打印窗口 4 秒后等待点击。然后单击将执行,并且 selenium 重新获得控制权,因为打印窗口已被处理。

【讨论】:

以上是关于如何处理 Selenium 中的打印对话框?的主要内容,如果未能解决你的问题,请参考以下文章

C#的webform中的button弹出确认对话框,该如何处理

如何处理C#的HttpWebResponse的GetResponse中的超时异常

如何处理后台线程上显示的 LWUIT 对话框

进度对话框和后台线程处于活动状态时如何处理屏幕方向更改?

进度对话框和后台线程处于活动状态时如何处理屏幕方向更改?

如何处理 Android 运行时权限中的“不再询问”复选框?