Skip to content

Commit

Permalink
Merge pull request #6300 from emilghittasv/playwright-improve-user-re…
Browse files Browse the repository at this point in the history
…lated-tests

Playwright improve user profile related tests page objects, flows & tests
  • Loading branch information
emilghittasv authored Oct 21, 2024
2 parents 4b40fed + 1136dcd commit 5b3947a
Show file tree
Hide file tree
Showing 20 changed files with 947 additions and 1,032 deletions.
17 changes: 13 additions & 4 deletions playwright_tests/core/basepage.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,8 @@ def _get_elements_count(self, xpath: str) -> int:
"""
return self._get_element_locator(xpath).count()

def _get_element_attribute_value(self, element: Union[str, Locator, list[Locator]],
attribute: str) -> Union[str, list[str]]:
def _get_element_attribute_value(self, element: Union[str, Locator, list[Locator],
ElementHandle], attribute: str) -> Union[str, list[str]]:
"""
This helper function returns the given attribute of a given locator or web element.
"""
Expand Down Expand Up @@ -118,6 +118,15 @@ def _get_text_content_of_all_locators(self, locator: Locator) -> list[str]:
"""
return locator.all_text_contents()

def _checkbox_interaction(self, xpath: str, check: bool):
"""
This helper function interacts with a checkbox element.
"""
if check:
self._get_element_locator(xpath).check()
else:
self._get_element_locator(xpath).uncheck()

