Skip to content

Commit 9758f35

Browse files
authored
Merge pull request #7673 from emilghittasv/playwright-new-tests
Playwright: Expand test coverage to Moderation /flagged page
2 parents 4f42d33 + 66c8401 commit 9758f35

9 files changed

Lines changed: 851 additions & 10 deletions

File tree

.github/workflows/playwright.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ on:
4646
- communityForums
4747
- adminAnnouncementBanners
4848
- userAdminPages
49+
- flaggedModerationPage
4950
- smokeTest
5051

5152
env:
@@ -102,7 +103,7 @@ jobs:
102103
run: |
103104
source ../.venv/bin/activate
104105
declare dispatch_test_suite="${{inputs.TestSuite}}"
105-
declare all_test_suites=("homePageTests" "topNavbarTests" "footerSectionTests" "contributePagesTests" "messagingSystem" "userContributionTests" "userProfile" "userSettings" "editUserProfileTests" "userQuestions" "contactSupportPage" "productSolutionsPage" "productSupportPage" "productTopicsPage" "aaqPage" "postedQuestions" "kbProductsPage" "kbArticleCreationAndAccess" "beforeThreadTests" "articleThreads" "afterThreadTests" "kbArticleShowHistory" "recentRevisionsDashboard" "kbDashboard" "kbRestrictedVisibility" "kbArticleTranslation" "exploreByTopics" "searchTests" "contributorForumSearch" "userGroupsTests" "antiSpamTests" "contributorDiscussions" "contributorDiscussionsThreads" "userDeletion" "communityForums" "adminAnnouncementBanners" "userAdminPages" "mediaGalleryTests" "kbTemplatesCategoryPage")
106+
declare all_test_suites=("homePageTests" "topNavbarTests" "footerSectionTests" "contributePagesTests" "messagingSystem" "userContributionTests" "userProfile" "userSettings" "editUserProfileTests" "userQuestions" "contactSupportPage" "productSolutionsPage" "productSupportPage" "productTopicsPage" "aaqPage" "postedQuestions" "kbProductsPage" "kbArticleCreationAndAccess" "beforeThreadTests" "articleThreads" "afterThreadTests" "kbArticleShowHistory" "recentRevisionsDashboard" "kbDashboard" "kbRestrictedVisibility" "kbArticleTranslation" "exploreByTopics" "searchTests" "contributorForumSearch" "userGroupsTests" "antiSpamTests" "contributorDiscussions" "contributorDiscussionsThreads" "userDeletion" "communityForums" "adminAnnouncementBanners" "userAdminPages" "mediaGalleryTests" "kbTemplatesCategoryPage" "flaggedModerationPage")
106107
if [ "$dispatch_test_suite" == "All" ] ; then
107108
for test in "${all_test_suites[@]}"; do
108109
if ! pytest -m ${test} --numprocesses 6 --browser ${BROWSER} --reruns 2 -v; then

