diff --git a/src/SeleniumLibrary/__init__.py b/src/SeleniumLibrary/__init__.py index 0187df611..82ee75e5d 100644 --- a/src/SeleniumLibrary/__init__.py +++ b/src/SeleniumLibrary/__init__.py @@ -50,7 +50,7 @@ WebDriverCache, WindowKeywords, ) -from SeleniumLibrary.keywords.screenshot import EMBED +from SeleniumLibrary.keywords.screenshot import EMBED, BASE64 from SeleniumLibrary.locators import ElementFinder from SeleniumLibrary.utils import LibraryListener, is_truthy, _convert_timeout, _convert_delay @@ -614,8 +614,8 @@ def __init__( - ``run_on_failure``: Default action for the `run-on-failure functionality`. - ``screenshot_root_directory``: - Path to folder where possible screenshots are created or EMBED. - See `Set Screenshot Directory` keyword for further details about EMBED. + Path to folder where possible screenshots are created or EMBED or BASE64. + See `Set Screenshot Directory` keyword for further details about EMBED and BASE64. If not given, the directory where the log file is written is used. - ``plugins``: Allows extending the SeleniumLibrary with external Python classes. @@ -846,6 +846,8 @@ def _resolve_screenshot_root_directory(self): if is_string(screenshot_root_directory): if screenshot_root_directory.upper() == EMBED: self.screenshot_root_directory = EMBED + if screenshot_root_directory.upper() == BASE64: + self.screenshot_root_directory = BASE64 @staticmethod def _get_translation(language: Union[str, None]) -> Union[Path, None]: diff --git a/src/SeleniumLibrary/keywords/screenshot.py b/src/SeleniumLibrary/keywords/screenshot.py index 8cd8dc299..11308af85 100644 --- a/src/SeleniumLibrary/keywords/screenshot.py +++ b/src/SeleniumLibrary/keywords/screenshot.py @@ -27,6 +27,8 @@ DEFAULT_FILENAME_PAGE = "selenium-screenshot-{index}.png" DEFAULT_FILENAME_ELEMENT = "selenium-element-screenshot-{index}.png" EMBED = "EMBED" +BASE64 = "BASE64" +EMBEDDED_OPTIONS = [EMBED, BASE64] DEFAULT_FILENAME_PDF = "selenium-page-{index}.pdf" @@ -59,6 +61,8 @@ def set_screenshot_directory(self, path: Union[None, str]) -> str: path = None elif path.upper() == EMBED: path = EMBED + elif path.upper() == BASE64: + path = BASE64 else: path = os.path.abspath(path) self._create_directory(path) @@ -79,7 +83,14 @@ def capture_page_screenshot(self, filename: str = DEFAULT_FILENAME_PAGE) -> str: If ``filename`` equals to EMBED (case insensitive), then screenshot is embedded as Base64 image to the log.html. In this case file is not - created in the filesystem. + created in the filesystem. If ``filename`` equals to BASE64 (case + insensitive), then the base64 string is returned and the screenshot + is embedded to the log. This allows one to reuse the image elsewhere + in the report. + + Example: + | ${ss}= | `Capture Page Screenshot` | BASE64 | + | Set Test Message | *HTML*Test Success

| Starting from SeleniumLibrary 1.8, if ``filename`` contains marker ``{index}``, it will be automatically replaced with an unique running @@ -89,9 +100,10 @@ def capture_page_screenshot(self, filename: str = DEFAULT_FILENAME_PAGE) -> str: format string syntax]. An absolute path to the created screenshot file is returned or if - ``filename`` equals to EMBED, word `EMBED` is returned. + ``filename`` equals to EMBED, word `EMBED` is returned. If ``filename`` + equals to BASE64, the base64 string containing the screenshot is returned. - Support for EMBED is new in SeleniumLibrary 4.2 + Support for BASE64 is new in SeleniumLibrary 6.8 Examples: | `Capture Page Screenshot` | | @@ -111,8 +123,9 @@ def capture_page_screenshot(self, filename: str = DEFAULT_FILENAME_PAGE) -> str: if not self.drivers.current: self.info("Cannot capture screenshot because no browser is open.") return - if self._decide_embedded(filename): - return self._capture_page_screen_to_log() + is_embedded, method = self._decide_embedded(filename) + if is_embedded: + return self._capture_page_screen_to_log(method) return self._capture_page_screenshot_to_file(filename) def _capture_page_screenshot_to_file(self, filename): @@ -123,9 +136,11 @@ def _capture_page_screenshot_to_file(self, filename): self._embed_to_log_as_file(path, 800) return path - def _capture_page_screen_to_log(self): + def _capture_page_screen_to_log(self, return_val): screenshot_as_base64 = self.driver.get_screenshot_as_base64() - self._embed_to_log_as_base64(screenshot_as_base64, 800) + base64_str = self._embed_to_log_as_base64(screenshot_as_base64, 800) + if return_val == BASE64: + return base64_str return EMBED @keyword @@ -140,18 +155,24 @@ def capture_element_screenshot( See the `Locating elements` section for details about the locator syntax. - An absolute path to the created element screenshot is returned. + An absolute path to the created element screenshot is returned. If the ``filename`` + equals to BASE64 (case insensitive), then the base64 string is returned in addition + to the screenshot embedded to the log. See ``Capture Page Screenshot`` for more + information. Support for capturing the screenshot from an element has limited support among browser vendors. Please check the browser vendor driver documentation does the browser support capturing a screenshot from an element. New in SeleniumLibrary 3.3. Support for EMBED is new in SeleniumLibrary 4.2. + Support for BASE64 is new in SeleniumLibrary 6.8. Examples: | `Capture Element Screenshot` | id:image_id | | | `Capture Element Screenshot` | id:image_id | ${OUTPUTDIR}/id_image_id-1.png | | `Capture Element Screenshot` | id:image_id | EMBED | + | ${ess}= | `Capture Element Screenshot` | id:image_id | BASE64 | + """ if not self.drivers.current: self.info( @@ -159,8 +180,9 @@ def capture_element_screenshot( ) return element = self.find_element(locator, required=True) - if self._decide_embedded(filename): - return self._capture_element_screen_to_log(element) + is_embedded, method = self._decide_embedded(filename) + if is_embedded: + return self._capture_element_screen_to_log(element, method) return self._capture_element_screenshot_to_file(element, filename) def _capture_element_screenshot_to_file(self, element, filename): @@ -171,8 +193,10 @@ def _capture_element_screenshot_to_file(self, element, filename): self._embed_to_log_as_file(path, 400) return path - def _capture_element_screen_to_log(self, element): - self._embed_to_log_as_base64(element.screenshot_as_base64, 400) + def _capture_element_screen_to_log(self, element, return_val): + base64_str = self._embed_to_log_as_base64(element.screenshot_as_base64, 400) + if return_val == BASE64: + return base64_str return EMBED @property @@ -184,20 +208,20 @@ def _screenshot_root_directory(self, value): self.ctx.screenshot_root_directory = value def _decide_embedded(self, filename): - filename = filename.lower() + filename = filename.upper() if ( - filename == DEFAULT_FILENAME_PAGE - and self._screenshot_root_directory == EMBED + filename == DEFAULT_FILENAME_PAGE.upper() + and self._screenshot_root_directory in EMBEDDED_OPTIONS ): - return True + return True, self._screenshot_root_directory if ( - filename == DEFAULT_FILENAME_ELEMENT - and self._screenshot_root_directory == EMBED + filename == DEFAULT_FILENAME_ELEMENT.upper() + and self._screenshot_root_directory in EMBEDDED_OPTIONS ): - return True - if filename == EMBED.lower(): - return True - return False + return True, self._screenshot_root_directory + if filename in EMBEDDED_OPTIONS: + return True, self._screenshot_root_directory + return False, None def _get_screenshot_path(self, filename): if self._screenshot_root_directory != EMBED: diff --git a/utest/test/keywords/test_screen_shot.py b/utest/test/keywords/test_screen_shot.py index a5cac9248..2ea09cb30 100644 --- a/utest/test/keywords/test_screen_shot.py +++ b/utest/test/keywords/test_screen_shot.py @@ -8,7 +8,7 @@ SCREENSHOT_FILE_NAME = "selenium-screenshot-{index}.png" ELEMENT_FILE_NAME = "selenium-element-screenshot-{index}.png" EMBED = "EMBED" - +BASE64 = "BASE64" @pytest.fixture(scope="module") def screen_shot(): @@ -22,24 +22,34 @@ def teardown_function(): def test_defaults(screen_shot): - assert screen_shot._decide_embedded(SCREENSHOT_FILE_NAME) is False - assert screen_shot._decide_embedded(ELEMENT_FILE_NAME) is False + assert screen_shot._decide_embedded(SCREENSHOT_FILE_NAME) == (False, None) + assert screen_shot._decide_embedded(ELEMENT_FILE_NAME) == (False, None) def test_screen_shotdir_embeded(screen_shot): screen_shot.ctx.screenshot_root_directory = EMBED - assert screen_shot._decide_embedded(SCREENSHOT_FILE_NAME) is True - assert screen_shot._decide_embedded(SCREENSHOT_FILE_NAME.upper()) is True - assert screen_shot._decide_embedded(ELEMENT_FILE_NAME) is True - assert screen_shot._decide_embedded(ELEMENT_FILE_NAME.upper()) is True - assert screen_shot._decide_embedded("other.psn") is False + assert screen_shot._decide_embedded(SCREENSHOT_FILE_NAME) == (True, EMBED) + assert screen_shot._decide_embedded(SCREENSHOT_FILE_NAME.upper()) == (True, EMBED) + assert screen_shot._decide_embedded(ELEMENT_FILE_NAME) == (True, EMBED) + assert screen_shot._decide_embedded(ELEMENT_FILE_NAME.upper()) == (True, EMBED) + assert screen_shot._decide_embedded("other.psn") == (False, None) + + +def test_screen_shotdir_return_base64(screen_shot): + screen_shot.ctx.screenshot_root_directory = BASE64 + assert screen_shot._decide_embedded(SCREENSHOT_FILE_NAME) == (True, BASE64) + assert screen_shot._decide_embedded(SCREENSHOT_FILE_NAME.upper()) == (True, BASE64) + assert screen_shot._decide_embedded(ELEMENT_FILE_NAME) == (True, BASE64) + assert screen_shot._decide_embedded(ELEMENT_FILE_NAME.upper()) == (True, BASE64) + assert screen_shot._decide_embedded("other.psn") == (False, None) def test_file_name_embeded(screen_shot): - assert screen_shot._decide_embedded(EMBED) is True - assert screen_shot._decide_embedded("other.psn") is False + assert screen_shot._decide_embedded("other.psn") == (False, None) screen_shot.ctx.screenshot_root_directory = EMBED - assert screen_shot._decide_embedded(EMBED) is True + assert screen_shot._decide_embedded(EMBED) == (True, EMBED) + screen_shot.ctx.screenshot_root_directory = BASE64 + assert screen_shot._decide_embedded(BASE64) == (True, BASE64) def test_screenshot_path_embedded(screen_shot): @@ -56,6 +66,12 @@ def test_sl_init_embed(): sl = SeleniumLibrary(screenshot_root_directory=EMBED) assert sl.screenshot_root_directory == EMBED + sl = SeleniumLibrary(screenshot_root_directory="bAsE64") + assert sl.screenshot_root_directory == BASE64 + + sl = SeleniumLibrary(screenshot_root_directory=BASE64) + assert sl.screenshot_root_directory == BASE64 + def test_sl_init_not_embed(): sl = SeleniumLibrary(screenshot_root_directory=None) @@ -76,6 +92,9 @@ def test_sl_set_screenshot_directory(): sl.set_screenshot_directory(EMBED) assert sl.screenshot_root_directory == EMBED + sl.set_screenshot_directory(BASE64) + assert sl.screenshot_root_directory == BASE64 + sl.set_screenshot_directory("EEmBedD") assert "EEmBedD" in sl.screenshot_root_directory assert len("EEmBedD") < len(sl.screenshot_root_directory)