0

My Selenium test looks something like this: customer selects a financial product, fills some necessary data and is presented with terms / agreement document in print preview (as required by local law). After printing / closing the print preview dialog customer enters more data and proceeds further, selects some options and finally gets another print preview of the contract. After that he confirms contract and process is done. I run my tests against Chrome version 75.

So far I've tried two things: 1. Switching to the print preview using Selenium, navigating to the "Cancel" button trough DOM and clicking it. But because the dialog uses shadow DOM it's very ugly, hard to maintain and frequently breaks after Chrome updates. 2. Tried using Robot class from awt, it works well when running locally but fails when running on Selenium grid because Chrome window is not focused and does not receive keyboard events.

Current state of the method handling the closure of print dialog:

    public void closePrintPreview() {
        WebDriverWait wait = new WebDriverWait(driver, 5);
        wait.until(driver -> driver.getWindowHandles().size() > 1);
        driver.switchTo().window(driver.getWindowHandles().toArray()[1].toString());

        wait.until(d -> {
            if (d.getWindowHandles().size() > 1) {
                d.switchTo().window(driver.getWindowHandles().toArray()[1].toString());
                try {
                    Robot robot = new Robot();
                    robot.keyPress(KeyEvent.VK_ESCAPE);
                    robot.keyRelease(KeyEvent.VK_ESCAPE);
                } catch (AWTException e) {
                    throw new RuntimeException(e);
                }
                return false;
            }
            return true;
        });

        driver.switchTo().window(driver.getWindowHandles().toArray()[0].toString());
    }

So my question would be if there is a simpler way to get the "Cancel" button in print print preview or maybe some way to force the Chrome window to be focused so it can receive key events from Robot?

Sig
  • 123
  • 11

2 Answers2

1

Here is the solution in python.

You can update the same to work in java.

Python:

def cancelPrintPreview():
    # get the current time and add 180 seconds to wait for the print preview cancel button
    endTime = time.time() + 180
    # switch to print preview window
    driver.switch_to.window(driver.window_handles[-1])
    while True:
        try:
            # get the cancel button
            cancelButton = driver.execute_script(
                "return document.querySelector('print-preview-app').shadowRoot.querySelector('#sidebar').shadowRoot.querySelector('print-preview-header#header').shadowRoot.querySelector('paper-button.cancel-button')")
            if cancelButton:
                # click on cancel
                cancelButton.click()
                # switch back to main window
                driver.switch_to.window(driver.window_handles[0])
                return True
        except:
            pass
        time.sleep(1)
        if time.time() > endTime:
            driver.switch_to.window(driver.window_handles[0])
            break

Java:

  public void closePrintPreview() {
        String jsCancel = "return document.querySelector('print-preview-app')" +
                ".shadowRoot.querySelector('#sidebar')" +
                ".shadowRoot.querySelector('print-preview-header#header')" +
                ".shadowRoot.querySelector('paper-button.cancel-button')";
        WebDriverWait wait = new WebDriverWait(driver, 5);
        JavascriptExecutor jse = (JavascriptExecutor) driver;
        WebElement cancelButton;

        wait.until(driver -> driver.getWindowHandles().size() > 1);
        driver.switchTo().window(driver.getWindowHandles().toArray(new String[0])[1]);

        while (driver.getWindowHandles().size() > 1) {
            driver.switchTo().window(driver.getWindowHandles().toArray(new String[0])[1]);
            cancelButton = (WebElement) jse.executeScript(jsCancel);
            cancelButton.click();
        }

        driver.switchTo().window(driver.getWindowHandles().toArray(new String[0])[0]);
    }

You can check my answer here for more information on working with shadow-root elements.

supputuri
  • 13,644
  • 2
  • 21
  • 39
  • Thank you! This allowed me to cut the clutter when getting button from shadow DOM and is quite stable when running test. – Sig Jun 20 '19 at 05:40
  • Glad we are helpful. Can you please share the java code that you used. So that I can update the answer with java option, too. That might help the future visitors. – supputuri Jun 20 '19 at 12:23
  • Thanks Sig, for contributing the Java converted method. – supputuri Jun 20 '19 at 17:46
0

Here is the Java implementation based on answer by @supputuri:

  public void closePrintPreview() {
        String jsCancel = "return document.querySelector('print-preview-app')" +
                ".shadowRoot.querySelector('#sidebar')" +
                ".shadowRoot.querySelector('print-preview-header#header')" +
                ".shadowRoot.querySelector('paper-button.cancel-button')";
        WebDriverWait wait = new WebDriverWait(driver, 5);
        JavascriptExecutor jse = (JavascriptExecutor) driver;
        WebElement cancelButton;

        wait.until(driver -> driver.getWindowHandles().size() > 1);
        driver.switchTo().window(driver.getWindowHandles().toArray(new String[0])[1]);

        while (driver.getWindowHandles().size() > 1) {
            driver.switchTo().window(driver.getWindowHandles().toArray(new String[0])[1]);
            cancelButton = (WebElement) jse.executeScript(jsCancel);
            cancelButton.click();
        }

        driver.switchTo().window(driver.getWindowHandles().toArray(new String[0])[0]);
    }
Sig
  • 123
  • 11