Skip to content

Commit

Permalink
Merge pull request #20 from ScreenPyHQ/wrap-playwright-errors
Browse files Browse the repository at this point in the history
Add an easier message to read when errors occur.
  • Loading branch information
perrygoy authored Jul 16, 2024
2 parents 5028497 + eb9212a commit bb01d34
Show file tree
Hide file tree
Showing 8 changed files with 130 additions and 16 deletions.
12 changes: 10 additions & 2 deletions screenpy_playwright/actions/click.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@

from typing import TYPE_CHECKING, Sequence, TypedDict

from screenpy.pacing import beat
from playwright.sync_api import Error as PlaywrightError
from screenpy import DeliveryError, beat

if TYPE_CHECKING:
from playwright.sync_api import Position
Expand Down Expand Up @@ -62,7 +63,14 @@ def describe(self) -> str:
@beat("{} clicks on the {target}.")
def perform_as(self, the_actor: Actor) -> None:
"""Direct the Actor to click on the element."""
self.target.found_by(the_actor).click(**self.kwargs)
try:
self.target.found_by(the_actor).click(**self.kwargs)
except PlaywrightError as e:
msg = (
f"{the_actor} encountered an issue while attempting to click "
f"{self.target}: {e.__class__.__name__}"
)
raise DeliveryError(msg) from e

def __init__(self, target: Target, **kwargs: Unpack[ClickTypes]) -> None:
self.target = target
Expand Down
13 changes: 10 additions & 3 deletions screenpy_playwright/actions/enter.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@

from typing import TYPE_CHECKING, TypedDict

from screenpy.exceptions import UnableToAct
from screenpy.pacing import beat
from playwright.sync_api import Error as PlaywrightError
from screenpy import DeliveryError, UnableToAct, beat

if TYPE_CHECKING:
from screenpy import Actor
Expand Down Expand Up @@ -87,7 +87,14 @@ def perform_as(self, the_actor: Actor) -> None:
)
raise UnableToAct(msg)

self.target.found_by(the_actor).fill(self.text, **self.kwargs)
try:
self.target.found_by(the_actor).fill(self.text, **self.kwargs)
except PlaywrightError as e:
msg = (
f"{the_actor} encountered an issue while attempting to enter text into "
f"{self.target}: {e.__class__.__name__}"
)
raise DeliveryError(msg) from e

