35

I have to handle print dialog (the same one that appears when clicking ctrl-p in browser). I tried with:

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

but it didn't work. Also I couldn't catch its window handle, because it's not a window...

Is it possible to handle these objects and how?

zorglub76
  • 4,852
  • 7
  • 37
  • 46
  • Could you explain why you need this? In particular, how and why is the print dialog triggered? Usually there's no point in triggering printing during a test. (I know this question is old, but it's still relevant, and I might be able to contribute). – sleske Aug 21 '15 at 15:39
  • The e-commerce application I was working on had one case in which you finish transaction and automatically get print dialog opened (that's the case for shop assistants who need to finish someone else's transactions) – zorglub76 Aug 21 '15 at 17:27
  • Ah, thanks. So I suppose the app somehow automatically called `window.print()` in Javascript? I'll try to write an answer for that case. – sleske Aug 22 '15 at 12:39

8 Answers8

27

Unfortunately, WebDriver can't handle these (or any other browser or OS dialog). Moreover, they tend to look differently across browsers / systems / language settings, so there's probably no definite answer. You'll need to detect and handle every possible case in order to make it work everywhere. Your options include:

  • The Robot class, it allows you to "press" programatically anything on the keyboard (or clicking blindly) and therefore getting rid of the dialog by, say, pressing Enter or Esc. However, as told above, any advanced interaction is dependant on OS / language / printer.

    // 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. It's a Windows program useful for handling any system-level automation. Same dependancy as above.

That's more or less it. If you can avoid the print dialog, try to take screenshot of the page and print it using standard Java tools.

Petr Janeček
  • 37,768
  • 12
  • 121
  • 145
  • Robot actually worked pretty fine for what I needed. I guess I can't use "wait until" to be sure that the dialog really appeared? – zorglub76 Jul 18 '12 at 13:20
  • @zorglub76 No, I don't know about a way to do it. If you come up with something, I'll be glad to hear t! – Petr Janeček Jul 18 '12 at 13:37
  • The Robot class may not work, as browser windows opened by WebDriver will usually not have (window) focus. In that case, the print dialog does not have focus either, so the keypress simulated by Robot does not reach it. You could try focusing the window first (e.g. using Javascript), but that means that your tests may fail if something changes the window focus. – sleske Aug 21 '15 at 14:06
  • I got error in static variable `VK_ESCAPE`, which was solved by simply importing `import java.awt.event.KeyEvent;` – zishan paya May 06 '15 at 15:06
14

One CAN handle Print dialog with Selenium in Chrome. Not sure about other browsers.

Access to Print dialog was added in ChromeDriver-2.17. Details can be found here: https://bugs.chromium.org/p/chromedriver/issues/detail?id=1087

Right-click on Print dialog -> Inspect Element. As a result, the DOM of Print dialog will open in a separate window. Now you can produce locators for any element on the dialog and use them in your tests.

To close the Print dialog one can do the following:

