From 55b70d26ecedeab0aaea59140ced8d2541606f06 Mon Sep 17 00:00:00 2001 From: Marek Stastny Date: Mon, 5 Aug 2024 16:13:24 +0200 Subject: [PATCH 1/3] Add admin-dashboard message counter test --- .../mail_and_messages/test_message_counter.py | 63 +++++++++++++++++++ testsuite/ui/views/admin/audience/messages.py | 53 +++++++++++++++- testsuite/ui/views/admin/foundation.py | 13 ++++ 3 files changed, 128 insertions(+), 1 deletion(-) create mode 100644 testsuite/tests/ui/mail_and_messages/test_message_counter.py diff --git a/testsuite/tests/ui/mail_and_messages/test_message_counter.py b/testsuite/tests/ui/mail_and_messages/test_message_counter.py new file mode 100644 index 000000000..776aa1740 --- /dev/null +++ b/testsuite/tests/ui/mail_and_messages/test_message_counter.py @@ -0,0 +1,63 @@ +"""Test of message counters in dashboard main-section tabs""" + +import pytest + +from testsuite.ui.views.admin.audience.messages import MessagesView +from testsuite.ui.views.admin.foundation import DashboardView +from testsuite.ui.views.devel.messages import ComposeView + + +@pytest.fixture() +def setup(navigator): + """Deletes all messages from inbox""" + admin_messages_view = navigator.navigate(MessagesView) + admin_messages_view.delete_all() + + +def _assert_dashboard_counters(navigator, message_count, unread_count): + admin_dashboard_view = navigator.navigate(DashboardView) + assert admin_dashboard_view.msg_count == message_count + assert admin_dashboard_view.unread_msg_count == unread_count + + +def _send_message_from_devel(navigator, subject, body): + devel_compose_view = navigator.navigate(ComposeView) + devel_compose_view.send_message(subject, body) + + +# pylint: disable=too-many-arguments +@pytest.mark.disruptive # test should be mark as disruptive because it deletes the state of inbox messages +@pytest.mark.usefixtures("login", "application", "service", "setup") +def test_message_counter(custom_devel_login, custom_admin_login, account, navigator): + """ + Test: + - Ensure that inbox is empty + - Assert that messages tab in admin dashboard shows 0 messages and none unread message + - Send two e-mails from developer to admin + - Assert that messages tab in admin dashboard shows 2 messages and 2 unread messages + - Read all messages + - Assert that messages tab in admin dashboard shows 2 messages and 0 unread messages + - Delete all messages + - Assert that messages tab in admin dashboard shows 0 messages and 0 unread messages + """ + custom_admin_login(account) + _assert_dashboard_counters(navigator, 0, 0) + + custom_devel_login(account) + _send_message_from_devel(navigator, "subject1", "body1") + _send_message_from_devel(navigator, "subject2", "body2") + + custom_admin_login(account) + _assert_dashboard_counters(navigator, 2, 2) + + admin_messages_view = navigator.navigate(MessagesView) + for link in admin_messages_view.get_first_unread_msg_link_gen(): + link.click() + navigator.navigate(MessagesView) + + _assert_dashboard_counters(navigator, 2, 0) + + admin_messages_view = navigator.navigate(MessagesView) + admin_messages_view.delete_all() + + _assert_dashboard_counters(navigator, 0, 0) diff --git a/testsuite/ui/views/admin/audience/messages.py b/testsuite/ui/views/admin/audience/messages.py index 9c3462bc7..f055676ef 100644 --- a/testsuite/ui/views/admin/audience/messages.py +++ b/testsuite/ui/views/admin/audience/messages.py @@ -1,8 +1,13 @@ """View representations of Messages pages""" +import time +import re + from widgetastic.widget import GenericLocatorWidget, View, Text from widgetastic_patternfly import TextInput -from widgetastic_patternfly4 import Button, PatternflyTable + +from widgetastic_patternfly4 import Button, PatternflyTable, Dropdown +from widgetastic_patternfly4.ouia import Dropdown as OUIADropdown from testsuite.ui.navigation import step from testsuite.ui.views.admin.audience import BaseAudienceView @@ -16,6 +21,52 @@ class MessagesView(BaseAudienceView): table = PatternflyTable("//table[@aria-label='Messages table']") compose_msg_link = GenericLocatorWidget("//*[contains(@href,'/p/admin/messages/outbox/new')]") empty_inbox = Text("//div[text()='Your inbox is empty, there are no new messages.']") + # select_all_checkbox = Checkbox('id="bulk-select"') + select_dropdown = OUIADropdown(component_id="OUIA-Generated-Dropdown-1") + # This dropdown does not have page unique component id + actions_dropdown = Dropdown( + None, locator="//div[@id='pf-random-id-0']//div[@data-ouia-component-id='OUIA-Generated-Dropdown-2']" + ) + delete_dialog_button = Button(locator='//div[@id="colorbox"]//button[contains(text(), "Delete")]') + + def delete_all(self): + """ + Deletes all massages from the inbox + """ + if self.empty_inbox.is_displayed: + return + items = self.select_dropdown.items + select_all_item = [s for s in items if re.match("Select all.*", s)][0] + self.select_dropdown.item_select(select_all_item) # item_select does not have better selector than exact text + self.actions_dropdown.open() + self.actions_dropdown.item_select("Delete") + time.sleep(1) + self.delete_dialog_button.click() + + def get_unread_msg_link(self, subject=None): + """Returns link to the first unread message, None if such message does not exist + :param str subject: Specify unread message, with given subject + """ + links = self.browser.elements("//tr[contains(@class, 'unread')]//td[@data-label='Subject']/a") + if links: + if subject: + for link in links: + if link.text == subject: + return link + else: + return links[0] + return None + + def get_first_unread_msg_link_gen(self): + """ + Returns generator, that returns link to the first unread message until, such message exists. + """ + while True: + link = self.get_unread_msg_link() + if link: + yield link + else: + break def prerequisite(self): return BaseAudienceView diff --git a/testsuite/ui/views/admin/foundation.py b/testsuite/ui/views/admin/foundation.py index 46432194a..ac99474d1 100644 --- a/testsuite/ui/views/admin/foundation.py +++ b/testsuite/ui/views/admin/foundation.py @@ -78,9 +78,22 @@ class DashboardView(BaseAdminView): billing_link = Text('//a[@href="/finance"]') develop_portal_link = Text('//a[@href="/p/admin/cms"]') message_link = Text('//a[@href="/p/admin/messages"]') + unread_messages_count = Text("//li[a[@href='/p/admin/messages']]/span[@class='u-notice']") explore_all_products = Text('//a[@href="/apiconfig/services"]') explore_all_backends = Text('//a[@href="/p/admin/backend_apis"]') + @property + def msg_count(self): + """Return number of messages in the inbox""" + return int(self.message_link.text.split()[0]) + + @property + def unread_msg_count(self): + """Returns number of unread messages""" + if not self.unread_messages_count.is_displayed: + return 0 + return int(self.unread_messages_count.text) + @View.nested # pylint: disable=invalid-name class backends(View): From 6650c222aab56daba290eeae71f87d25bbb0ef1e Mon Sep 17 00:00:00 2001 From: Marek Stastny Date: Tue, 6 Aug 2024 15:01:15 +0200 Subject: [PATCH 2/3] Fix: don't delete previsous messages --- .../mail_and_messages/test_message_counter.py | 59 ++++++++++--------- testsuite/ui/views/admin/audience/messages.py | 22 ++++--- 2 files changed, 44 insertions(+), 37 deletions(-) diff --git a/testsuite/tests/ui/mail_and_messages/test_message_counter.py b/testsuite/tests/ui/mail_and_messages/test_message_counter.py index 776aa1740..dc6cbf65c 100644 --- a/testsuite/tests/ui/mail_and_messages/test_message_counter.py +++ b/testsuite/tests/ui/mail_and_messages/test_message_counter.py @@ -7,57 +7,60 @@ from testsuite.ui.views.devel.messages import ComposeView -@pytest.fixture() -def setup(navigator): - """Deletes all messages from inbox""" - admin_messages_view = navigator.navigate(MessagesView) - admin_messages_view.delete_all() - - -def _assert_dashboard_counters(navigator, message_count, unread_count): +def assert_dashboard_counters(navigator, message_count, unread_count): + """ + Asserts counters in the messages tab in admin dashboard + """ admin_dashboard_view = navigator.navigate(DashboardView) assert admin_dashboard_view.msg_count == message_count assert admin_dashboard_view.unread_msg_count == unread_count -def _send_message_from_devel(navigator, subject, body): +def send_message_from_devel(navigator, subject, body): + """ + Sends the message from the developer portal + """ devel_compose_view = navigator.navigate(ComposeView) devel_compose_view.send_message(subject, body) # pylint: disable=too-many-arguments @pytest.mark.disruptive # test should be mark as disruptive because it deletes the state of inbox messages -@pytest.mark.usefixtures("login", "application", "service", "setup") +@pytest.mark.usefixtures("login", "application", "service") def test_message_counter(custom_devel_login, custom_admin_login, account, navigator): """ Test: - - Ensure that inbox is empty - - Assert that messages tab in admin dashboard shows 0 messages and none unread message + - Take a note of number of messages (msg_count) and unread messages (unread_count) in messages tab in + admin dashboard - Send two e-mails from developer to admin - - Assert that messages tab in admin dashboard shows 2 messages and 2 unread messages - - Read all messages - - Assert that messages tab in admin dashboard shows 2 messages and 0 unread messages - - Delete all messages - - Assert that messages tab in admin dashboard shows 0 messages and 0 unread messages + - Assert that messages tab in admin dashboard shows msg_count + 2 messages and unread_count + 2 unread messages + - Read two new messages + - Assert that messages tab in admin dashboard msg_count + 2 messages and unread_count + 2 unread messages + - Delete two new messages + - Assert that messages tab in admin dashboard shows msg_count messages and unread_count unread messages """ - custom_admin_login(account) - _assert_dashboard_counters(navigator, 0, 0) + admin_dashboard_view = navigator.navigate(DashboardView) + start_msg_count = admin_dashboard_view.msg_count + start_unread_msg_count = admin_dashboard_view.unread_msg_count custom_devel_login(account) - _send_message_from_devel(navigator, "subject1", "body1") - _send_message_from_devel(navigator, "subject2", "body2") + send_message_from_devel(navigator, "subject1", "body1") + send_message_from_devel(navigator, "subject2", "body2") custom_admin_login(account) - _assert_dashboard_counters(navigator, 2, 2) + assert_dashboard_counters(navigator, start_msg_count + 2, start_unread_msg_count + 2) admin_messages_view = navigator.navigate(MessagesView) - for link in admin_messages_view.get_first_unread_msg_link_gen(): - link.click() - navigator.navigate(MessagesView) + link = admin_messages_view.get_unread_msg_link(subject="subject1") + link.click() + admin_messages_view = navigator.navigate(MessagesView) + link = admin_messages_view.get_unread_msg_link(subject="subject2") + link.click() - _assert_dashboard_counters(navigator, 2, 0) + assert_dashboard_counters(navigator, start_msg_count + 2, start_unread_msg_count + 0) admin_messages_view = navigator.navigate(MessagesView) - admin_messages_view.delete_all() + admin_messages_view.delete_message("subject1") + admin_messages_view.delete_message("subject2") - _assert_dashboard_counters(navigator, 0, 0) + assert_dashboard_counters(navigator, start_msg_count + 0, start_unread_msg_count + 0) diff --git a/testsuite/ui/views/admin/audience/messages.py b/testsuite/ui/views/admin/audience/messages.py index f055676ef..319dd9737 100644 --- a/testsuite/ui/views/admin/audience/messages.py +++ b/testsuite/ui/views/admin/audience/messages.py @@ -21,7 +21,6 @@ class MessagesView(BaseAudienceView): table = PatternflyTable("//table[@aria-label='Messages table']") compose_msg_link = GenericLocatorWidget("//*[contains(@href,'/p/admin/messages/outbox/new')]") empty_inbox = Text("//div[text()='Your inbox is empty, there are no new messages.']") - # select_all_checkbox = Checkbox('id="bulk-select"') select_dropdown = OUIADropdown(component_id="OUIA-Generated-Dropdown-1") # This dropdown does not have page unique component id actions_dropdown = Dropdown( @@ -43,19 +42,24 @@ def delete_all(self): time.sleep(1) self.delete_dialog_button.click() + def delete_message(self, subject): + """ + Deletes first message with given subject + """ + delete_button = self.browser.elements(f"//table[@id='messages']//tr[descendant::a[text()='{subject}']]//button") + if delete_button: + delete_button[0].click() + def get_unread_msg_link(self, subject=None): """Returns link to the first unread message, None if such message does not exist :param str subject: Specify unread message, with given subject """ links = self.browser.elements("//tr[contains(@class, 'unread')]//td[@data-label='Subject']/a") - if links: - if subject: - for link in links: - if link.text == subject: - return link - else: - return links[0] - return None + if not links: + return None + if subject: + links = [link for link in links if link.text == subject] + return links[0] def get_first_unread_msg_link_gen(self): """ From a4026b0ee2188405db64b3fc29a14d1e914e2f58 Mon Sep 17 00:00:00 2001 From: Marek Stastny Date: Thu, 28 Nov 2024 09:43:56 +0100 Subject: [PATCH 3/3] Use patternfly table --- .../mail_and_messages/test_message_counter.py | 9 +++---- testsuite/ui/views/admin/audience/messages.py | 27 +++++++++---------- 2 files changed, 16 insertions(+), 20 deletions(-) diff --git a/testsuite/tests/ui/mail_and_messages/test_message_counter.py b/testsuite/tests/ui/mail_and_messages/test_message_counter.py index dc6cbf65c..e1531dc18 100644 --- a/testsuite/tests/ui/mail_and_messages/test_message_counter.py +++ b/testsuite/tests/ui/mail_and_messages/test_message_counter.py @@ -25,7 +25,6 @@ def send_message_from_devel(navigator, subject, body): # pylint: disable=too-many-arguments -@pytest.mark.disruptive # test should be mark as disruptive because it deletes the state of inbox messages @pytest.mark.usefixtures("login", "application", "service") def test_message_counter(custom_devel_login, custom_admin_login, account, navigator): """ @@ -51,16 +50,16 @@ def test_message_counter(custom_devel_login, custom_admin_login, account, naviga assert_dashboard_counters(navigator, start_msg_count + 2, start_unread_msg_count + 2) admin_messages_view = navigator.navigate(MessagesView) - link = admin_messages_view.get_unread_msg_link(subject="subject1") + link = admin_messages_view.get_unread_msg_link(Subject="subject1", From=account.entity_name) link.click() admin_messages_view = navigator.navigate(MessagesView) - link = admin_messages_view.get_unread_msg_link(subject="subject2") + link = admin_messages_view.get_unread_msg_link(Subject="subject2", From=account.entity_name) link.click() assert_dashboard_counters(navigator, start_msg_count + 2, start_unread_msg_count + 0) admin_messages_view = navigator.navigate(MessagesView) - admin_messages_view.delete_message("subject1") - admin_messages_view.delete_message("subject2") + admin_messages_view.delete_message(Subject="subject1", From=account.entity_name) + admin_messages_view.delete_message(Subject="subject2", From=account.entity_name) assert_dashboard_counters(navigator, start_msg_count + 0, start_unread_msg_count + 0) diff --git a/testsuite/ui/views/admin/audience/messages.py b/testsuite/ui/views/admin/audience/messages.py index 319dd9737..32088790f 100644 --- a/testsuite/ui/views/admin/audience/messages.py +++ b/testsuite/ui/views/admin/audience/messages.py @@ -1,6 +1,5 @@ """View representations of Messages pages""" -import time import re from widgetastic.widget import GenericLocatorWidget, View, Text @@ -39,27 +38,25 @@ def delete_all(self): self.select_dropdown.item_select(select_all_item) # item_select does not have better selector than exact text self.actions_dropdown.open() self.actions_dropdown.item_select("Delete") - time.sleep(1) + self.delete_dialog_button.wait_displayed(timeout="1s") self.delete_dialog_button.click() - def delete_message(self, subject): + def delete_message(self, **kwargs): """ - Deletes first message with given subject + Deletes first message with which matches given text values in columns + e.g. delete_message(Subject='subject1, From='user1') will delete message with subject subject1 from + user user1 if such message exists and is not already deleted. """ - delete_button = self.browser.elements(f"//table[@id='messages']//tr[descendant::a[text()='{subject}']]//button") - if delete_button: - delete_button[0].click() + row = self.table.row(**kwargs) + if row.From.text != "(deleted)": + row[4].click() - def get_unread_msg_link(self, subject=None): + def get_unread_msg_link(self, **kwargs): """Returns link to the first unread message, None if such message does not exist - :param str subject: Specify unread message, with given subject + **kwargs: Allows filter rows by values in the columns. + Keys are names of the columns, values are text values in the specified column. """ - links = self.browser.elements("//tr[contains(@class, 'unread')]//td[@data-label='Subject']/a") - if not links: - return None - if subject: - links = [link for link in links if link.text == subject] - return links[0] + return self.table.row(_row__attr=("class", "unread"), **kwargs).Subject.browser.element("./a") def get_first_unread_msg_link_gen(self): """