def __init__(
self, text: str, *, mask: bool = False, **kwargs: Unpack[EnterTypes]
Expand Down
13 changes: 11 additions & 2 deletions screenpy_playwright/actions/open.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
import os
from typing import TYPE_CHECKING, TypedDict

from screenpy.pacing import beat
from playwright.sync_api import Error as PlaywrightError
from screenpy import DeliveryError, beat

from ..abilities import BrowseTheWebSynchronously

Expand Down Expand Up @@ -56,7 +57,15 @@ def perform_as(self, the_actor: Actor) -> None:
"""Direct the actor to Open a webpage."""
browse_the_web = the_actor.ability_to(BrowseTheWebSynchronously)
page = browse_the_web.browser.new_page()
page.goto(self.url, **self.kwargs)
try:
page.goto(self.url, **self.kwargs)
except PlaywrightError as e:
msg = (
f"{the_actor} encountered an issue while attempting to go to "
f"{self.url}: {e.__class__.__name__}"
)
raise DeliveryError(msg) from e

browse_the_web.current_page = page
browse_the_web.pages.append(page)

Expand Down
12 changes: 10 additions & 2 deletions screenpy_playwright/actions/refresh_the_page.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@

from typing import TYPE_CHECKING, Literal, TypedDict

from screenpy import beat
from playwright.sync_api import Error as PlaywrightError
from screenpy import DeliveryError, beat

from screenpy_playwright.abilities import BrowseTheWebSynchronously

Expand Down Expand Up @@ -45,4 +46,11 @@ def describe(self) -> str:
def perform_as(self, the_actor: Actor) -> None:
"""Direct the Actor to refresh the page."""
page = the_actor.ability_to(BrowseTheWebSynchronously).current_page
page.reload(**self.kwargs)
try:
page.reload(**self.kwargs)
except PlaywrightError as e:
msg = (
f"{the_actor} encountered an issue while attempting to "
f"refresh the page: {e.__class__.__name__}"
)
raise DeliveryError(msg) from e
13 changes: 11 additions & 2 deletions screenpy_playwright/actions/save_screenshot.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
from pathlib import Path
from typing import TYPE_CHECKING, Any

from screenpy import AttachTheFile, UnableToAct, beat
from playwright.sync_api import Error as PlaywrightError
from screenpy import AttachTheFile, DeliveryError, UnableToAct, beat

from ..abilities import BrowseTheWebSynchronously

Expand Down Expand Up @@ -89,7 +90,15 @@ def perform_as(self, the_actor: Actor) -> None:
msg = "No page has been opened! Cannot save a screenshot."
raise UnableToAct(msg)

screenshot = current_page.screenshot(path=self.path)
try:
screenshot = current_page.screenshot(path=self.path)
except PlaywrightError as e:
msg = (
f"{the_actor} encountered an issue while attempting to "
f"save a screenshot: {e.__class__.__name__}"
)
raise DeliveryError(msg) from e

Path(self.path).write_bytes(screenshot)

if self.attach_kwargs is not None:
Expand Down
12 changes: 10 additions & 2 deletions screenpy_playwright/actions/scroll.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@

from typing import TYPE_CHECKING

from screenpy import beat
from playwright.sync_api import Error as PlaywrightError
from screenpy import DeliveryError, beat

from ..abilities import BrowseTheWebSynchronously

Expand Down Expand Up @@ -100,4 +101,11 @@ def direction_to_log(self) -> str:
def perform_as(self, the_actor: Actor) -> None:
"""Direct the Actor to scroll the page."""
page = the_actor.ability_to(BrowseTheWebSynchronously).current_page
page.mouse.wheel(delta_x=self.delta_x, delta_y=self.delta_y)
try:
page.mouse.wheel(delta_x=self.delta_x, delta_y=self.delta_y)
except PlaywrightError as e:
msg = (
f"{the_actor} encountered an issue while attempting to scroll "
f"{self.direction_to_log}: {e.__class__.__name__}"
)
raise DeliveryError(msg) from e
12 changes: 10 additions & 2 deletions screenpy_playwright/actions/select.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@

from typing import TYPE_CHECKING, Sequence, TypedDict

from screenpy import UnableToAct, beat
from playwright.sync_api import Error as PlaywrightError
from screenpy import DeliveryError, UnableToAct, beat

if TYPE_CHECKING:
from playwright.sync_api import ElementHandle
Expand Down Expand Up @@ -106,4 +107,11 @@ def perform_as(self, the_actor: Actor) -> None:
)
raise UnableToAct(msg)

self.target.found_by(the_actor).select_option(self.args, **self.kwargs)
try:
self.target.found_by(the_actor).select_option(self.args, **self.kwargs)
except PlaywrightError as e:
msg = (
f"{the_actor} encountered an issue while attempting to select "
f"{self.target}: {e.__class__.__name__}"
)
raise DeliveryError(msg) from e
59 changes: 58 additions & 1 deletion tests/test_actions.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
from unittest import mock

import pytest
from screenpy import Actor, Describable, Performable, UnableToAct
from playwright.sync_api import Error as PlaywrightError
from screenpy import Actor, DeliveryError, Describable, Performable, UnableToAct

