Skip to content

Commit

Permalink
Merge pull request #1851 from emanlove/print-page-as-pdf-1824
Browse files Browse the repository at this point in the history
Added `Print Page As PDF` Keyword
  • Loading branch information
emanlove authored May 14, 2024
2 parents 1a12a4d + e9061cc commit 3ea3041
Show file tree
Hide file tree
Showing 3 changed files with 127 additions and 2 deletions.
25 changes: 25 additions & 0 deletions atest/acceptance/keywords/print_page.robot
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
*** Settings ***
Documentation Suite description
Suite Setup Go To Page "non_ascii.html"
Resource ../resource.robot
Test Setup Remove Files ${OUTPUTDIR}/selenium-page-*.pdf
*** Test Cases ***
Print Page As PDF Without Print Options
Print Page As PDF
Verify Index Increments With Multiple Prints
[Setup] Remove Files ${OUTPUTDIR}/selenium-page-*.pdf
${file_1} = Print Page As PDF background=${True} scale=${2}
Should Be Equal ${file_1} ${OUTPUTDIR}${/}selenium-page-1.pdf
${file_2} = Print Page As PDF orientation=landscape
Should Be Equal ${file_2} ${OUTPUTDIR}${/}selenium-page-2.pdf
Go To https://robotframework.org/foundation/
${file_3} = Print Page As PDF shrink_to_fit=${True} page_height=${35.56} page_width=${21.59}
Should Be Equal ${file_3} ${OUTPUTDIR}${/}selenium-page-3.pdf
Print With Full Options
Print Page As PDF page_ranges=['1'] background=${False} shrink_to_fit=${False} orientation=portrait
... margin_top=${0.5} margin_left=${1.5} margin_bottom=${0.5} margin_right=${1.5}
... page_height=${35.56} page_width=${21.59}
102 changes: 101 additions & 1 deletion src/SeleniumLibrary/keywords/screenshot.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,20 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import os
from typing import Union
from typing import Optional, Union
from base64 import b64decode

from robot.utils import get_link_path
from selenium.webdriver.remote.webelement import WebElement
from selenium.webdriver.common.print_page_options import PrintOptions, Orientation

from SeleniumLibrary.base import LibraryComponent, keyword
from SeleniumLibrary.utils.path_formatter import _format_path

DEFAULT_FILENAME_PAGE = "selenium-screenshot-{index}.png"
DEFAULT_FILENAME_ELEMENT = "selenium-element-screenshot-{index}.png"
EMBED = "EMBED"
DEFAULT_FILENAME_PDF = "selenium-page-{index}.pdf"


class ScreenshotKeywords(LibraryComponent):
Expand Down Expand Up @@ -235,3 +238,100 @@ def _embed_to_log_as_file(self, path, width):
f'<a href="{src}"><img src="{src}" width="{width}px"></a>',
html=True,
)

@keyword
def print_page_as_pdf(self,
filename: str = DEFAULT_FILENAME_PDF,
background: Optional[bool] = None,
margin_bottom: Optional[float] = None,
margin_left: Optional[float] = None,
margin_right: Optional[float] = None,
margin_top: Optional[float] = None,
orientation: Optional[Orientation] = None,
page_height: Optional[float] = None,
page_ranges: Optional[list] = None,
page_width: Optional[float] = None,
scale: Optional[float] = None,
shrink_to_fit: Optional[bool] = None,
# path_to_file=None,
):
""" Print the current page as a PDF
``page_ranges`` defaults to `['-']` or "all" pages. ``page_ranges`` takes a list of
strings indicating the ranges.
The page size defaults to 21.59 for ``page_width`` and 27.94 for ``page_height``.
This is the equivalent size of US-Letter. The assumed units on these parameters
is centimeters.
The default margin for top, left, bottom, right is `1`. The assumed units on
these parameters is centimeters.
The default ``orientation`` is `portrait`. ``orientation`` can be either `portrait`
or `landscape`.
The default ``scale`` is `1`. ``scale`` must be greater than or equal to `0.1` and
less than or equal to `2`.
``background`` and ``scale_to_fit`` can be either `${True}` or `${False}`..
If all print options are None then a pdf will fail to print silently.
"""

if page_ranges is None:
page_ranges = ['-']

print_options = PrintOptions()
if background is not None:
print_options.background = background
if margin_bottom is not None:
print_options.margin_bottom = margin_bottom
if margin_left is not None:
print_options.margin_left = margin_left
if margin_right is not None:
print_options.margin_right = margin_right
if margin_top is not None:
print_options.margin_top = margin_top
if orientation is not None:
print_options.orientation = orientation
if page_height is not None:
print_options.page_height = page_height
if page_ranges is not None:
print_options.page_ranges = page_ranges
if page_width is not None:
print_options.page_width = page_width
if scale is not None:
print_options.scale = scale
if shrink_to_fit is not None:
print_options.shrink_to_fit = shrink_to_fit

if not self.drivers.current:
self.info("Cannot print page to pdf because no browser is open.")
return
return self._print_page_as_pdf_to_file(filename, print_options)

def _print_page_as_pdf_to_file(self, filename, options):
path = self._get_pdf_path(filename)
self._create_directory(path)
pdfdata = self.driver.print_page(options)
if not pdfdata:
raise RuntimeError(f"Failed to print page.")
self._save_pdf_to_file(pdfdata, path)
return path

def _save_pdf_to_file(self, pdfbase64, path):
pdfdata = b64decode(pdfbase64)
with open(path, mode='wb') as pdf:
pdf.write(pdfdata)

def _get_pdf_path(self, filename):
directory = self.log_dir
filename = filename.replace("/", os.sep)
index = 0
while True:
index += 1
formatted = _format_path(filename, index)
path = os.path.join(directory, formatted)
# filename didn't contain {index} or unique path was found
if formatted == filename or not os.path.exists(path):
return path
2 changes: 1 addition & 1 deletion utest/test/api/test_plugins.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ def setUpClass(cls):
def test_no_libraries(self):
for item in [None, "None", ""]:
sl = SeleniumLibrary(plugins=item)
self.assertEqual(len(sl.get_keyword_names()), 181)
self.assertEqual(len(sl.get_keyword_names()), 182)

def test_parse_library(self):
plugin = "path.to.MyLibrary"
Expand Down

0 comments on commit 3ea3041

Please sign in to comment.