From 39300589f2aa2cda6efcb8cfba22b7726f5ba575 Mon Sep 17 00:00:00 2001 From: Emil Ghitta Date: Wed, 11 Dec 2024 12:13:25 +0200 Subject: [PATCH] - Expand playwright coverage to anti-spam measures in test_anti_spam_measures.py by adding two tests (one that checks for the presence of the anti_spam banner across different sumo pages and one for verifying that valid TLD-s posted as question replies are automatically flagged as spam) - Adding anti-spam measures test markers to pytest.ini - Adding flagged spam question reply banner text to question_page_messages.py - Refactoring the question_page locators and adding functions to the newly added locators related to the spam banner locators. - Adding the antiSpamTests to the playwright.yml --- .github/workflows/playwright.yml | 3 +- .../AAQ_messages/question_page_messages.py | 1 + .../messages/common_elements_messages.py | 4 + .../posted_question_pages/questions_page.py | 419 ++++++++++-------- .../common_elements/common_web_elements.py | 18 + playwright_tests/pages/sumo_pages.py | 5 +- playwright_tests/pytest.ini | 1 + playwright_tests/test_data/general_data.json | 9 + .../aaq_tests/test_anti_spam_measures.py | 125 ++++++ .../aaq_tests/test_posted_questions.py | 1 - 10 files changed, 409 insertions(+), 177 deletions(-) create mode 100644 playwright_tests/messages/common_elements_messages.py create mode 100644 playwright_tests/pages/common_elements/common_web_elements.py create mode 100644 playwright_tests/tests/ask_a_question_tests/aaq_tests/test_anti_spam_measures.py diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml index 5dc72dd168c..abdb1930a9a 100644 --- a/.github/workflows/playwright.yml +++ b/.github/workflows/playwright.yml @@ -39,6 +39,7 @@ on: - exploreByTopics - searchTests - userGroupsTests + - antiSpamTests env: TEST_ACCOUNT_12: ${{secrets.AUTOMATION_TEST_ACCOUNT_12}} @@ -104,7 +105,7 @@ jobs: if: success() || failure() && steps.create-sessions.outcome == 'success' run: | declare dispatch_test_suite="${{inputs.TestSuite}}" - declare all_test_suites=("homePageTests" "topNavbarTests" "footerSectionTests" "contributePagesTests" "messagingSystem" "messagingSystemCleanup" "userContributionTests" "userProfile" "userSettings" "editUserProfileTests" "userQuestions" "contactSupportPage" "productSolutionsPage" "productSupportPage" "productTopicsPage" "aaqPage" "postedQuestions" "kbProductsPage" "kbArticleCreationAndAccess" "beforeThreadTests" "articleThreads" "afterThreadTests" "kbArticleShowHistory" "recentRevisionsDashboard" "kbDashboard" "kbRestrictedVisibility" "kbArticleTranslation" "exploreByTopics" "searchTests" "userGroupsTests") + declare all_test_suites=("homePageTests" "topNavbarTests" "footerSectionTests" "contributePagesTests" "messagingSystem" "messagingSystemCleanup" "userContributionTests" "userProfile" "userSettings" "editUserProfileTests" "userQuestions" "contactSupportPage" "productSolutionsPage" "productSupportPage" "productTopicsPage" "aaqPage" "postedQuestions" "kbProductsPage" "kbArticleCreationAndAccess" "beforeThreadTests" "articleThreads" "afterThreadTests" "kbArticleShowHistory" "recentRevisionsDashboard" "kbDashboard" "kbRestrictedVisibility" "kbArticleTranslation" "exploreByTopics" "searchTests" "userGroupsTests", "antiSpamTests") if [ "$dispatch_test_suite" == "All" ] || [ "${{ github.event_name}}" == "schedule" ] ; then for test in "${all_test_suites[@]}"; do if ! poetry run pytest -m ${test} --numprocesses 6 --browser ${{ env.BROWSER }} --reruns 2; then diff --git a/playwright_tests/messages/ask_a_question_messages/AAQ_messages/question_page_messages.py b/playwright_tests/messages/ask_a_question_messages/AAQ_messages/question_page_messages.py index 51561c73ef6..e029eb9562a 100644 --- a/playwright_tests/messages/ask_a_question_messages/AAQ_messages/question_page_messages.py +++ b/playwright_tests/messages/ask_a_question_messages/AAQ_messages/question_page_messages.py @@ -24,3 +24,4 @@ class QuestionPageMessages: "-mozilla-tech-support-scams") TRY_THESE_MANUAL_STEPS_LINK = ("https://support.mozilla.org/kb/use-troubleshooting" "-information-page-fix-firefox") + SPAM_FLAGGED_REPLY = "A moderator must manually approve your post before it will be visible." diff --git a/playwright_tests/messages/common_elements_messages.py b/playwright_tests/messages/common_elements_messages.py new file mode 100644 index 00000000000..41f99710a20 --- /dev/null +++ b/playwright_tests/messages/common_elements_messages.py @@ -0,0 +1,4 @@ +class CommonElementsMessages: + AVOID_SCAM_BANNER_TEXT = ("Avoid support scams. We will never ask you to call or text a phone " + "number or share personal information. Please report suspicious " + "activity using the “Report Abuse” option.") diff --git a/playwright_tests/pages/ask_a_question/posted_question_pages/questions_page.py b/playwright_tests/pages/ask_a_question/posted_question_pages/questions_page.py index ebb0322bb8d..01b452452cd 100644 --- a/playwright_tests/pages/ask_a_question/posted_question_pages/questions_page.py +++ b/playwright_tests/pages/ask_a_question/posted_question_pages/questions_page.py @@ -6,25 +6,26 @@ class QuestionPage(BasePage): # "Posted successfully" green banner locators. - __posted_questions_success_banner_message = "//ul[@class='user-messages']/li/p" - __posted_questions_success_banner_my_questions_link = "//ul[@class='user-messages']/li/p/a" - __posted_questions_success_banner_close_button = "//ul[@class='user-messages']/li/button" - - # Lock this thread banner locators. - __lock_this_thread_banner = "//div[@class='notice mzp-c-notification-bar mzp-t-click']/p" - __lock_this_thread_banner_link = ("//div[@class='notice mzp-c-notification-bar " - "mzp-t-click']/p/a") - - # Marked as spam banner locators. - __marked_as_spam_banner = "//p[@class='is-spam']" - - # Solved problem banner - __problem_solved_banner_text = "//li[@class='mzp-c-notification-bar mzp-t-success']/p" - __problem_solved_reply_text = "//div[@class='reply']/p" - __problem_solved_reply_section = "//div[@class='solution card elevation-00']" - __problem_solved_reply_section_header = "//h4[@class='is-solution']" - __problem_solved_reply_reply_link = "//div[@class='reply']/a" - __undo_solves_problem = "//input[@value='Undo']" + BANNER_LOCATORS = { + "posted_questions_success_banner_message": "//ul[@class='user-messages']/li/p", + "posted_questions_success_banner_my_questions_link": "//ul[@class='user-messages']/li/p/a", + "posted_questions_success_banner_close_button": "//ul[@class='user-messages']/li/button", + "reply_flagged_as_spam_banner": "//li[@class='mzp-c-notification-bar mzp-t-warning']/p", + "marked_as_spam_banner": "//p[@class='is-spam']", + "lock_this_thread_banner": "//div[@class='notice mzp-c-notification-bar mzp-t-click']/p", + "lock_this_thread_banner_link": ("//div[@class='notice mzp-c-notification-bar " + "mzp-t-click']/p/a"), + "problem_solved_banner_text": "//li[@class='mzp-c-notification-bar mzp-t-success']/p" + } + + # Problem solved locators. + PROBLEM_SOLVED_LOCATORS = { + "problem_solved_reply_text": "//div[@class='reply']/p", + "problem_solved_reply_section": "//div[@class='solution card elevation-00']", + "problem_solved_reply_section_header": "//h4[@class='is-solution']", + "problem_solved_reply_reply_link": "//div[@class='reply']/a", + "undo_solves_problem": "//input[@value='Undo']" + } # Question locators. QUESTION_LOCATORS = { @@ -35,127 +36,169 @@ class QuestionPage(BasePage): } # Progress bar locators. - __complete_progress_items_label = ("//li[@class='progress--item is-complete']//span[" - "@class='progress--label']") + PROGRESS_BAR_LOCATORS = { + "complete_progress_items_label": ("//li[@class='progress--item is-complete']//span" + "[@class='progress--label']") + } # Breadcrumbs locators. - __aaq_page_breadcrumbs = "//ol[@id='breadcrumbs']/li/a" + BREADCRUMB_LOCATORS = { + "aaq_page_breadcrumbs": "//ol[@id='breadcrumbs']/li/a" + } # Question details locators. - __question_details_button = "//button[@aria-controls='question-details']" - __more_system_details_modal = "//div[normalize-space(@class)='mzp-c-modal']" - __more_system_details_option = "//a[@id='show-more-details']" - __close_additional_system_details_button = "//div[@class='mzp-c-modal-close']/button" - __user_agent_information = "//div[@class='about-support']//li" - __question_section = "//article/div[@class='question']" + QUESTION_DETAILS_LOCATORS = { + "question_details_button": "//button[@aria-controls='question-details']", + "more_system_details_modal": "//div[normalize-space(@class)='mzp-c-modal']", + "more_system_details_option": "//a[@id='show-more-details']", + "close_additional_system_details_button": "//div[@class='mzp-c-modal-close']/button", + "user_agent_information": "//div[@class='about-support']//li", + "question_section": "//article/div[@class='question']" + } # Searchbar locators. - __search_support_searchbar = "//form[@id='support-search-sidebar']/input" - __search_support_search_button = "//form[@id='support-search-sidebar']/button" + SEARCHBAR_LOCATORS = { + "search_support_searchbar": "//form[@id='support-search-sidebar']/input", + "search_support_search_button": "//form[@id='support-search-sidebar']/button" + } # Still need help widget locators. - __still_need_help_ask_now_button = "//div[contains(@class,'aaq-widget')]//a" + STILL_NEED_HELP_WIDGET_LOCATORS = { + "still_need_help_ask_now_button": "//div[contains(@class,'aaq-widget')]//a" + } # Question Tools locators. - __edit_this_question_option = "//ul[@id='related-content']/li[@class='edit']/a" - __stop_email_updates_option = "//ul[@id='related-content']/li[@class='email']/a" - __subscribe_to_feed_option = "//ul[@id='related-content']/li[@class='rss']/a" - __delete_this_question_option = "//ul[@id='related-content']//a[@class='delete']" - __lock_this_question_option = "//a[@data-form='lock-form']" - __archive_this_question_option = "//a[@data-form='archive-form']" - __system_details_options = "//div[@id='system-details']/ul[@class='system']/li" - __mark_as_spam_option = "//ul[@id='related-content']//form[@class='spam-form cf']/a" + QUESTION_TOOLS_LOCATORS = { + "edit_this_question_option": "//ul[@id='related-content']/li[@class='edit']/a", + "stop_email_updates_option": "//ul[@id='related-content']/li[@class='email']/a", + "subscribe_to_feed_option": "//ul[@id='related-content']/li[@class='rss']/a", + "delete_this_question_option": "//ul[@id='related-content']//a[@class='delete']", + "lock_this_question_option": "//a[@data-form='lock-form']", + "archive_this_question_option": "//a[@data-form='archive-form']", + "system_details_options": "//div[@id='system-details']/ul[@class='system']/li", + "mark_as_spam_option": "//ul[@id='related-content']//form[@class='spam-form cf']/a" + } # Tags section locators. - __question_tags_options_for_non_moderators = "//li[@class='tag']/a" - __question_tags_options_for_moderators = "//div[@class='ts-control']/div" - __add_a_tag_input_field = "//input[contains(@id, 'tag-select')]" + TAGS_SECTION_LOCATORS = { + "question_tags_options_for_non_moderators": "//li[@class='tag']/a", + "question_tags_options_for_moderators": "//div[@class='ts-control']/div", + "add_a_tag_input_field": "//input[contains(@id, 'tag-select')]" + } # Post a reply section locators. - __post_a_reply_section_heading = "//h3[@class='sumo-card-heading']" - __post_a_reply_textarea = "//textarea[@id='id_content']" - __post_a_reply_textarea_bold_button = "//button[@title='Bold']" - __post_a_reply_textarea_italic_button = "//button[@title='Italic']" - __post_a_reply_textarea_link_button = "//button[@title='Insert a link...']" - __post_a_reply_textarea_numbered_list_button = "//button[@title='Numbered List']" - __post_a_reply_textarea_bulleted_list_button = "//button[@title='Bulleted List']" - __last_reply_by = "//span[@class='forum--meta-val visits no-border']" + POST_A_REPLY_SECTION_LOCATORS = { + "post_a_reply_section_heading": "//h3[@class='sumo-card-heading']", + "post_a_reply_textarea": "//textarea[@id='id_content']", + "post_a_reply_textarea_bold_button": "//button[@title='Bold']", + "post_a_reply_textarea_italic_button": "//button[@title='Italic']", + "post_a_reply_textarea_link_button": "//button[@title='Insert a link...']", + "post_a_reply_textarea_numbered_list_button": "//button[@title='Numbered List']", + "post_a_reply_textarea_bulleted_list_button": "//button[@title='Bulleted List']", + "last_reply_by": "//span[@class='forum--meta-val visits no-border']" + } # Common Responses locators. - __common_responses_option = "//a[@title='Common responses']" - __common_responses_search_field = "//input[@id='filter-responses-field']" - __common_responses_modal_close_button = "//div[@id='media-modal']/a" - __common_responses_categories_options = "//div[@id='responses-area']//li" - __common_responses_responses_options = ("//ul[@class='sidebar-nav']/li[@class='response' and " - "not(@style='display: none;')]") - __common_responses_no_cat_selected = "//h4[@class='nocat-label']" - __common_responses_switch_to_mode = "//div[@id='response-content-area']//button" - __common_responses_response_preview = ("//p[@class='response-preview-rendered']//div[" - "@class='main-content']/div[@class='content']") - __common_responses_textarea_field = "//textarea[@id='response-content']" - __common_responses_insert_response_button = "//button[@id='insert-response']" - __common_responses_cancel_button = "//div[@id='response-submit-area']/a" + COMMON_RESPONSES_LOCATORS = { + "common_responses_option": "//a[@title='Common responses']", + "common_responses_search_field": "//input[@id='filter-responses-field']", + "common_responses_modal_close_button": "//div[@id='media-modal']/a", + "common_responses_categories_options": "//div[@id='responses-area']//li", + "common_responses_responses_options": ("//ul[@class='sidebar-nav']/li[@class='response' " + "and not(@style='display: none;')]"), + "common_responses_no_cat_selected": "//h4[@class='nocat-label']", + "common_responses_switch_to_mode": "//div[@id='response-content-area']//button", + "common_responses_response_preview": ("//p[@class='response-preview-rendered']//div[" + "@class='main-content']/div[@class='content']"), + "common_responses_textarea_field": "//textarea[@id='response-content']", + "common_responses_insert_response_button": "//button[@id='insert-response']", + "common_responses_cancel_button": "//div[@id='response-submit-area']/a" + } # I have this problem too locators. - __i_have_this_problem_too_button = "//div[@class='me-too']//button" - __i_have_this_problem_too_counter = "//span[@class='forum--meta-val have-problem']" + I_HAVE_THIS_PROBLEM_TOO_LOCATORS = { + "i_have_this_problem_too_button": "//div[@class='me-too']//button", + "i_have_this_problem_too_counter": "//span[@class='forum--meta-val have-problem']" + } # Needs more information from the user locators. - __needs_more_information_from_the_user_checkbox = "//input[@id='id_needs_info']" - __more_information_panel_header = ("//section[@id='more-system-details']//h3[contains(text()," - "'More Information')]") + NEEDS_MORE_INFORMATION_LOCATORS = { + "needs_more_information_from_the_user_checkbox": "//input[@id='id_needs_info']", + "more_information_panel_header": ("//section[@id='more-system-details']//h3[" + "contains(text(),'More Information')]") + } # Attached image locators. - __attached_image = "//a[@class='image']/img" - __add_image_button = "//div[@class='field add-attachment']" + ATTACHED_IMAGE_LOCATORS = { + "attached_image": "//a[@class='image']/img", + "add_image_button": "//div[@class='field add-attachment']" + } # Preview Reply button locators. - __preview_reply_button = "//input[@id='preview']" + PREVIEW_REPLY_LOCATORS = { + "preview_reply_button": "//input[@id='preview']" + } # Post Reply button locators. - __post_reply_button = "//button[normalize-space(text())='Post Reply']" + POST_REPLY_LOCATORS = { + "post_reply_button": "//button[normalize-space(text())='Post Reply']" + } # Delete question locators. - __delete_question_delete_button = "//input[@value='Delete']" - __delete_question_cancel_button = "//a[contains(text(),'Cancel')]" + DELETE_QUESTION_LOCATORS = { + "delete_question_delete_button": "//input[@value='Delete']", + "delete_question_cancel_button": "//a[contains(text(),'Cancel')]" + } # Report abuse section. - __report_abuse_submit_button = "//div[@class='mzp-c-modal-inner']//button[@type='submit']" - __report_abuse_textarea = "//div[@class='mzp-c-modal-inner']//textarea" - __report_abuse_flagged_this_content_message = ("//div[@class='mzp-c-modal-inner']//span[" - "@class='message']") - __report_abuse_modal_close_button = ("//div[@class='mzp-c-modal-inner']//button[" - "@class='mzp-c-modal-button-close']") + REPORT_ABUSE_LOCATORS = { + "report_abuse_submit_button": "//div[@class='mzp-c-modal-inner']//button[@type='submit']", + "report_abuse_textarea": "//div[@class='mzp-c-modal-inner']//textarea", + "report_abuse_flagged_this_content_message": ("//div[@class='mzp-c-modal-inner']//span[" + "@class='message']"), + "report_abuse_modal_close_button": ("//div[@class='mzp-c-modal-inner']//button[" + "@class='mzp-c-modal-button-close']") + } # Signed out card locators. - __log_in_to_your_account_signed_out_card_option = ("//div[@class='question-tools " - "ask-a-question card is-shaded']/p/a[" - "text()='log in to your account']") - __start_a_new_question_signed_out_card_option = ("//div[@class='question-tools ask-a-question " - "card is-shaded']/p/a[text()='start a new " - "question']") - __ask_a_question_signed_out_card_option = ("//div[@class='question-tools ask-a-question card " - "is-shaded']//a[text()='Ask a question']") - __i_have_this_problem_too_signed_out_card_option = ("//div[@class='question-tools " - "ask-a-question card " - "is-shaded']//button[text()='I have this " - "problem, too']") + SIGNED_OUT_CARD_LOCATORS = { + "log_in_to_your_account_signed_out_card_option": ("//div[@class='question-tools " + "ask-a-question card is-shaded']/p/a[" + "text()='log in to your account']"), + "start_a_new_question_signed_out_card_option": ("//div[@class='question-tools " + "ask-a-question card is-shaded']/p/a" + "[text()='start a new question']"), + "ask_a_question_signed_out_card_option": ("//div[@class='question-tools ask-a-question " + "card is-shaded']//a[text()='Ask a question']"), + "i_have_this_problem_too_signed_out_card_option": ("//div[@class='question-tools " + "ask-a-question card is-shaded']//" + "button[text()='I have this problem, " + "too']") + } def __init__(self, page: Page): super().__init__(page) + # Spam marked banner actions. + def get_text_of_spam_marked_banner(self) -> str: + return self._get_text_of_element(self.BANNER_LOCATORS["reply_flagged_as_spam_banner"]) + + def is_spam_marked_banner_displayed(self) -> bool: + return self._is_element_visible(self.BANNER_LOCATORS["reply_flagged_as_spam_banner"]) + # Report abuse actions. def click_abuse_modal_close_button(self): - self._click(self.__report_abuse_modal_close_button) + self._click(self.REPORT_ABUSE_LOCATORS["report_abuse_modal_close_button"]) def get_successful_flagged_this_content_text(self) -> str: - return self._get_text_of_element(self.__report_abuse_flagged_this_content_message) + return self._get_text_of_element( + self.REPORT_ABUSE_LOCATORS["report_abuse_flagged_this_content_message"]) def add_text_to_report_abuse_textarea(self, text: str): - self._fill(self.__report_abuse_textarea, text) + self._fill(self.REPORT_ABUSE_LOCATORS["report_abuse_textarea"], text) def click_on_report_abuse_submit_button(self): - self._click(self.__report_abuse_submit_button) + self._click(self.REPORT_ABUSE_LOCATORS["report_abuse_submit_button"]) # Breadcrumbs actions. def get_current_breadcrumb_locator(self, question_title: str) -> Locator: @@ -167,29 +210,31 @@ def click_on_breadcrumb(self, breadcrumb_xpath: str): # Get email updates actions. def get_email_updates_option(self) -> Locator: - return self._get_element_locator(self.__stop_email_updates_option) + return self._get_element_locator(self.QUESTION_TOOLS_LOCATORS["stop_email_updates_option"]) # Problem solved actions. def get_problem_solved_section_header_text(self) -> str: - return self._get_text_of_element(self.__problem_solved_reply_section_header) + return self._get_text_of_element( + self.PROBLEM_SOLVED_LOCATORS["problem_solved_reply_section_header"]) def click_on_undo_button(self): - self._click(self.__undo_solves_problem) + self._click(self.PROBLEM_SOLVED_LOCATORS["undo_solves_problem"]) def get_undo_button_locator(self) -> Locator: - return self._get_element_locator(self.__undo_solves_problem) + return self._get_element_locator(self.PROBLEM_SOLVED_LOCATORS["undo_solves_problem"]) def click_read_this_answer_in_context_link(self): - self._click(self.__problem_solved_reply_reply_link) + self._click(self.PROBLEM_SOLVED_LOCATORS["problem_solved_reply_reply_link"]) def get_chosen_solution_text(self) -> str: - return self._get_text_of_element(self.__problem_solved_reply_text) + return self._get_text_of_element(self.PROBLEM_SOLVED_LOCATORS["problem_solved_reply_text"]) def get_chosen_solution_section_locator(self) -> Locator: - return self._get_element_locator(self.__problem_solved_reply_section) + return self._get_element_locator( + self.PROBLEM_SOLVED_LOCATORS["problem_solved_reply_section"]) def get_solved_problem_banner_text(self) -> str: - return self._get_text_of_element(self.__problem_solved_banner_text) + return self._get_text_of_element(self.BANNER_LOCATORS["problem_solved_banner_text"]) def get_solved_the_problem_button_locator(self, target_reply_id: str) -> Locator: return self._get_element_locator(f"//div[@id='{target_reply_id}']/" @@ -203,23 +248,25 @@ def get_chosen_solution_reply_message_locator(self, reply_id: str) -> Locator: # I have this problem too actions. def get_i_have_this_problem_too_locator(self) -> Locator: - return self._get_element_locator(self.__i_have_this_problem_too_button) + return self._get_element_locator( + self.I_HAVE_THIS_PROBLEM_TOO_LOCATORS["i_have_this_problem_too_button"]) def click_i_have_this_problem_too_button(self): - self._click(self.__i_have_this_problem_too_button) + self._click(self.I_HAVE_THIS_PROBLEM_TOO_LOCATORS["i_have_this_problem_too_button"]) def get_i_have_this_problem_too_counter(self) -> int: - return int(self._get_text_of_element(self.__i_have_this_problem_too_counter)) + return int(self._get_text_of_element( + self.I_HAVE_THIS_PROBLEM_TOO_LOCATORS["i_have_this_problem_too_counter"])) def get_last_reply_by_text(self) -> str: - return self._get_text_of_element(self.__last_reply_by) + return self._get_text_of_element(self.POST_A_REPLY_SECTION_LOCATORS["last_reply_by"]) # Page content actions. def get_question_header(self) -> str: return self._get_text_of_element(self.QUESTION_LOCATORS["questions_header"]) def click_last_reply_by(self): - self._click(self.__last_reply_by) + self._click(self.POST_A_REPLY_SECTION_LOCATORS["last_reply_by"]) def get_question_body(self) -> str: return self._get_text_of_element(self.QUESTION_LOCATORS["question_body"]) @@ -228,7 +275,8 @@ def get_question_author_name(self) -> str: return self._get_text_of_element(self.QUESTION_LOCATORS["question_author"]) def get_question_id(self) -> str: - return self._get_element_attribute_value(self.__question_section, 'id') + return self._get_element_attribute_value( + self.QUESTION_DETAILS_LOCATORS["question_section"], 'id') def get_modified_question_locator(self) -> Locator: return self._get_element_locator(self.QUESTION_LOCATORS["modified_question_section"]) @@ -237,18 +285,18 @@ def get_modified_by_text(self) -> str: return self._get_text_of_element(self.QUESTION_LOCATORS["modified_question_section"]) def get_add_image_section_locator(self) -> Locator: - return self._get_element_locator(self.__add_image_button) + return self._get_element_locator(self.ATTACHED_IMAGE_LOCATORS["add_image_button"]) def click_on_my_questions_banner_option(self): - self._click(self.__posted_questions_success_banner_my_questions_link) + self._click(self.BANNER_LOCATORS["posted_questions_success_banner_my_questions_link"]) def click_on_solves_the_problem_button(self, target_reply_id: str): self._click(f"//div[@id='{target_reply_id}']/following-sibling::aside//" f"input[@type='submit']") def is_post_reply_button_visible(self) -> ElementHandle: - self._wait_for_selector(self.__post_reply_button) - return self._get_element_handle(self.__post_reply_button) + self._wait_for_selector(self.POST_REPLY_LOCATORS["post_reply_button"]) + return self._get_element_handle(self.POST_REPLY_LOCATORS["post_reply_button"]) def click_on_the_reply_author(self, reply_id: str): self._click(f"//div[@id='{reply_id}']//a[@class='author-name']") @@ -271,21 +319,21 @@ def get_displayed_user_title_of_question_reply(self, reply_id: str) -> str: # Question tag actions. def get_question_tag_options(self, is_moderator: bool) -> list[str]: return [tag.replace("\n×", "") for tag in self._get_text_of_elements( - self.__question_tags_options_for_moderators if is_moderator else self - .__question_tags_options_for_non_moderators - )] + self. + TAGS_SECTION_LOCATORS["question_tags_options_for_moderators"] if is_moderator else self + .TAGS_SECTION_LOCATORS["question_tags_options_for_non_moderators"])] def get_remove_tag_button_locator(self, tag_name: str) -> Locator: return self._get_element_locator(f"//div[@class='ts-control']/div[normalize-space(" f"text())='{tag_name}']/a[@class='remove']") def add_text_to_add_a_tag_input_field(self, text: str): - self._fill(self.__add_a_tag_input_field, text) + self._fill(self.TAGS_SECTION_LOCATORS["add_a_tag_input_field"], text) self._wait_for_given_timeout(2000) - self._press_a_key(self.__add_a_tag_input_field, "Enter") + self._press_a_key(self.TAGS_SECTION_LOCATORS["add_a_tag_input_field"], "Enter") def get_add_a_tag_input_field(self) -> Locator: - return self._get_element_locator(self.__add_a_tag_input_field) + return self._get_element_locator(self.TAGS_SECTION_LOCATORS["add_a_tag_input_field"]) def click_on_a_certain_tag(self, tag_name: str): self._click(f"//li[@class='tag']//a[text()='{tag_name}']", @@ -301,33 +349,34 @@ def click_on_tag_remove_button(self, tag_name: str): # Attached image actions. def get_attached_image(self) -> Locator: - return self._get_element_locator(self.__attached_image) + return self._get_element_locator(self.ATTACHED_IMAGE_LOCATORS["attached_image"]) # Question more information actions. def get_more_information_with_text_locator(self, text: str) -> Locator: return self._get_element_locator(f"//div[@class='about-support']/p[text()='{text}']") def get_question_details_button_locator(self) -> Locator: - return self._get_element_locator(self.__question_details_button) + return self._get_element_locator(self.QUESTION_DETAILS_LOCATORS["question_details_button"]) def get_more_information_locator(self) -> Locator: - return self._get_element_locator(self.__more_information_panel_header) + return self._get_element_locator( + self.NEEDS_MORE_INFORMATION_LOCATORS["more_information_panel_header"]) def get_user_agent_information(self) -> str: - self._wait_for_selector(self.__more_system_details_modal) - return self._get_text_of_element(self.__user_agent_information) + self._wait_for_selector(self.QUESTION_DETAILS_LOCATORS["more_system_details_modal"]) + return self._get_text_of_element(self.QUESTION_DETAILS_LOCATORS["user_agent_information"]) def get_system_details_information(self) -> list[str]: - return self._get_text_of_elements(self.__system_details_options) + return self._get_text_of_elements(self.QUESTION_TOOLS_LOCATORS["system_details_options"]) def click_on_question_details_button(self): - self._click(self.__question_details_button) + self._click(self.QUESTION_DETAILS_LOCATORS["question_details_button"]) def click_on_more_system_details_option(self): - self._click(self.__more_system_details_option) + self._click(self.QUESTION_DETAILS_LOCATORS["more_system_details_option"]) def click_on_the_additional_system_panel_close(self): - self._click(self.__close_additional_system_details_button) + self._click(self.QUESTION_DETAILS_LOCATORS["close_additional_system_details_button"]) def get_reply_section_locator(self, answer_id: str) -> Locator: return self._get_element_locator(f"//div[@id='{answer_id}']") @@ -375,23 +424,26 @@ def get_delete_this_post_reply_locator(self, answer_id: str) -> Locator: f"a[text()='Delete this post']") def click_on_cancel_delete_button(self): - self._click(self.__delete_question_cancel_button) + self._click(self.DELETE_QUESTION_LOCATORS["delete_question_cancel_button"]) # Post a reply actions. def add_text_to_post_a_reply_textarea(self, text: str): - self._fill(self.__post_a_reply_textarea, text) + self._fill(self.POST_A_REPLY_SECTION_LOCATORS["post_a_reply_textarea"], text) def type_inside_the_post_a_reply_textarea(self, text: str): - self._type(self.__post_a_reply_textarea, text, 100) + self._type(self.POST_A_REPLY_SECTION_LOCATORS["post_a_reply_textarea"], text, 100) def get_post_a_reply_textarea_locator(self) -> Locator: - return self._get_element_locator(self.__post_a_reply_textarea) + return self._get_element_locator( + self.POST_A_REPLY_SECTION_LOCATORS["post_a_reply_textarea"]) def get_post_a_reply_textarea_text(self) -> str: - return self._get_text_of_element(self.__post_a_reply_textarea) + return self._get_text_of_element( + self.POST_A_REPLY_SECTION_LOCATORS["post_a_reply_textarea"]) def get_post_a_reply_textarea_value(self) -> str: - return self._get_element_input_value(self.__post_a_reply_textarea) + return self._get_element_input_value( + self.POST_A_REPLY_SECTION_LOCATORS["post_a_reply_textarea"]) def get_posted_reply_locator(self, question_id: str) -> Locator: return self._get_element_locator(f"//div[@id='{question_id}']") @@ -418,7 +470,7 @@ def get_posted_reply_modified_by_locator(self, reply_id: str) -> Locator: f"p[@class='edited text-body-sm']/em") def click_on_post_reply_button(self, repliant_username) -> str: - self._click(self.__post_reply_button, + self._click(self.POST_REPLY_LOCATORS["post_reply_button"], expected_locator=f"//span[@class='display-name' and contains(text(), " f"'{repliant_username}')]") return self._get_element_attribute_value("(//span[@class='display-name' and " @@ -428,59 +480,69 @@ def click_on_post_reply_button(self, repliant_username) -> str: # Question Tools actions. def get_edit_this_question_option_locator(self) -> Locator: - return self._get_element_locator(self.__edit_this_question_option) + return self._get_element_locator(self.QUESTION_TOOLS_LOCATORS["edit_this_question_option"]) def get_delete_this_question_locator(self) -> Locator: - return self._get_element_locator(self.__delete_this_question_option) + return self._get_element_locator( + self.QUESTION_TOOLS_LOCATORS["delete_this_question_option"]) def get_lock_this_question_locator(self) -> Locator: - return self._get_element_locator(self.__lock_this_question_option) + return self._get_element_locator(self.QUESTION_TOOLS_LOCATORS["lock_this_question_option"]) # Stands for archived banner as well def get_thread_locked_text(self) -> str: - return self._get_text_of_element(self.__lock_this_thread_banner) + return self._get_text_of_element(self.BANNER_LOCATORS["lock_this_thread_banner"]) def get_thread_locked_locator(self) -> Locator: - return self._get_element_locator(self.__lock_this_thread_banner) + return self._get_element_locator(self.BANNER_LOCATORS["lock_this_thread_banner"]) def get_archive_this_question_locator(self) -> Locator: - return self._get_element_locator(self.__archive_this_question_option) + return self._get_element_locator( + self.QUESTION_TOOLS_LOCATORS["archive_this_question_option"]) def get_needs_more_information_checkbox_locator(self) -> Locator: - return self._get_element_locator(self.__needs_more_information_from_the_user_checkbox) + return self._get_element_locator( + self.NEEDS_MORE_INFORMATION_LOCATORS["needs_more_information_from_the_user_checkbox"]) def get_mark_as_spam_locator(self) -> Locator: - return self._get_element_locator(self.__mark_as_spam_option) + return self._get_element_locator(self.QUESTION_TOOLS_LOCATORS["mark_as_spam_option"]) def get_marked_as_spam_banner_locator(self) -> Locator: - return self._get_element_locator(self.__marked_as_spam_banner) + return self._get_element_locator(self.BANNER_LOCATORS["marked_as_spam_banner"]) def get_marked_as_spam_banner_text(self) -> str: - return self._get_text_of_element(self.__marked_as_spam_banner) + return self._get_text_of_element(self.BANNER_LOCATORS["marked_as_spam_banner"]) def click_on_thread_locked_link(self): - self._click(self.__lock_this_thread_banner_link) + self._click(self.BANNER_LOCATORS["lock_this_thread_banner_link"]) def click_on_lock_this_question_locator(self): - self._click(self.__lock_this_question_option) + self._click(self.QUESTION_TOOLS_LOCATORS["lock_this_question_option"]) def click_on_subscribe_to_feed_option(self): - self._click(self.__subscribe_to_feed_option) + self._click(self.QUESTION_TOOLS_LOCATORS["subscribe_to_feed_option"]) def click_on_mark_as_spam_option(self): - self._click(self.__mark_as_spam_option) + self._click(self.QUESTION_TOOLS_LOCATORS["mark_as_spam_option"]) def click_on_edit_this_question_question_tools_option(self): - self._click(self.__edit_this_question_option) + self._click(self.QUESTION_TOOLS_LOCATORS["edit_this_question_option"]) def click_delete_this_question_question_tools_option(self): - self._click(self.__delete_this_question_option) + self._click(self.QUESTION_TOOLS_LOCATORS["delete_this_question_option"]) def click_on_archive_this_question_option(self): - self._click(self.__archive_this_question_option) + self._click(self.QUESTION_TOOLS_LOCATORS["archive_this_question_option"]) def click_delete_this_question_button(self): - self._click(self.__delete_question_delete_button) + self._click(self.DELETE_QUESTION_LOCATORS["delete_question_delete_button"]) + + def is_reply_displayed(self, reply_id: str) -> bool: + return self._is_element_visible(f"//div[@id='{reply_id}']") + + def is_reply_with_content_displayed(self, reply_content: str) -> bool: + return self._is_element_visible(f"//div[@class='content']/p[normalize-space(text()" + f")='{reply_content}']") # Votes reply section def get_reply_votes_section_locator(self, reply_id: str) -> Locator: @@ -520,39 +582,46 @@ def get_not_helpful_count(self, reply_id) -> str: # Signed out card actions. def click_on_log_in_to_your_account_signed_out_card_link(self): - self._click(self.__log_in_to_your_account_signed_out_card_option) + self._click(self.SIGNED_OUT_CARD_LOCATORS["log_in_to_your_account_signed_out_card_option"]) def click_on_start_a_new_question_signed_out_card_link(self): - self._click(self.__start_a_new_question_signed_out_card_option) + self._click(self.SIGNED_OUT_CARD_LOCATORS["start_a_new_question_signed_out_card_option"]) def click_on_ask_a_question_signed_out_card_option(self): - self._click(self.__ask_a_question_signed_out_card_option) + self._click(self.SIGNED_OUT_CARD_LOCATORS["ask_a_question_signed_out_card_option"]) def ask_a_question_signed_out_card_option_locator(self) -> Locator: - return self._get_element_locator(self.__ask_a_question_signed_out_card_option) + return self._get_element_locator( + self.SIGNED_OUT_CARD_LOCATORS["ask_a_question_signed_out_card_option"]) def click_on_i_have_this_problem_too_signed_out_card_option(self): - self._click(self.__i_have_this_problem_too_signed_out_card_option) + self._click( + self.SIGNED_OUT_CARD_LOCATORS["i_have_this_problem_too_signed_out_card_option"]) def get_i_have_this_problem_too_signed_out_card_locator(self) -> Locator: - return self._get_element_locator(self.__i_have_this_problem_too_signed_out_card_option) + return self._get_element_locator( + self.SIGNED_OUT_CARD_LOCATORS["i_have_this_problem_too_signed_out_card_option"]) # Common responses actions. def click_on_common_responses_option(self): - self._click(self.__common_responses_option) + self._click(self.COMMON_RESPONSES_LOCATORS["common_responses_option"]) def type_into_common_responses_search_field(self, text: str): - self._type(self.__common_responses_search_field, text, 100) + self._type( + self.COMMON_RESPONSES_LOCATORS["common_responses_search_field"], text, 100) def get_text_of_no_cat_responses(self) -> str: - return self._get_text_of_element(self.__common_responses_no_cat_selected) + return self._get_text_of_element( + self.COMMON_RESPONSES_LOCATORS["common_responses_no_cat_selected"]) def get_list_of_categories(self) -> list[str]: - return self._get_text_of_elements(self.__common_responses_categories_options) + return self._get_text_of_elements( + self.COMMON_RESPONSES_LOCATORS["common_responses_categories_options"]) def get_list_of_responses(self) -> list[str]: - return self._get_text_of_elements(self.__common_responses_responses_options) + return self._get_text_of_elements( + self.COMMON_RESPONSES_LOCATORS["common_responses_responses_options"]) def click_on_a_particular_category_option(self, option: str): self._click(f"//ul[@class='category-list']/li[text()='{option}']") @@ -562,23 +631,25 @@ def click_on_a_particular_response_option(self, option: str): # Removing both newline characters and link syntax format. def get_text_of_response_editor_textarea_field(self) -> str: - return (self._get_element_input_value(self.__common_responses_textarea_field) - .replace("\n", "") - .replace("[", "") - .replace("]", "") - ) + return (self._get_element_input_value( + self.COMMON_RESPONSES_LOCATORS["common_responses_textarea_field"]) + .replace("\n", "") + .replace("[", "") + .replace("]", "") + ) def get_text_of_response_preview(self) -> str: - return self._get_text_of_element(self.__common_responses_response_preview) + return self._get_text_of_element( + self.COMMON_RESPONSES_LOCATORS["common_responses_response_preview"]) def click_on_switch_to_mode(self): - self._click(self.__common_responses_switch_to_mode) + self._click(self.COMMON_RESPONSES_LOCATORS["common_responses_switch_to_mode"]) def click_on_common_responses_cancel_button(self): - self._click(self.__common_responses_cancel_button) + self._click(self.COMMON_RESPONSES_LOCATORS["common_responses_cancel_button"]) def click_on_common_responses_insert_response_button(self): - self._click(self.__common_responses_insert_response_button) + self._click(self.COMMON_RESPONSES_LOCATORS["common_responses_insert_response_button"]) def get_time_from_reply(self, reply_id: str) -> str: """Returns the time displayed inside the question for when a reply was made. diff --git a/playwright_tests/pages/common_elements/common_web_elements.py b/playwright_tests/pages/common_elements/common_web_elements.py new file mode 100644 index 00000000000..7918ebe3455 --- /dev/null +++ b/playwright_tests/pages/common_elements/common_web_elements.py @@ -0,0 +1,18 @@ +from playwright.sync_api import Page +from playwright_tests.core.basepage import BasePage + + +class CommonWebElements(BasePage): + AVOID_SPAM_BANNER = { + "scam_banner": "//div[@id='id_scam_alert']", + "scam_banner_text": "//div[@id='id_scam_alert']//p[@class='heading']", + "learn_more_button": "//div[@id='id_scam_alert']//a" + } + + def __init__(self, page: Page): + super().__init__(page) + + # Actions against the Avoid Spam Banner + def get_scam_banner_text(self) -> str: + """Returns the scam banner text.""" + return self._get_text_of_element(self.AVOID_SPAM_BANNER["scam_banner_text"]) diff --git a/playwright_tests/pages/sumo_pages.py b/playwright_tests/pages/sumo_pages.py index 496b0127d74..7426d6fe234 100644 --- a/playwright_tests/pages/sumo_pages.py +++ b/playwright_tests/pages/sumo_pages.py @@ -1,5 +1,4 @@ from playwright.sync_api import Page - from playwright_tests.flows.ask_a_question_flows.aaq_flows.aaq_flow import AAQFlow from playwright_tests.flows.explore_articles_flows.article_flows.add_kb_article_flow import ( AddKbArticleFlow) @@ -19,6 +18,7 @@ from playwright_tests.flows.user_groups_flows.user_group_flow import UserGroupFlow from playwright_tests.flows.user_profile_flows.edit_profile_data_flow import EditProfileDataFlow from playwright_tests.pages.ask_a_question.aaq_pages.aaq_form_page import AAQFormPage +from playwright_tests.pages.common_elements.common_web_elements import CommonWebElements from playwright_tests.pages.contribute.contribute_pages.contributor_discussions_pages.\ contributor_discussions_page import ContributorDiscussionPage from playwright_tests.pages.contribute.contribute_pages.contributor_discussions_pages.\ @@ -225,3 +225,6 @@ def __init__(self, page: Page): # KB article threads Flow self.kb_article_thread_flow = KbThreads(page) + + # Common Web Elements + self.common_web_elements = CommonWebElements(page) diff --git a/playwright_tests/pytest.ini b/playwright_tests/pytest.ini index b0cb5cac0fe..33b19803245 100644 --- a/playwright_tests/pytest.ini +++ b/playwright_tests/pytest.ini @@ -33,4 +33,5 @@ markers = exploreByTopics: Tests belonging to the explore help articles by topics page. searchTests: Tests belonging to the search functionality. userGroupsTests: Tests belonging to the user groups section. + antiSpamTests: Tests belonging to the anti-spam measures section. addopts = --alluredir=./reports/allure_reports --tb=no diff --git a/playwright_tests/test_data/general_data.json b/playwright_tests/test_data/general_data.json index d2b519501f1..6ce9e8544ef 100644 --- a/playwright_tests/test_data/general_data.json +++ b/playwright_tests/test_data/general_data.json @@ -68,6 +68,15 @@ "Firefox Focus": "https://support.allizom.org/en-US/questions/new/focus-firefox", "Mozilla Account": "https://support.allizom.org/en-US/questions/new/mozilla-account" }, + "product_forums" :{ + "Firefox": "https://support.allizom.org/en-US/questions/firefox", + "Firefox for Android": "https://support.allizom.org/en-US/questions/mobile", + "Firefox for iOS": "https://support.allizom.org/en-US/questions/ios", + "Firefox for Enterprise": "https://support.allizom.org/en-US/questions/firefox-enterprise", + "Firefox Focus": "https://support.allizom.org/en-US/questions/focus-firefox", + "Thunderbird": "https://support.allizom.org/en-US/questions/thunderbird", + "Thunderbird for Android": "https://support.allizom.org/en-US/questions/thunderbird-android" + }, "dashboard_links": { "recent_revisions": "https://support.allizom.org/en-US/kb/revisions", "kb_overview": "https://support.allizom.org/en-US/contributors/kb-overview", diff --git a/playwright_tests/tests/ask_a_question_tests/aaq_tests/test_anti_spam_measures.py b/playwright_tests/tests/ask_a_question_tests/aaq_tests/test_anti_spam_measures.py new file mode 100644 index 00000000000..881c1a6026c --- /dev/null +++ b/playwright_tests/tests/ask_a_question_tests/aaq_tests/test_anti_spam_measures.py @@ -0,0 +1,125 @@ +import allure +import pytest +from playwright.sync_api import Page +from playwright_tests.core.utilities import Utilities +from playwright_tests.messages.ask_a_question_messages.AAQ_messages.question_page_messages import \ + QuestionPageMessages +from playwright_tests.messages.common_elements_messages import CommonElementsMessages +from playwright_tests.pages.sumo_pages import SumoPages +from pytest_check import check + + +# C946237 +@pytest.mark.antiSpamTests +@pytest.mark.parametrize("username", ['', 'TEST_ACCOUNT_12']) +def test_anti_spam_banner(page: Page, username): + sumo_pages = SumoPages(page) + utilities = Utilities(page) + + with allure.step("Signing in with an admin account and creating an AAQ question"): + utilities.start_existing_session(utilities.username_extraction_from_email( + utilities.user_secrets_accounts["TEST_ACCOUNT_MODERATOR"] + )) + + utilities.navigate_to_link(utilities.aaq_question_test_data["products_aaq_url"]["Firefox"]) + question_info_one = sumo_pages.aaq_flow.submit_an_aaq_question( + subject=utilities.aaq_question_test_data["valid_firefox_question"]["subject"], + topic_name=sumo_pages.aaq_form_page.get_aaq_form_topic_options()[0], + body=utilities.aaq_question_test_data["valid_firefox_question"] + ["simple_body_text"], + attach_image=False, + expected_locator=sumo_pages.question_page.QUESTION_LOCATORS["questions_header"] + ) + + if username != '': + utilities.start_existing_session(utilities.username_extraction_from_email( + utilities.user_secrets_accounts[username] + )) + else: + utilities.delete_cookies() + + with allure.step("Navigating to each available product support forum and verifying that the " + "scam banner is displayed"): + for product, url in utilities.general_test_data["product_forums"].items(): + utilities.navigate_to_link(url) + assert sumo_pages.common_web_elements.get_scam_banner_text() == ( + CommonElementsMessages.AVOID_SCAM_BANNER_TEXT) + + with allure.step("Navigating to the posted question and verifying that the scam banner is " + "displayed"): + utilities.navigate_to_link(question_info_one["question_page_url"]) + assert sumo_pages.common_web_elements.get_scam_banner_text() == (CommonElementsMessages. + AVOID_SCAM_BANNER_TEXT) + + utilities.start_existing_session(utilities.username_extraction_from_email( + utilities.user_secrets_accounts["TEST_ACCOUNT_MODERATOR"] + )) + with allure.step("Deleting the posted question"): + sumo_pages.aaq_flow.deleting_question_flow() + + +# C946274 +@pytest.mark.antiSpamTests +def test_valid_tld_in_question_comment(page: Page): + sumo_pages = SumoPages(page) + utilities = Utilities(page) + invalid_tld = "dom.ipc.processCount" + valid_tld = "layout.display-list.retain.chrome" + + with allure.step("Signing in with an admin account and creating an AAQ question"): + utilities.start_existing_session(utilities.username_extraction_from_email( + utilities.user_secrets_accounts["TEST_ACCOUNT_MODERATOR"] + )) + + utilities.navigate_to_link(utilities.aaq_question_test_data["products_aaq_url"]["Firefox"]) + sumo_pages.aaq_flow.submit_an_aaq_question( + subject=utilities.aaq_question_test_data["valid_firefox_question"]["subject"], + topic_name=sumo_pages.aaq_form_page.get_aaq_form_topic_options()[0], + body=utilities.aaq_question_test_data["valid_firefox_question"] + ["simple_body_text"], + attach_image=False, + expected_locator=sumo_pages.question_page.QUESTION_LOCATORS["questions_header"] + ) + + with allure.step("Signing in with an account that doesn't have the bypass ratelimit " + "permission"): + username = utilities.start_existing_session(utilities.username_extraction_from_email( + utilities.user_secrets_accounts["TEST_ACCOUNT_MESSAGE_2"] + )) + + with allure.step("Leaving a comment with an invalid TLD"): + reply_one = sumo_pages.aaq_flow.post_question_reply_flow( + repliant_username=username, + reply=invalid_tld + ) + + with check, allure.step("Verifying that the invalid TLD comment is not marked as spam " + "and the spam banner is not displayed"): + assert not sumo_pages.question_page.is_spam_marked_banner_displayed() + assert sumo_pages.question_page.is_reply_displayed(reply_one) + + with allure.step("Leaving a comment with a valid TLD"): + sumo_pages.aaq_flow.post_question_reply_flow( + repliant_username=username, + reply=valid_tld + ) + + with check, allure.step("Verifying that the valid TLD comment is marked as spam and the " + "banner is successfully displayed"): + assert (QuestionPageMessages.SPAM_FLAGGED_REPLY == sumo_pages.question_page. + get_text_of_spam_marked_banner()) + assert not sumo_pages.question_page.is_reply_with_content_displayed(valid_tld) + + with check, allure.step("Signing out and verifying that the reply is not displayed"): + utilities.delete_cookies() + assert not sumo_pages.question_page.is_reply_with_content_displayed(valid_tld) + + with check, allure.step("Signing in with an admin account and verifying that the Marked as" + "spam reply is visible"): + utilities.start_existing_session(utilities.username_extraction_from_email( + utilities.user_secrets_accounts["TEST_ACCOUNT_MODERATOR"] + )) + assert sumo_pages.question_page.is_reply_with_content_displayed(valid_tld) + + with allure.step("Deleting the question"): + sumo_pages.aaq_flow.deleting_question_flow() diff --git a/playwright_tests/tests/ask_a_question_tests/aaq_tests/test_posted_questions.py b/playwright_tests/tests/ask_a_question_tests/aaq_tests/test_posted_questions.py index fd6e880c281..1e4143c666d 100644 --- a/playwright_tests/tests/ask_a_question_tests/aaq_tests/test_posted_questions.py +++ b/playwright_tests/tests/ask_a_question_tests/aaq_tests/test_posted_questions.py @@ -1,6 +1,5 @@ import os import time - import allure import pytest from pytest_check import check