diff --git a/screenpy_selenium/actions/enter.py b/screenpy_selenium/actions/enter.py index 3895ca4..895e038 100644 --- a/screenpy_selenium/actions/enter.py +++ b/screenpy_selenium/actions/enter.py @@ -7,6 +7,7 @@ from screenpy.exceptions import DeliveryError, UnableToAct from screenpy.pacing import aside, beat +from screenpy.speech_tools import represent_prop from selenium.common.exceptions import WebDriverException from ..common import pos_args_deprecated @@ -36,7 +37,7 @@ class Enter: target: Target | None following_keys: list[str] text: str - text_to_log: str + mask: bool @classmethod def the_text(cls, text: str) -> Self: @@ -109,11 +110,22 @@ def then_press(self, *keys: str) -> Self: """Alias for :meth:`~screenpy_selenium.actions.Enter.then_hit`.""" return self.then_hit(*keys) + @property + def text_to_log(self) -> str: + """Get a proper representation of the text.""" + if self.mask: + altered_text = "[CENSORED]" + else: + altered_text = self.text + for value, keyname in KEY_NAMES.items(): + altered_text = altered_text.replace(value, keyname) + return represent_prop(altered_text) + def describe(self) -> str: """Describe the Action in present tense.""" - return f'Enter "{self.text_to_log}" into the {self.target}.' + return f"Enter {self.text_to_log} into the {self.target}." - @beat('{} enters "{text_to_log}" into the {target}.') + @beat("{} enters {text_to_log} into the {target}.") def perform_as(self, the_actor: Actor) -> None: """Direct the Actor to enter the text into the element.""" if self.target is None: @@ -137,7 +149,7 @@ def perform_as(self, the_actor: Actor) -> None: ) raise DeliveryError(msg) from e - @beat(' Enter "{text_to_log}" into the {target}!') + @beat(" Enter {text_to_log} into the {target}!") def add_to_chain(self, the_actor: Actor, the_chain: ActionChains) -> None: """Add the Enter Action to a Chain of Actions.""" if self.target is None: @@ -155,11 +167,4 @@ def __init__(self, text: str, mask: bool = False) -> None: # noqa: FBT001, FBT0 self.text = text self.target = None self.following_keys = [] - - if mask: - self.text_to_log = "[CENSORED]" - else: - altered_text = text - for value, keyname in KEY_NAMES.items(): - altered_text = altered_text.replace(value, keyname) - self.text_to_log = altered_text + self.mask = mask diff --git a/tests/test_actions.py b/tests/test_actions.py index e8eb9d6..dd85bb2 100644 --- a/tests/test_actions.py +++ b/tests/test_actions.py @@ -1,5 +1,6 @@ from __future__ import annotations +import logging import warnings from contextlib import contextmanager from typing import TYPE_CHECKING, Generator, cast @@ -358,7 +359,7 @@ def test_secret_masks_text(self) -> None: e = Enter.the_secret(text) assert e.text == text - assert e.text_to_log == "[CENSORED]" + assert e.text_to_log == "'[CENSORED]'" def test_text_to_log_humanizes_keys(self) -> None: """unicode key values are turned into human-readable text""" @@ -431,11 +432,16 @@ def test_exception(self, Tester: Actor) -> None: def test_describe(self) -> None: assert ( - Enter("blah").into(TARGET).describe() == f'Enter "blah" into the {TARGET}.' + Enter("blah").into(TARGET).describe() == f"Enter 'blah' into the {TARGET}." ) assert ( Enter.the_secret("blah").into(TARGET).describe() - == f'Enter "[CENSORED]" into the {TARGET}.' + == f"Enter '[CENSORED]' into the {TARGET}." + ) + + assert ( + Enter("\ue008 \ue004 \ue007").into(TARGET).describe() + == f"Enter 'SHIFT TAB ENTER' into the {TARGET}." ) def test_subclass(self) -> None: @@ -447,6 +453,32 @@ def new_method(self) -> bool: assert SubEnter.the_text("blah").new_method() is True + def test_beat_logging( + self, Tester: Actor, caplog: pytest.LogCaptureFixture + ) -> None: + target, element = get_mocked_target_and_element() + text = 'Speak "Friend" and Enter' + caplog.set_level(logging.INFO) + Enter.the_text(text).into_the(target).perform_as(Tester) + + assert [r.msg for r in caplog.records] == [ + f"Tester enters 'Speak \"Friend\" and Enter' into the {target}." + ] + + def test_beat_logging_chain( + self, Tester: Actor, caplog: pytest.LogCaptureFixture + ) -> None: + chain = get_mocked_chain() + target, element = get_mocked_target_and_element() + text = "Hello, Champion City." + + caplog.set_level(logging.INFO) + Enter.the_text(text).into_the(target).add_to_chain(Tester, chain) + + assert [r.msg for r in caplog.records] == [ + f" Enter 'Hello, Champion City.' into the {target}!" + ] + def test_positional_arg_warns(self) -> None: with pytest.warns(DeprecationWarning): Enter("", True)