playwright_tests/flows/ask_a_question_flows/aaq_flows/aaq_flow.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -215,19 +215,24 @@ def post_question_reply_flow(self, repliant_username: str, reply='', submit_repl
215215
if submit_reply:
216216
return self.question_page.click_on_post_reply_button(repliant_username, fetch_id)
217217

218-
def report_question_abuse(self, answer_id="", text=''):
218+
def report_question_abuse(self, answer_id="", text='', report_reason=""):
219219
"""
220220
Flow for reporting question as abusive.
221221
Args:
222222
answer_id (str): The ID of the question reply.
223223
text: Text to be added inside the report.
224+
report_reason (str): The reason radio value to select (e.g. 'spam', 'language',
225+
'abuse', 'other'). Defaults to the preselected 'spam' reason when not provided.
224226
"""
225227

226228
if answer_id:
227229
self.question_page.click_on_report_abuse_for_a_certain_reply(answer_id)
228230
else:
229231
self.question_page.click_on_question_report_abuse_option()
230232

233+
if report_reason:
234+
self.question_page.click_on_report_abuse_reason_option(report_reason)
235+
231236
if text:
232237
self.question_page.add_text_to_report_abuse_textarea(text)
233238

playwright_tests/messages/ask_a_question_messages/AAQ_messages/question_page_messages.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ class QuestionPageMessages:
33
EDIT_REPLY_URL = "/edit/"
44
DELETE_QUESTION_URL_ENDPOINT = '/delete'
55
DELETE_QUESTION_REPLY_URL = '/delete/'
6+
DELETE_QUESTION_CONFIRMATION_HEADING = "Are you sure you want to delete this question?"
7+
DELETE_ANSWER_CONFIRMATION_HEADING = "Are you sure you want to delete this answer?"
68
LOCKED_THREAD_BANNER = "This thread was closed. Please ask a new question if you need help."
79
ARCHIVED_THREAD_BANNER = ("This thread was archived. Please ask a new question if you need "
810
"help.")

playwright_tests/messages/common_elements_messages.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@ class CommonElementsMessages:
22
AVOID_SCAM_BANNER_TEXT = ("Avoid support scams. We will never ask you to call or text a phone "
33
"number or share personal information. Please report suspicious "
44
"activity using the “Report Abuse” option.")
5+
CONTRIBUTOR_TOOLS_SIDEBAR_HEADING = "Contributor tools"
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
from playwright_tests.messages.homepage_messages import HomepageMessages
2+
3+
14
class ModerateForumContentPageMessages:
5+
PAGE_URL = HomepageMessages.STAGE_HOMEPAGE_URL_EN_US + "flagged"
6+
DEACTIVATED_USERS_PAGE_URL = HomepageMessages.STAGE_HOMEPAGE_URL_EN_US + (
7+
"users/deactivation_log")
28
UPDATE_STATUS_FIRST_VALUE = "1"
39
UPDATE_STATUS_SECOND_VALUE = "2"
10+
SIDEBAR_OPTION_NAME = "Moderate forum content"

playwright_tests/pages/ask_a_question/posted_question_pages/questions_page.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,11 +223,19 @@ def __init__(self, page: Page):
223223
"""Locators belonging to the delete question section."""
224224
self.delete_question_delete_button = page.locator("input[value='Delete']")
225225
self.delete_question_cancel_button = page.get_by_role("link").filter(has_text="Cancel")
226+
self.delete_confirmation_section = page.locator("div[class='to-delete highlight-box']")
227+
self.delete_confirmation_heading = page.locator("div[class='to-delete highlight-box'] h1")
226228

227229
"""Locators belonging to the report abuse section."""
228230
self.report_abuse_submit_button = page.locator(
229231
"div[class='mzp-c-modal-inner'] button[type='submit']")
230232
self.report_abuse_textarea = page.locator("div[class='mzp-c-modal-inner'] textarea")
233+
# The reason radio options ('spam', 'language', 'abuse', 'other') inside the currently
234+
# open report-abuse modal. 'spam' is preselected by default. The radio <input>s are
235+
# visually hidden by the styled-radio CSS, so the (clickable) <label> is targeted
236+
# instead - matched by its 'for' attribute suffix, since the id prefix is dynamic.
237+
self.report_abuse_reason_option = lambda reason_value: page.locator(
238+
"div[class='mzp-c-modal-inner']").locator(f"label[for$='_{reason_value}']")
231239
self.report_abuse_flagged_this_content_message = page.locator(
232240
"div[class='mzp-c-modal-inner'] span[class='message']")
233241
self.report_abuse_modal_close_button = page.locator(
@@ -256,6 +264,9 @@ def click_abuse_modal_close_button(self):
256264
def add_text_to_report_abuse_textarea(self, text: str):
257265
self._fill(self.report_abuse_textarea, text)
258266

267+
def click_on_report_abuse_reason_option(self, reason_value: str):
268+
self._click(self.report_abuse_reason_option(reason_value))
269+
259270
def click_on_report_abuse_submit_button(self):
260271
self._click(self.report_abuse_submit_button)
261272

playwright_tests/pages/contribute/contributor_tools_pages/moderate_forum_content.py

Lines changed: 39 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,11 @@ def __init__(self, page: Page):
77
super().__init__(page)
88

99
"""Locators belonging to the View All deactivated users page."""
10-
self.view_all_deactivated_users_button = page.locator("div[class='sumo-button-wrap'] a")
10+
self.view_all_deactivated_users_button = page.get_by_role(
11+
"link", name="View all deactivated users", exact=True)
12+
self.deactivation_log_deactivated_user = lambda username: page.locator(
13+
f"//table[@id='deactivations-log']/tbody/tr/td[2]/a[normalize-space(text())="
14+
f"'{username}']")
1115

1216
"""Locators belonging to the flagged questions page."""
1317
self.flagged_question = lambda question_info: page.locator("p").get_by_text(
@@ -18,13 +22,13 @@ def __init__(self, page: Page):
1822
question_title, exact=True).locator("> div[class='content'] p")
1923
self.created_by_link_text = lambda question_info: page.locator(
2024
f"//p[normalize-space(text())='{question_info}']/ancestor::div"
21-
f"[@class='flagged-item-content']//h3[text()='Created:']/following-sibling::p/a")
25+
f"[@class='flagged-item-content']//h3[text()='Created:']/following-sibling::p[1]/a")
2226
self.flagged_by_link_text = lambda question_info: page.locator(
2327
f"//p[normalize-space(text())='{question_info}']/ancestor::div"
24-
f"[@class='flagged-item-content']//h3[text()='Flagged:']/following-sibling::p/a")
25-
self.take_action_view_option = lambda question_info: page.get_by_role(
26-
"paragraph", name=question_info, exact=True).locator("+ div").get_by_role(
27-
"link", name="View", exact=True)
28+
f"[@class='flagged-item-content']//h3[text()='Flagged:']/following-sibling::p[1]/a")
29+
self.take_action_view_option = lambda flagged_info: page.locator(
30+
f"//li[.//*[normalize-space(text())='{flagged_info}']]"
31+
f"//a[normalize-space(text())='View']")
2832
self.take_action_edit_option = lambda question_info: page.locator(
2933
f"//p[normalize-space(text())='{question_info}']/ancestor::"
3034
f"div[@class='flagged-item-content']//a[text()='Edit']")
@@ -37,9 +41,23 @@ def __init__(self, page: Page):
3741
self.update_status_button = lambda question_info: page.locator(
3842
f"//p[normalize-space(text())='{question_info}']/ancestor::div"
3943
f"[@class='flagged-item-content']//following-sibling::form/input[@value='Update']")
44+
# Profile tickets render the flagged username inside an <h2> (rather than a <p>), so the
45+
# profile update-status controls are anchored on that heading instead.
46+
self.update_profile_status_option = lambda username: page.locator(
47+
f"//h2[@class='sumo-page-subheading' and text()='{username}']/ancestor::div"
48+
f"[@class='flagged-item-content']//following-sibling::form/select")
49+
self.update_profile_status_button = lambda username: page.locator(
50+
f"//h2[@class='sumo-page-subheading' and text()='{username}']/ancestor::div"
51+
f"[@class='flagged-item-content']//following-sibling::form/input[@value='Update']")
4052
self.paginator_section = page.locator("//ol[@class='pagination cf']")
4153
self.last_paginator_option = page.locator("//ol[@class='pagination cf']/li/a").last
4254

