Skip to content

Commit

Permalink
add support for iframes to Target.
Browse files Browse the repository at this point in the history
  • Loading branch information
perrygoy committed Feb 20, 2024
1 parent aba843c commit db5f2d2
Show file tree
Hide file tree
Showing 2 changed files with 102 additions and 1 deletion.
13 changes: 12 additions & 1 deletion screenpy_playwright/target.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ class Target:
"""

locator: str | None
frame_path: list[str]
_description: str | None

@staticmethod
Expand All @@ -41,6 +42,11 @@ def located_by(self, locator: str) -> Target:
self.locator = locator
return self

def in_frame(self, frame_locator: str) -> Target:
"""Provide the Playwright locator which describes the frame."""
self.frame_path.append(frame_locator)
return self

@property
def target_name(self) -> str:
"""Get the name of the Target.
Expand Down Expand Up @@ -76,7 +82,11 @@ def found_by(self, the_actor: Actor) -> Locator:
msg = f"{self} does not have a locator set."
raise TargetingError(msg)

return browse_the_web.current_page.locator(self.locator)
frame = browse_the_web.current_page
for frame_locator in self.frame_path:
frame = frame.frame_locator(frame_locator)

return frame.locator(self.locator)

def __repr__(self) -> str:
"""Get a human-readable representation of this Target.
Expand All @@ -89,3 +99,4 @@ def __repr__(self) -> str:
def __init__(self, name: str | None = None) -> None:
self._description = name
self.locator = None
self.frame_path = []
90 changes: 90 additions & 0 deletions tests/test_target.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
from __future__ import annotations

from typing import TYPE_CHECKING

import pytest
from unittest import mock

from screenpy_playwright import BrowseTheWebSynchronously, Target, TargetingError

if TYPE_CHECKING:
from screenpy import Actor


def test_can_be_instantiated() -> None:
t1 = Target.the("test")
t2 = Target.the("test").located_by("test")
t3 = Target("test")
t4 = Target().located_by("test")
t5 = Target()

assert isinstance(t1, Target)
assert isinstance(t2, Target)
assert isinstance(t3, Target)
assert isinstance(t4, Target)
assert isinstance(t5, Target)


def test_auto_describe() -> None:
"""When no description is provided, automatically use the string of the locator"""
t1 = Target().located_by("#yellow")
t2 = Target("favorite color").located_by("#no greeeeen")
t3 = Target()
t4 = Target("").located_by("baz")

assert t1.target_name == "#yellow"
assert t2.target_name == "favorite color"
assert t3.target_name == "None"
assert t4.target_name == "baz"


def test_found_by(Tester: Actor) -> None:
test_locator = "#spam>baked-beans>eggs>sausage+spam"
mocked_btws = Tester.ability_to(BrowseTheWebSynchronously)
mocked_btws.current_page = mock.Mock()

Target.the("test").located_by(test_locator).found_by(Tester)

mocked_btws.current_page.locator.assert_called_once_with(test_locator)


def test_found_by_with_frames(Tester: Actor) -> None:
test_locator = "#spam>baked-beans>eggs>sausage+spam"
mocked_btws = Tester.ability_to(BrowseTheWebSynchronously)
mocked_btws.current_page = mock.Mock()
frame_path = ["#frame1", "#frame2"]
target = Target.the("test").located_by(test_locator)
for frame in frame_path:
target.in_frame(frame)

target.found_by(Tester)

page = mocked_btws.current_page
page.frame_locator.assert_called_once_with(frame_path[0])
page.frame_locator().frame_locator.assert_called_once_with(frame_path[1])
page.frame_locator().frame_locator().locator.assert_called_once_with(test_locator)


def test_found_by_raises_if_no_locator(Tester: Actor) -> None:
test_name = "John Cleese"

with pytest.raises(TargetingError) as excinfo:
Target.the(test_name).located_by("*").found_by(Tester)

assert test_name in str(excinfo.value)


def test_repr() -> None:
t1 = Target()
t2 = Target("foo")

assert repr(t1) == "None"
assert repr(t2) == "foo"


def test_str() -> None:
t1 = Target()
t2 = Target("foo")

assert str(t1) == "None"
assert str(t2) == "foo"

0 comments on commit db5f2d2

Please sign in to comment.