def _click(self, element: Union[str, Locator], with_wait=True, with_force=False,
retries=3, delay=2000):
"""
Expand All @@ -133,8 +142,8 @@ def _click(self, element: Union[str, Locator], with_wait=True, with_force=False,
element.click(force=with_force)
print(f"Click succeeded on attempt {attempt + 1}")
break
except PlaywrightTimeoutError as timeout_error:
print(f"Click failed on attempt {attempt + 1}. Error: {timeout_error}")
except (PlaywrightTimeoutError, Exception) as error:
print(f"Click failed on attempt {attempt + 1}. Error: {error}")
if attempt < retries - 1:
self.page.wait_for_timeout(delay)
else:
Expand Down
8 changes: 7 additions & 1 deletion playwright_tests/core/utilities.py
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ def navigate_to_link(self, link: str):
response = navigation_info.value
self.wait_for_dom_to_load()

if response.status is not None:
if response is not None and response.status is not None:
if response.status >= 400:
self.refresh_page()

Expand Down Expand Up @@ -424,3 +424,9 @@ def _exact_phrase_check(self, search_result: str, search_term: str) -> bool:

def get_api_response(self, page: Page, api_url: str):
return page.request.get(api_url)

def block_request(self, route):
"""
This function blocks a certain request
"""
route.abort()
126 changes: 81 additions & 45 deletions playwright_tests/flows/user_profile_flows/edit_profile_data_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,63 +19,99 @@ def __init__(self, page: Page):
self.profile_contribution_areas = MyProfileEditContributionAreasPage(page)

# Editing a profile with data flow.
def edit_profile_with_test_data(self):
def edit_profile_with_test_data(self, info_only=False, submit_change=False) -> dict[str, str]:
edit_test_data = self.utilities.profile_edit_test_data
valid_user_edit = edit_test_data["valid_user_edit"]

self._clear_input_fields()
self.edit_profile_page.send_text_to_username_field(
edit_test_data["valid_user_edit"]["username"]
)
self.edit_profile_page.send_text_to_display_name_field(
edit_test_data["valid_user_edit"]["display_name"]
)
self.edit_profile_page.send_text_to_biography_field(
edit_test_data["valid_user_edit"]["biography"]
)
self.edit_profile_page.send_text_to_website_field(
edit_test_data["valid_user_edit"]["website"]
)
self.edit_profile_page.send_text_to_twitter_username_field(
edit_test_data["valid_user_edit"]["twitter_username"]
)
self.edit_profile_page.send_text_to_community_portal_field(
edit_test_data["valid_user_edit"]["community_portal_username"]
)
self.edit_profile_page.send_text_to_people_directory_username(
edit_test_data["valid_user_edit"]["people_directory_username"]
)
self.edit_profile_page.send_text_to_matrix_nickname(
edit_test_data["valid_user_edit"]["matrix_nickname"]
)
self.edit_profile_page.select_country_dropdown_option_by_value(
edit_test_data["valid_user_edit"]["country_code"]
)
self.edit_profile_page.sent_text_to_city_field(edit_test_data["valid_user_edit"]["city"])
self.edit_profile_page.select_timezone_dropdown_option_by_value(
edit_test_data["valid_user_edit"]["timezone"]
)
self.edit_profile_page.select_preferred_language_dropdown_option_by_value(
edit_test_data["valid_user_edit"]["preferred_language"]
)
self.edit_profile_page.select_involved_from_month_option_by_value(
edit_test_data["valid_user_edit"]["involved_from_month_number"]
)
self.edit_profile_page.select_involved_from_year_option_by_value(
edit_test_data["valid_user_edit"]["involved_from_year"]
)
self.clear_input_fields(info_only)

if not info_only:
self._update_fields([
("send_text_to_username_field", valid_user_edit["username"]),
("send_text_to_display_name_field", valid_user_edit["display_name"]),
("select_timezone_dropdown_option_by_value", valid_user_edit["timezone"]),
("select_preferred_language_dropdown_option_by_value",
valid_user_edit["preferred_language"])
])

self._update_fields([
("send_text_to_biography_field", valid_user_edit["biography"]),
("send_text_to_website_field", valid_user_edit["website"]),
("send_text_to_twitter_username_field", valid_user_edit["twitter_username"]),
("send_text_to_community_portal_field", valid_user_edit["community_portal_username"]),
("send_text_to_people_directory_username",
valid_user_edit["people_directory_username"]),
("send_text_to_matrix_nickname", valid_user_edit["matrix_nickname"]),
("select_country_dropdown_option_by_value", valid_user_edit["country_code"]),
("sent_text_to_city_field", valid_user_edit["city"]),
("select_involved_from_month_option_by_value",
valid_user_edit["involved_from_month_number"]),
("select_involved_from_year_option_by_value", valid_user_edit["involved_from_year"])
])

if submit_change:
self.edit_profile_page.click_update_my_profile_button()

return {
"username": valid_user_edit["username"],
"display_name": valid_user_edit["display_name"],
"biography": valid_user_edit["biography"],
"website": valid_user_edit["website"],
"twitter": valid_user_edit["twitter_username"],
"community_portal": valid_user_edit["community_portal_username"],
"people_directory": valid_user_edit["people_directory_username"],
"matrix_nickname": valid_user_edit["matrix_nickname"],
"country": valid_user_edit["country_value"],
"city": valid_user_edit["city"],
"timezone": valid_user_edit["timezone"],
"preferred_language": valid_user_edit["preferred_language"],
"involved_from_month": valid_user_edit["involved_from_month_value"],
"involved_from_year": valid_user_edit["involved_from_year"]
}

def _update_fields(self, fields: list[tuple[str, str]]):
"""
Updates the fields on the edit profile page.
Args:
fields (list[tuple[str, str]]): A list of tuples where each tuple contains the method
name and the value to be set.
"""
for method_name, value in fields:
getattr(self.edit_profile_page, method_name)(value)

# Clear all profile edit input fields flow.
def _clear_input_fields(self):
self.edit_profile_page.clear_all_input_fields()
self.edit_profile_page.clear_username_field()
def clear_input_fields(self, only_profile_info=False, submit_change=False):
"""
Clears all profile edit input fields.
Args:
only_profile_info (bool): If True, all profile info fields are cleared except username
and display name.
submit_change (bool): If True, submits the changes after clearing the fields.
"""
self.edit_profile_page.clear_all_input_fields(only_profile_info)
self.edit_profile_page.clear_biography_textarea_field()
if submit_change:
self.edit_profile_page.click_update_my_profile_button()

def check_all_user_settings(self):
"""
Navigates to the settings profile option, checks all settings checkboxes,
and updates the settings.
"""
self.top_navbar.click_on_settings_profile_option()
self.edit_settings_page.click_on_all_settings_checkboxes()
self.edit_settings_page.click_on_update_button()

def check_all_profile_contribution_areas(self, checked: bool):
"""
Navigates to the contribution areas section and checks or unchecks all contribution areas.
Args:
checked (bool): If True, checks all contribution areas. If False, unchecks all
contribution areas.
"""
self.top_navbar.click_on_settings_profile_option()
self.profile_navbar.click_on_edit_contribution_areas_option()

Expand Down
32 changes: 20 additions & 12 deletions playwright_tests/pages/user_pages/my_profile_answers_page.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,31 @@

class MyProfileAnswersPage(BasePage):
# My Profile Answers.
__my_answers_page_header = "//h2[@class='sumo-page-subheading']"
__my_answers_question_subject_links = "//article[@id='profile']//li/a"
MY_PROFILE_ANSWERS_LOCATORS = {
"my_answers_page_header": "//h2[@class='sumo-page-subheading']",
"my_answers_question_subject_links": "//article[@id='profile']//li/a"
}

def __init__(self, page: Page):
super().__init__(page)

# My Profile Answers actions.
def _get_page_header(self) -> str:
return super()._get_text_of_element(self.__my_answers_page_header)
def get_page_header(self) -> str:
"""Get the header of the My Profile Answers page."""
return self._get_text_of_element(self.MY_PROFILE_ANSWERS_LOCATORS["my_answers_page_"
"header"])

def _get_text_of_question_subjects(self) -> list[str]:
return super()._get_text_of_elements(self.__my_answers_question_subject_links)
def get_text_of_question_subjects(self) -> list[str]:
"""Get the text of the question subjects."""
return self._get_text_of_elements(self.MY_PROFILE_ANSWERS_LOCATORS["my_answers_question_"
"subject_links"])

def _click_on_specific_answer(self, answer_id: str):
super()._click(f"//article[@id='profile']//a[contains(@href, '{answer_id}')]")
def click_on_specific_answer(self, answer_id: str):
"""Click on a specific answer"""
self._click(f"//article[@id='profile']//a[contains(@href, '{answer_id}')]")

def _get_my_answer_text(self, answer_id: str) -> str:
return super()._get_text_of_element(f"//article[@id='profile']//"
f"a[contains(@href, '{answer_id}')]/"
f"following-sibling::blockquote")
def get_my_answer_text(self, answer_id: str) -> str:
"""Get the text of a specific answer."""
return self._get_text_of_element(f"//article[@id='profile']//"
f"a[contains(@href, '{answer_id}')]/"
f"following-sibling::blockquote")
20 changes: 13 additions & 7 deletions playwright_tests/pages/user_pages/my_profile_documents_page.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,23 @@

class MyProfileDocumentsPage(BasePage):
# My profile documents locators.
__documents_link_list = "//main//a"
MY_PROFILE_DOCUMENTS_LOCATORS = {
"documents_link_list": "//main//a"
}

def __init__(self, page: Page):
super().__init__(page)

# My profile documents actions.
def _click_on_a_particular_document(self, document_name: str):
super()._click(f"//main//a[contains(text(),'{document_name}')]")
def click_on_a_particular_document(self, document_name: str):
"""Click on a particular document"""
self._click(f"//main//a[contains(text(),'{document_name}')]")

def _get_text_of_document_links(self) -> list[str]:
return super()._get_text_of_elements(self.__documents_link_list)
def get_text_of_document_links(self) -> list[str]:
"""Get text of all document links"""
return self._get_text_of_elements(self.MY_PROFILE_DOCUMENTS_LOCATORS["documents_link_"
"list"])

def _get_a_particular_document_locator(self, document_name: str) -> Locator:
return super()._get_element_locator(f"//main//a[contains(text(),'{document_name}')]")
def get_a_particular_document_locator(self, document_name: str) -> Locator:
"""Get a particular document locator"""
return self._get_element_locator(f"//main//a[contains(text(),'{document_name}')]")
Loading

0 comments on commit 5b3947a

Please sign in to comment.