//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();
Iryna
  • 161
  • 1
  • 5
  • If "ok" is selected where will the printed pdf appear? – N-ate Aug 03 '18 at 17:45
  • I assume, you meant "Print" button (there is no Ok button on Print popup at least in Chrome). If you click on "Print" button, destination of the printed PDF will be defined by value in Destination field on the popup. This can be either hardware or PDF printer (like Foxit Reader PDF printer). I – Iryna Aug 15 '18 at 12:38
  • As mentioned in the link, `window.print()` needs to be called from setTimeout, including if called by the page itself, otherwise it blocks further processing. E.g. if a button on the page triggers printing, then use `setTimeout(() => window.print(), 0)`. – DS. Oct 09 '20 at 21:44
  • 1
    Also, the print dialog uses shadow dom now, so `findElement` does not work, but using `sendKeys` with `ESCAPE` or `ENTER` is an easy workaround (after switching to the dialog's window handle). – DS. Oct 09 '20 at 21:45
  • XPATH does not work – eastwater Jan 07 '22 at 20:36
  • @DS. I tried to sendKeys ESCAPE to the body element of print dialog after waiting for 5 seconds, it did not work. – eastwater Jan 07 '22 at 21:50
  • Maybe try sending the key globally rather than to a particular element? To be honest, I ended up never using this because I couldn't get it to work in headless mode, and that was a requirement. – DS. Jan 08 '22 at 23:17
6

I was able to resolve this issue by adding --kiosk-printing which bypasses the print dialog completely. I have my default print set to pdf, so I end up with a pdf in my Downloads folder, but at least selenium doesn't hang. Here's what the code looks like:

        ChromeOptions cOptions = new ChromeOptions();
        cOptions.addArguments("kiosk-printing");
        RemoteWebDriver driver = new RemoteWebDriver(hostUrl, cOptions);
Zeki
  • 5,107
  • 1
  • 20
  • 27
  • See also https://stackoverflow.com/questions/47007720/set-selenium-chromedriver-userpreferences-to-save-as-pdf. – jsf80238 Jul 26 '20 at 13:45
2

Slanec's answer is correct - WebDriver doesn't have native capability for this. The way I solved this in Windows is with the System.Windows.Forms.SendKeys object:

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

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

I've actually got this in a loop printing off a bunch of statements. Works like a charm.

Chris B. Behrens
  • 6,255
  • 8
  • 45
  • 71
2

You can simply close the browser after the print dialog has appeared. This is admittedly a somewhat drastic measure, but the advantages are:

  • it is simple
  • it does not require any external tools
  • it works across OSes and browsers

Just call:

myWebDriver.quit();

Typically, you would run your test, and check elements on the page to be printed as usual. WebDriver can check page elements even if the print dialog is open.

Once you are done, quit the browser (and fire up a new one for the next test).


We have used this successfully on a project. To make things easier, we wrote a wrapper class that keeps track of a "current WebDriver instance". I has methods to retrieve this instance (creating one as required) and to close it. That way, you can always call getCurrentWebDriver() and get a valid instance (reused or freshly created).

sleske
  • 81,358
  • 34
  • 189
  • 227
  • This feels like an overkill. – Kermit_ice_tea Nov 11 '16 at 20:24
  • @Kermit_ice_tea: As I said, it is a bit drastic, but has the advantage of actually working - and that cross-platform, and without other tools. If you have another solution, feel free to post an answer :-). – sleske Nov 11 '16 at 21:25
  • "WebDriver can check page elements even if the print dialog is open." This is the part that I need for my purposes. – Code-Apprentice Mar 02 '20 at 23:21
1

Another option could be to edit Windows registry for Chrome to disable print window.

--disable-print-preview - flag that will tell Chrome to disable print preview

  1. Go to Registry Editor
  2. Navigate to "Computer\HKEY_CLASSES_ROOT\ChromeBHTML\shell\open\command"
  3. Set value to be: "C:\Program Files (x86)\Google\Chrome Beta\Application\chrome.exe" --disable-print-preview

This solution worked for my specific case.

Taras
  • 93
  • 7
0

Using Selenium and Facebook WebDriver with Codeception, I had the same problem – the test scenario would stop running because the print dialog prevented any interaction with the page.

I ended up not opening the print dialog in the test environment (example using Symfony and 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 %}

This has the advantage of not stopping the test. However, it doesn't allow testing that the print dialog actually appears.

As a smoke test, I added $I->seeInCurrentUrl('print=true'); (because this URL parameter triggers window.print()).

Yngve Høiseth
  • 570
  • 6
  • 26
-1

I was trying to print 100+ pages from a patterned list on a website that did not allow for a 'print-all'. So selenium would help me with this automatically in theory. I came up with a completely unorthodox solution to the print dialog window.

##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 would usually get stuck waiting for something to happen when the print dialog window opened up. I used something I recently learned called 'Threading' and this allowed me to do two things at once technically. I would call for a click to initiate in 4 seconds (push function) and then immediately after, Selenium would click on the websites print button. When Selenium opened up the print dialog window, it became stuck waiting around, but the delayed click was still running and waiting to click after 4 seconds of selenium opening the print window. Then the click would execute, and selenium retook control because the print window was taken care of.