Skip to content
40 changes: 40 additions & 0 deletions tests/ui_tools/test_popups.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
MsgInfoView,
PopUpConfirmationView,
PopUpView,
SpoilerView,
StreamInfoView,
StreamMembersView,
UserInfoView,
Expand Down Expand Up @@ -952,6 +953,45 @@ def test_keypress_exit_popup(
assert self.controller.exit_popup.called


class TestSpoilerView:
@pytest.fixture(autouse=True)
def mock_external_classes(self, mocker: MockerFixture) -> None:
self.controller = mocker.Mock()
mocker.patch.object(
self.controller, "maximum_popup_dimensions", return_value=(64, 64)
)
mocker.patch(MODULE + ".urwid.SimpleFocusListWalker", return_value=[])
self.spoiler_view = SpoilerView(self.controller, "Spoiler View", "")

def test_keypress_any_key(
self, widget_size: Callable[[Widget], urwid_Size]
) -> None:
key = "a"
size = widget_size(self.spoiler_view)
self.spoiler_view.keypress(size, key)
assert not self.controller.exit_popup.called

@pytest.mark.parametrize("key", {*keys_for_command("EXIT_POPUP")})
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
@pytest.mark.parametrize("key", {*keys_for_command("EXIT_POPUP")})
@pytest.mark.parametrize("key", keys_for_command("EXIT_POPUP"))

def test_keypress_exit_popup(
self, key: str, widget_size: Callable[[Widget], urwid_Size]
) -> None:
size = widget_size(self.spoiler_view)
self.spoiler_view.keypress(size, key)
assert self.controller.exit_popup.called

def test_keypress_navigation(
self,
mocker: MockerFixture,
widget_size: Callable[[Widget], urwid_Size],
navigation_key_expected_key_pair: Tuple[str, str] = ("ENTER", "ENTER"),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assume the intention is to clarify the variables, but is this really required for this test? Can't we just use a single variable?

) -> None:
key, expected_key = navigation_key_expected_key_pair
size = widget_size(self.spoiler_view)
super_keypress = mocker.patch(MODULE + ".urwid.ListBox.keypress")
self.spoiler_view.keypress(size, key)
super_keypress.assert_called_once_with(size, expected_key)


class TestMsgInfoView:
@pytest.fixture(autouse=True)
def mock_external_classes(
Expand Down
6 changes: 6 additions & 0 deletions zulipterminal/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
MsgInfoView,
NoticeView,
PopUpConfirmationView,
SpoilerView,
StreamInfoView,
StreamMembersView,
UserInfoView,
Expand Down Expand Up @@ -481,6 +482,11 @@ def report_warning(
"""
self.view.set_footer_text(text, "task:warning", duration)

def show_spoiler(self, content: str) -> None:
self.show_pop_up(
SpoilerView(self, "Spoiler (up/down scrolls)", content), "area:msg"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I appreciate the convention. But, this suggestion of "up/down scrolls" looks out of place for most spoiler use cases. Could we update to include that only when not all of the spoiler is visible, and not show it otherwise?

)

def show_media_confirmation_popup(
self, func: Any, tool: str, media_path: str
) -> None:
Expand Down
8 changes: 8 additions & 0 deletions zulipterminal/ui_tools/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -1076,6 +1076,14 @@ def __init__(
super().__init__(controller, widgets, "EXIT_POPUP", width, title)


class SpoilerView(PopUpView):
def __init__(self, controller: Any, title: str, content: str) -> None:
width, _ = controller.maximum_popup_dimensions()
widget = [urwid.Text(content)]

super().__init__(controller, widget, "MSG_INFO", width, title)


class AboutView(PopUpView):
def __init__(
self,
Expand Down