55+
"""Locators belonging to the 'Filter by reason' and 'Filter by type' dropdowns."""
56+
self.filter_by_reason_dropdown = page.locator("select#flagit-reason-filter")
57+
self.filter_by_type_dropdown = page.locator("select#flagit-content-type-filter")
58+
self.filter_by_type_option = lambda type_name: page.locator(
59+
f"//select[@id='flagit-content-type-filter']/option[normalize-space()='{type_name}']")
60+
4361
"""Locators belonging to the flagged profile tickets"""
4462
self.profile_flagged_ticket = lambda username: page.locator(
4563
f"//h2[@class='sumo-page-subheading' and text()='{username}']")
@@ -57,8 +75,8 @@ def click_created_by_link(self, question_info: str):
5775
def click_flagged_by_link(self, question_info: str):
5876
self._click(self.flagged_by_link_text(question_info))
5977

60-
def click_take_action_view_option(self, question_info: str):
61-
self._click(self.take_action_view_option(question_info))
78+
def click_take_action_view_option(self, flagged_info: str):
79+
self._click(self.take_action_view_option(flagged_info))
6280

6381
def click_take_action_edit_option(self, question_info: str):
6482
self._click(self.take_action_edit_option(question_info))
@@ -72,9 +90,22 @@ def select_update_status_option(self, question_info: str, select_value: str):
7290
def click_on_the_update_button(self, question_info: str):
7391
self._click(self.update_status_button(question_info))
7492

93+
def select_update_profile_status_option(self, username: str, select_value: str):
94+
self._select_option_by_value(self.update_profile_status_option(username), select_value)
95+
96+
def click_on_the_update_profile_button(self, username: str):
97+
self._click(self.update_profile_status_button(username))
98+
7599
def click_view_all_deactivated_users_button(self):
76100
self._click(self.view_all_deactivated_users_button)
77101

102+
def filter_flagged_content_by_reason(self, reason_value: str):
103+
self._select_option_by_value(self.filter_by_reason_dropdown, reason_value)
104+
105+
def filter_flagged_content_by_type(self, type_name: str):
106+
value = self._get_element_attribute_value(self.filter_by_type_option(type_name), "value")
107+
self._select_option_by_value(self.filter_by_type_dropdown, value)
108+
78109
def is_paginator_visible(self) -> bool:
79110
self.wait_for_dom_to_load()
80111
return self._is_element_visible(self.paginator_section)

playwright_tests/pytest.ini

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,4 +39,5 @@ markers =
3939
communityForums: Tests belonging to the community forums suite.
4040
adminAnnouncementBanners: Tests belonging to announcement banners.
4141
userAdminPages: Tests belonging to the admin user pages.
42+
flaggedModerationPage: Tests belonging to the flagged content moderation page.
4243
addopts = --alluredir=./reports/allure_reports --video retain-on-failure --tb=no

0 commit comments

Comments
 (0)