Repository: robocorp/rpaframework

Issue:
`RPA.Browser.Selenium` can't print PDF pages with Chrome
Put a breakpoint in the `Print To PDF` keyword and here's the internal result error we get when printing any page:
```
{'error': 'unknown error', 'message': 'unknown error: unhandled inspector error: {"code":-32000,"message":"Printing is not available"}\n
```
which of course isn't b64 decodable and results into another user-facing error:
```
Traceback (most recent call last):
  File "/Users/cmin/Repos/rpaframework/packages/main/.venv/lib/python3.9/site-packages/SeleniumLibrary/__init__.py", line 492, in run_keyword
    return DynamicCore.run_keyword(self, name, args, kwargs)
  File "/Users/cmin/Repos/rpaframework/packages/main/.venv/lib/python3.9/site-packages/robotlibcore.py", line 94, in run_keyword
    return self.keywords[name](*args, **(kwargs or {}))
  File "/Users/cmin/Repos/rpaframework/packages/main/src/RPA/Browser/Selenium.py", line 1979, in print_to_pdf
    pdf = base64.b64decode(result["data"])
TypeError: string indices must be integers
```


Discussion:

Resolving patch:
diff --git a/packages/main/src/RPA/Browser/Selenium.py b/packages/main/src/RPA/Browser/Selenium.py
--- a/packages/main/src/RPA/Browser/Selenium.py
+++ b/packages/main/src/RPA/Browser/Selenium.py
@@ -1938,26 +1938,28 @@ def clear_all_highlights(self):
         self.driver.execute_script(script, *elements)
 
     @keyword
-    def print_to_pdf(self, output_path: str = None, params: dict = None):
-        """
-        Print the current page to a PDF document using Chromium devtools.
+    def print_to_pdf(
+        self, output_path: Optional[str] = None, params: Optional[dict] = None
+    ) -> str:
+        """Print the current page to a PDF document using Chrome/Chromium DevTools.
 
+        Attention: This works in ``headless`` mode only!
         For supported parameters see:
         https://chromedevtools.github.io/devtools-protocol/tot/Page/#method-printToPDF
-
-        ``output_path`` filepath for the generated pdf. By default it is saved to
-          the output folder with name `out.pdf`.
-
-        ``params`` parameters for the Chrome print method. By default uses values:
-
-        ``{
-            "landscape": False,
-            "displayHeaderFooter": False,
-            "printBackground": True,
-            "preferCSSPageSize": True,
-        }``
+        Returns the output PDF file path.
+
+        :param output_path: File path for the generated PDF document. By default, it is
+            saved to the output folder with the name `out.pdf`.
+        :param params: Parameters for the browser printing method. By default, it uses
+            the following values:
+            ``{
+                "landscape": False,
+                "displayHeaderFooter": False,
+                "printBackground": True,
+                "preferCSSPageSize": True,
+            }``
         """
-        if "chrom" not in self.driver.name:
+        if not self.driver.name.lower().startswith("chrom"):
             raise NotImplementedError("PDF printing works only with Chrome/Chromium")
 
         default_params = {
@@ -1966,20 +1968,20 @@ def print_to_pdf(self, output_path: str = None, params: dict = None):
             "printBackground": True,
             "preferCSSPageSize": True,
         }
+        params = params or default_params
+        result = self._send_command_and_get_result("Page.printToPDF", params)
+        if isinstance(result, str) and "Printing is not available" in result:
+            raise TypeError("PDF printing works in headless mode only")
 
         try:
             output_dir = BuiltIn().get_variable_value("${OUTPUT_DIR}", "output")
         except robot.libraries.BuiltIn.RobotNotRunningError:
             output_dir = "output"
-        default_output = f"{output_dir}/out.pdf"
+        default_output = str(Path(output_dir) / "out.pdf")
         output_path = output_path or default_output
-
-        params = params or default_params
-        result = self._send_command_and_get_result("Page.printToPDF", params)
-        pdf = base64.b64decode(result["data"])
-
-        with open(output_path, "wb") as f:
-            f.write(pdf)
+        pdf_data = base64.b64decode(result["data"])
+        with open(output_path, "wb") as stream:
+            stream.write(pdf_data)
 
         return output_path
 


Test patch: