Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 14 additions & 5 deletions screenpy_selenium/actions/wait.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@

if TYPE_CHECKING:
from screenpy import Actor
from selenium.types import WaitExcTypes
from selenium.webdriver.remote.webelement import WebElement
from typing_extensions import Self

from ..target import Target
Expand Down Expand Up @@ -54,9 +56,10 @@ class Wait:
args: Iterable[Any]
timeout: float
log_detail: str | None
ignored_exceptions: WaitExcTypes | None

@classmethod
def for_the(cls, target: Target) -> Self:
def for_the(cls, target: Target | WebElement) -> Self:
"""Set the Target to wait for.

Aliases:
Expand All @@ -65,7 +68,7 @@ def for_the(cls, target: Target) -> Self:
return cls(seconds=settings.TIMEOUT, args=[target])

@classmethod
def for_(cls, target: Target) -> Self:
def for_(cls, target: Target | WebElement) -> Self:
"""Alias for :meth:`~screenpy_selenium.actions.Wait.for_the`."""
return cls.for_the(target=target)

Expand Down Expand Up @@ -128,6 +131,11 @@ def log_message(self) -> str:

return self.log_detail.format(*self.args)

def ignoring(self, *ignored_exceptions: type[Exception]) -> Self:
"""Set the expception classes to ignore."""
self.ignored_exceptions = ignored_exceptions
return self

def describe(self) -> str:
"""Describe the Action in present tense."""
return f"Wait {self.timeout} seconds {self.log_message}."
Expand All @@ -138,9 +146,9 @@ def perform_as(self, the_actor: Actor) -> None:
browser = the_actor.ability_to(BrowseTheWeb).browser

try:
WebDriverWait(browser, self.timeout, settings.POLLING).until(
self.condition(*self.args)
)
WebDriverWait(
browser, self.timeout, settings.POLLING, self.ignored_exceptions
).until(self.condition(*self.args))
except WebDriverException as e:
msg = (
f"Encountered an exception using {self.condition.__name__} with "
Expand All @@ -155,3 +163,4 @@ def __init__(
self.timeout = seconds if seconds is not None else settings.TIMEOUT
self.condition = EC.visibility_of_element_located
self.log_detail = None
self.ignored_exceptions = None
17 changes: 13 additions & 4 deletions tests/test_actions.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,11 @@
from screenpy import DeliveryError, Describable, Performable, UnableToAct, settings
from screenpy.configuration import ScreenPySettings
from screenpy_pyotp.abilities import AuthenticateWith2FA
from selenium.common.exceptions import WebDriverException
from selenium.common.exceptions import (
NoSuchFrameException,
StaleElementReferenceException,
WebDriverException,
)
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.remote.webelement import WebElement
from selenium.webdriver.support import expected_conditions as EC
Expand Down Expand Up @@ -1525,7 +1529,7 @@ def test_defaults(
Wait.for_the(test_target).perform_as(Tester)

mocked_webdriverwait.assert_called_once_with(
mocked_browser, settings.TIMEOUT, settings.POLLING
mocked_browser, settings.TIMEOUT, settings.POLLING, None
)
mocked_ec.visibility_of_element_located.assert_called_once_with(test_target)
mocked_webdriverwait(
Expand All @@ -1544,10 +1548,15 @@ def test_override(
mocked_browser = get_mocked_browser(Tester)
timeout = 4

Wait(timeout).seconds_for(test_target).perform_as(Tester)
Wait(timeout).seconds_for(test_target).ignoring(
StaleElementReferenceException, NoSuchFrameException
).perform_as(Tester)

mocked_webdriverwait.assert_called_once_with(
mocked_browser, timeout, settings.POLLING
mocked_browser,
timeout,
settings.POLLING,
(StaleElementReferenceException, NoSuchFrameException),
)
mocked_ec.visibility_of_element_located.assert_called_once_with(test_target)
mocked_webdriverwait(mocked_browser, timeout).until.assert_called_once_with(
Expand Down
Loading