11import base64
22import functools
33import io
4+ import json
45import logging
56import multiprocessing
67import os
@@ -230,6 +231,31 @@ def set_screen_resolution(self, width=None, height=None):
230231 """ , width , height )
231232 self ._driver .set_window_size (* window_size )
232233
234+ def _webdriver_command (self , command , params = None , req_type = "POST" ):
235+ """
236+ Execute a webdriver command.
237+
238+ Args:
239+ command (str): The command URL after the session part
240+ params (dict): The payload to be serialized and sent to the webdriver. Defaults to None.
241+ req_type (str, optional): The type of request to be made. Defaults to "POST".
242+
243+ Returns:
244+ str: The value of the response
245+ """
246+ if not params :
247+ params = {}
248+
249+ resource = f"/session/{ self .driver .session_id } /{ command } "
250+ url = self .driver .command_executor ._url + resource
251+ body = json .dumps (params )
252+ response = self .driver .command_executor ._request (req_type , url , body )
253+
254+ if not response :
255+ raise Exception (response .get ('value' ))
256+
257+ return response .get ('value' )
258+
233259 ##########
234260 # Display
235261 ##########
@@ -747,7 +773,6 @@ def create_tab(self, url):
747773 self .navigate_to (url )
748774
749775 def create_window (self , url ):
750-
751776 try :
752777 # Refactor this when Selenium 4 is released
753778 self .execute_javascript (f"window.open('{ url } ', '_blank', 'location=0');" )
@@ -769,10 +794,47 @@ def close_page(self):
769794 def activate_tab (self , handle ):
770795 self ._driver .switch_to .window (handle )
771796
797+ def print_pdf (self , path = None , print_options = None ):
798+ """Print the current page as a PDF file.
799+
800+ Args:
801+ path (str, optional): The path for the file to be saved. Defaults to None.
802+ print_options (dict, optional): Print options as defined at. Defaults to None.
803+
804+ Returns:
805+ str: the saved file path
806+ """
807+ title = self .page_title () or "document"
808+ default_path = os .path .expanduser (os .path .join ("~" , "Desktop" , f"{ title } .pdf" ))
809+
810+ if self .browser in [Browser .CHROME , Browser .EDGE ] and not self .headless :
811+ # Chrome still does not support headless webdriver print
812+ # but Firefox does.
813+ self .execute_javascript ("window.print();" )
814+ # We need to wait for the file to be available in this case.
815+ self .wait_for_file (default_path )
816+ return default_path
817+
818+ if print_options is None :
819+ print_options = {
820+ 'landscape' : False ,
821+ 'displayHeaderFooter' : False ,
822+ 'printBackground' : True ,
823+ 'preferCSSPageSize' : True ,
824+ 'marginTop' : 0 ,
825+ 'marginBottom' : 0
826+ }
827+ data = self ._webdriver_command ("print" , print_options )
828+ bytes_file = base64 .b64decode (data )
829+ if not path :
830+ path = default_path
831+ with open (path , "wb" ) as f :
832+ f .write (bytes_file )
833+ return path
834+
772835 #######
773836 # Mouse
774837 #######
775-
776838 @only_if_element
777839 def click_on (self , label ):
778840 """
@@ -1491,14 +1553,14 @@ def sleep(self, interval):
14911553 """
14921554 self .wait (interval )
14931555
1494- def wait_for_file (self , path , timeout = 10000 ):
1556+ def wait_for_file (self , path , timeout = 60000 ):
14951557 """
1496- Invoke the system handler to open the given file .
1558+ Wait for a file to be available on disk .
14971559
14981560 Args:
14991561 path (str): The path for the file to be executed
15001562 timeout (int, optional): Maximum wait time (ms) to search for a hit.
1501- Defaults to 10000ms (10s ).
1563+ Defaults to 60000ms (60s ).
15021564
15031565 Returns:
15041566 status (bool): Whether or not the file was available before the timeout
0 commit comments