from screenpy_playwright import (
BrowseTheWebSynchronously,
Expand Down Expand Up @@ -50,6 +51,13 @@ def test_perform_click(self, Tester: Actor) -> None:
target.found_by.assert_called_once_with(Tester)
locator.click.assert_called_once_with(delay=0.5)

def test_raises_deliveryerror(self, Tester: Actor) -> None:
target, locator = get_mocked_target_and_locator()
locator.click.side_effect = PlaywrightError("I have no more pens.")

with pytest.raises(DeliveryError):
Click(target).perform_as(Tester)


class TestEnter:
def test_can_be_instantiated(self) -> None:
Expand Down Expand Up @@ -99,6 +107,13 @@ def test_perform_enter(self, Tester: Actor) -> None:
target.found_by.assert_called_once_with(Tester)
locator.fill.assert_called_once_with(text, force=True)

def test_raises_deliveryerror(self, Tester: Actor) -> None:
target, locator = get_mocked_target_and_locator()
locator.fill.side_effect = PlaywrightError("I have no more ink.")

with pytest.raises(DeliveryError):
Enter("quietly").into_the(target).perform_as(Tester)


class TestRefreshThePage:
def test_can_be_instantiated(self) -> None:
Expand All @@ -125,6 +140,15 @@ def test_perform_refresh(self, Tester: Actor) -> None:

current_page.reload.assert_called_once_with(timeout=20)

def test_raises_deliveryerror(self, Tester: Actor) -> None:
page = cast(
mock.Mock, Tester.ability_to(BrowseTheWebSynchronously).current_page
)
page.reload.side_effect = PlaywrightError("I have no more paper.")

with pytest.raises(DeliveryError):
RefreshThePage().perform_as(Tester)


class TestSaveScreenshot:

Expand Down Expand Up @@ -190,6 +214,15 @@ class SubSaveScreenshot(SaveScreenshot):
assert isinstance(sss2, SubSaveScreenshot)
assert isinstance(sss3, SubSaveScreenshot)

def test_raises_deliveryerror(self, Tester: Actor) -> None:
page = cast(
mock.Mock, Tester.ability_to(BrowseTheWebSynchronously).current_page
)
page.screenshot.side_effect = PlaywrightError("I have no camera.")

with pytest.raises(DeliveryError):
SaveScreenshot("./screenshot.png").perform_as(Tester)


class TestScroll:
def test_can_be_instantiated(self) -> None:
Expand Down Expand Up @@ -246,6 +279,15 @@ def test_perform_scroll(self, Tester: Actor) -> None:

current_page.mouse.wheel.assert_called_once_with(delta_x=1337, delta_y=-9001)

def test_raises_deliveryerror(self, Tester: Actor) -> None:
page = cast(
mock.Mock, Tester.ability_to(BrowseTheWebSynchronously).current_page
)
page.mouse.wheel.side_effect = PlaywrightError("I have no legs.")

with pytest.raises(DeliveryError):
Scroll(1337, -9001).perform_as(Tester)


class TestSelect:
def test_can_be_instantiated(self) -> None:
Expand Down Expand Up @@ -286,6 +328,13 @@ def test_raises_with_no_target(self, Tester: Actor) -> None:
with pytest.raises(UnableToAct):
Select("option").perform_as(Tester)

def test_raises_deliveryerror(self, Tester: Actor) -> None:
target, locator = get_mocked_target_and_locator()
locator.select_option.side_effect = PlaywrightError("I have no opinions.")

with pytest.raises(DeliveryError):
Select("option").from_the(target).perform_as(Tester)


class TestVisit:
def test_can_be_instantiated(self) -> None:
Expand Down Expand Up @@ -334,3 +383,11 @@ def test_perform_visit(self, Tester: Actor) -> None:
mock_page.goto.assert_called_once_with(url, wait_until="commit")
assert mock_ability.current_page == mock_page
assert mock_page in mock_ability.pages

def test_raises_deliveryerror(self, Tester: Actor) -> None:
browse_the_web = cast(mock.Mock, Tester.ability_to(BrowseTheWebSynchronously))
browse_the_web.browser.new_page.return_value = browse_the_web.current_page
browse_the_web.current_page.goto.side_effect = PlaywrightError("I have no map.")

with pytest.raises(DeliveryError):
Visit("url").perform_as(Tester)

0 comments on commit bb01d34

Please sign in to comment.