From 88584cd0b1f675adc58858aec23e5a67dbe3361c Mon Sep 17 00:00:00 2001 From: Niloth-p <20315308+Niloth-p@users.noreply.github.com> Date: Wed, 1 May 2024 06:55:17 +0530 Subject: [PATCH] tests: boxes: Add tests for saving drafts. Added - 1 fixture for saved drafts - 2 fixtures for draft compositions - stream and private - 2 setup fixtures - stream and private - 2 test functions for stream compositions - when a draft previously exists, call the confirmation popup - when new draft matches saved draft, do not save again - 3 test functions for private compositions - valid recipients, invalid recipients, new draft matches already saved draft Co-authored-by: Manu_K_Paul --- tests/ui_tools/test_boxes.py | 239 ++++++++++++++++++++++++++++++++++- 1 file changed, 238 insertions(+), 1 deletion(-) diff --git a/tests/ui_tools/test_boxes.py b/tests/ui_tools/test_boxes.py index 8fc050391f..c6066a1b8d 100644 --- a/tests/ui_tools/test_boxes.py +++ b/tests/ui_tools/test_boxes.py @@ -1,8 +1,10 @@ import datetime from collections import OrderedDict -from typing import Any, Callable, Dict, List, Optional +from functools import reduce +from typing import Any, Callable, Dict, List, Optional, Tuple, Union import pytest +from pytest import FixtureRequest from pytest import param as case from pytest_mock import MockerFixture from urwid import Widget @@ -11,6 +13,9 @@ TYPING_STARTED_EXPIRY_PERIOD, TYPING_STARTED_WAIT_PERIOD, TYPING_STOPPED_WAIT_PERIOD, + Composition, + PrivateComposition, + StreamComposition, ) from zulipterminal.config.keys import ( keys_for_command, @@ -103,6 +108,238 @@ def test_not_calling_typing_method_without_recipients( assert not write_box.model.send_typing_status_by_user_ids.called + @pytest.fixture( + params=[ + { + "draft_composition": None, + "expected_function": "model.save_draft", + }, + { + "draft_composition": StreamComposition( + type="stream", + to="Random Stream", + content="Random stream draft", + subject="Topic name", + read_by_sender=True, + ), + "expected_function": "view.controller.save_draft_confirmation_popup", + }, + { + "draft_composition": PrivateComposition( + type="private", + to=[5140], + content="Random private draft", + read_by_sender=True, + ), + "expected_function": "view.controller.save_draft_confirmation_popup", + }, + { + "draft_composition": PrivateComposition( + type="private", + to=[5140, 5179], + content="Random group draft", + read_by_sender=True, + ), + "expected_function": "view.controller.save_draft_confirmation_popup", + }, + ], + ids=[ + "no_saved_draft_exists", + "saved_stream_draft_exists", + "saved_private_draft_exists", + "saved_private_group_draft_exists", + ], + ) + def saved_draft( + self, request: FixtureRequest + ) -> Dict[str, Union[Optional[Composition], str]]: + return request.param + + @pytest.fixture( + params=[ + { + "type": "private", + "to": [5140], + "content": "Random message", + "read_by_sender": True, + }, + { + "type": "private", + "to": [5140, 5179], + "content": "Random DM group message", + "read_by_sender": True, + }, + ], + ids=["dm", "dm_group"], + ) + def private_draft_composition(self, request: FixtureRequest) -> PrivateComposition: + return request.param + + @pytest.fixture( + params=[ + { + "type": "stream", + "to": "Current Stream", + "content": "Random message", + "subject": "Topic", + "read_by_sender": True, + }, + ], + ) + def stream_draft_composition(self, request: FixtureRequest) -> StreamComposition: + return request.param + + @pytest.fixture + def private_draft_setup_fixture(self, mocker: MockerFixture, private_draft_composition: PrivateComposition, write_box: WriteBox) -> Tuple[MockerFixture, WriteBox]: + mocker.patch(MODULE + ".WriteBox.update_recipients") + write_box.msg_write_box = mocker.Mock( + edit_text=private_draft_composition["content"] + ) + write_box.to_write_box = mocker.Mock() + write_box.compose_box_status = "open_with_private" + write_box.recipient_user_ids = private_draft_composition["to"] + return mocker, write_box + + @pytest.fixture + def stream_draft_setup_fixture(self, mocker: MockerFixture, stream_draft_composition: StreamComposition, write_box: WriteBox) -> Tuple[MockerFixture, WriteBox]: + mocker.patch(MODULE + ".WriteBox.update_recipients") + write_box.msg_write_box = mocker.Mock( + edit_text=stream_draft_composition["content"] + ) + write_box.stream_write_box = mocker.Mock( + edit_text=stream_draft_composition["to"] + ) + write_box.title_write_box = mocker.Mock( + edit_text=stream_draft_composition["subject"] + ) + write_box.compose_box_status = "open_with_stream" + write_box.stream_id = 1 + return mocker, write_box + + @pytest.mark.parametrize("key", keys_for_command("SAVE_AS_DRAFT")) + def test_keypress_SAVE_AS_DRAFT_stream( + self, + key: str, + saved_draft: Dict[str, Union[Optional[Composition], str]], + stream_draft_composition: StreamComposition, + stream_draft_setup_fixture: Tuple[MockerFixture, WriteBox], + write_box: WriteBox, + widget_size: Callable[[Widget], urwid_Size], + ) -> None: + draft_saved_in_current_session = saved_draft["draft_composition"] + _, write_box = stream_draft_setup_fixture + assert isinstance(saved_draft["expected_function"], str) + expected_function = reduce( + getattr, saved_draft["expected_function"].split("."), write_box + ) + write_box.model.session_draft_message.return_value = ( + draft_saved_in_current_session + ) + + size = widget_size(write_box) + write_box.keypress(size, key) + + write_box.model.session_draft_message.assert_called() + expected_function.assert_called_once_with(stream_draft_composition) + + @pytest.mark.parametrize("key", keys_for_command("SAVE_AS_DRAFT")) + def test_keypress_SAVE_AS_DRAFT_private__valid_recipients( + self, + key: str, + mocker: MockerFixture, + private_draft_composition: PrivateComposition, + saved_draft: Dict[str, Union[Optional[Composition], str]], + private_draft_setup_fixture: Tuple[MockerFixture, WriteBox], + write_box: WriteBox, + widget_size: Callable[[Widget], urwid_Size], + ) -> None: + draft_saved_in_current_session = saved_draft["draft_composition"] + mocker, write_box = private_draft_setup_fixture + assert isinstance(saved_draft["expected_function"], str) + expected_function = reduce( + getattr, saved_draft["expected_function"].split("."), write_box + ) + mocker.patch( + MODULE + ".WriteBox._tidy_valid_recipients_and_notify_invalid_ones", + return_value=True, + ) + write_box.model.session_draft_message.return_value = ( + draft_saved_in_current_session + ) + + size = widget_size(write_box) + write_box.keypress(size, key) + + write_box.model.session_draft_message.assert_called() + expected_function.assert_called_once_with(private_draft_composition) + + @pytest.mark.parametrize("key", keys_for_command("SAVE_AS_DRAFT")) + def test_keypress_SAVE_AS_DRAFT_private__invalid_recipients( + self, + key: str, + mocker: MockerFixture, + saved_draft: Dict[str, Union[Optional[Composition], str]], + private_draft_setup_fixture: Tuple[MockerFixture, WriteBox], + write_box: WriteBox, + widget_size: Callable[[Widget], urwid_Size], + ) -> None: + draft_saved_in_current_session = saved_draft["draft_composition"] + mocker, write_box = private_draft_setup_fixture + mocker.patch( + MODULE + ".WriteBox._tidy_valid_recipients_and_notify_invalid_ones", + return_value=False, + ) + write_box.model.session_draft_message.return_value = ( + draft_saved_in_current_session + ) + + size = widget_size(write_box) + write_box.keypress(size, key) + + write_box.model.save_draft.assert_not_called() + write_box.view.controller.save_draft_confirmation_popup.assert_not_called() + + @pytest.mark.parametrize("key", keys_for_command("SAVE_AS_DRAFT")) + def test_keypress_SAVE_AS_DRAFT_stream__already_saved( + self, + key: str, + stream_draft_composition: StreamComposition, + stream_draft_setup_fixture: Tuple[MockerFixture, WriteBox], + write_box: WriteBox, + widget_size: Callable[[Widget], urwid_Size], + ) -> None: + write_box.model.session_draft_message.return_value = stream_draft_composition + _, write_box = stream_draft_setup_fixture + + size = widget_size(write_box) + write_box.keypress(size, key) + + write_box.model.session_draft_message.assert_called() + write_box.view.controller.save_draft_confirmation_popup.assert_not_called() + + @pytest.mark.parametrize("key", keys_for_command("SAVE_AS_DRAFT")) + def test_keypress_SAVE_AS_DRAFT_private__same_as_saved_draft( + self, + key: str, + mocker: MockerFixture, + private_draft_composition: PrivateComposition, + private_draft_setup_fixture: Tuple[MockerFixture, WriteBox], + write_box: WriteBox, + widget_size: Callable[[Widget], urwid_Size], + ) -> None: + mocker, write_box = private_draft_setup_fixture + mocker.patch( + MODULE + ".WriteBox._tidy_valid_recipients_and_notify_invalid_ones", + return_value=True, + ) + write_box.model.session_draft_message.return_value = private_draft_composition + + size = widget_size(write_box) + write_box.keypress(size, key) + + write_box.model.session_draft_message.assert_called() + write_box.view.controller.save_draft_confirmation_popup.assert_not_called() + @pytest.mark.parametrize( "text, state, is_valid_stream, required_typeahead", [