Skip to content

Commit

Permalink
Add a workaround for capturing screenshots when a DOM's body element … (
Browse files Browse the repository at this point in the history
#30)

* Add a workaround for capturing screenshots when a DOM's body element has no calculated height.

* Increase package version to 5.0.2
  • Loading branch information
Thomas Thorogood authored Feb 24, 2022
1 parent 347a320 commit 86a086e
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 2 deletions.
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name = "uw-webdriver-recorder"
# This version string is typically managed by the CI workflow,
# and is changed anytime `poetry version [new version]` is run.
# Do not revert this manually.
version = "5.0.1"
version = "5.0.2"
description = "A pytest plugin for recording screenshots of selenium interactions, with other convenient features too."
authors = ["Tom Thorogood <[email protected]>"]
license = "Apache Software License 3.0"
Expand Down
34 changes: 34 additions & 0 deletions tests/test_browser.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,40 @@ def test_snap(browser, load_page):
assert len(browser.pngs) == 1


def test_snap_0_height(browser, load_page):
"""
This particular case is hard to set up, but in rare
circumstances a page's DOM will ahve a 0-height
'body', which causes an error when creating our
normal screenshot. Here we are simply testing that, in that case,
the "legacy" method of creating a screenshot is used instead.
"""
# Create a fake `body` object
orig_find_element = browser.find_element
orig_screenshot = browser.get_screenshot_as_base64
mock_body = mock.MagicMock()
mock_body.rect = {"height": 0}

def mock_find_element(by_: By, value: str):
if value == "body":
return mock_body
return orig_find_element(by_, value)

def mock_take_screenshot():
return orig_screenshot()

screenshot_mocker = mock.patch.object(browser, "get_screenshot_as_base64", side_effect=mock_take_screenshot)
find_element_mocker = mock.patch.object(browser, "find_element", mock_find_element)
screenshot_mock = screenshot_mocker.start()
find_element_mocker.start()
try:
browser.snap()
screenshot_mock.assert_called_once()
finally:
screenshot_mocker.stop()
find_element_mocker.stop()


def test_send(browser, load_page):
time.sleep(0.5)
browser.send("foo", "bar")
Expand Down
13 changes: 12 additions & 1 deletion webdriver_recorder/browser.py
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,18 @@ def snap(self, caption: Optional[str] = None, is_error: bool = False):
Resize the window ahead of time so the full page shows in the shot.
"""
with self._resize_for_screenshot():
b64_image = self.find_element(By_.TAG_NAME, "body").screenshot_as_base64
# The 'body' tag is the preferred way of capturing a screenshot
# because it will be more consistent than having to worry about
# scrollbars, etc. However, in some cases, a body DOM
# may have content but no calculated height, which causes an
# error when trying to capture the screenshot.
# This if/else prevents the error by capturing a screenshot
# using the window if the body's height is false-y.
body = self.find_element(By_.TAG_NAME, "body")
if body.rect.get("height"):
b64_image = body.screenshot_as_base64
else:
b64_image = self.get_screenshot_as_base64()
# The sha256 digest is used to fingerprint the image.
# This can SIGNIFICANTLY reduce the payload of a report
# artifact bundle by de-duplicating images, especially
Expand Down

0 comments on commit 86a086e

Please sign in to comment.