pages/desktop/frontend/users.py (713 lines of code) (raw):

import os from pathlib import Path from pypom import Region from selenium.webdriver.common.by import By from selenium.common.exceptions import StaleElementReferenceException from selenium.webdriver.support.wait import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from pages.desktop.base import Base from pages.desktop.frontend.home import Home from pages.desktop.frontend.reviews import Reviews from pages.desktop.frontend.search import Search class User(Base): URL_TEMPLATE = "/users/edit" _display_name_locator = (By.CLASS_NAME, "UserProfile-name") def wait_for_page_to_load(self): """Waits for various page components to be loaded""" self.wait.until( EC.invisibility_of_element_located((By.CLASS_NAME, "LoadingText")) ) return self def wait_for_user_to_load(self): WebDriverWait( self.driver, 20, ignored_exceptions=StaleElementReferenceException ).until(lambda _: self.is_element_displayed(*self._display_name_locator)) return self @property def user_display_name(self): self.wait.until(EC.visibility_of_element_located(self._display_name_locator)) return self.find_element(*self._display_name_locator) @property def view(self): return self.ViewProfile(self) @property def edit(self): return self.EditProfile(self) @property def minimal(self): return self.MinimalProfileDetails(self) class MinimalProfileDetails(Region): _profile_name_selector = (By.CSS_SELECTOR, ".UserProfile-name") _user_profile_since_selector = (By.CSS_SELECTOR, ".UserProfile-user-since") _report_abuse_button_selector = (By.CSS_SELECTOR, ".ReportUserAbuse-show-more") @property def profile_name(self): self.wait.until( EC.visibility_of_element_located(self._profile_name_selector) ) return self.find_element(*self._profile_name_selector) @property def user_profile_since(self): self.wait.until( EC.visibility_of_element_located(self._user_profile_since_selector) ) return self.find_element(*self._user_profile_since_selector) @property def report_abuse_button(self): self.wait.until( EC.visibility_of_element_located(self._report_abuse_button_selector) ) return self.find_element(*self._report_abuse_button_selector) class ViewProfile(Region): _user_icon_placeholder_locator = (By.CSS_SELECTOR, ".Icon-anonymous-user") _user_profile_image_locator = (By.CSS_SELECTOR, ".UserAvatar-image") _user_developer_role_locator = (By.CSS_SELECTOR, ".UserProfile-developer") _user_developer_role_icon_locator = (By.CSS_SELECTOR, ".Icon-developer") _user_artist_role_locator = (By.CSS_SELECTOR, ".UserProfile-artist") _user_artist_role_icon_locator = (By.CSS_SELECTOR, ".Icon-artist") _user_homepage_locator = (By.CSS_SELECTOR, ".UserProfile-homepage a") _user_location_locator = (By.CSS_SELECTOR, ".UserProfile-location") _user_occupation_locator = (By.CSS_SELECTOR, ".UserProfile-occupation") _user_creation_date_locator = (By.CSS_SELECTOR, ".UserProfile-user-since") _user_addons_count_locator = (By.CSS_SELECTOR, ".UserProfile-number-of-addons") _user_addon_average_rating_locator = ( By.CSS_SELECTOR, ".UserProfile-rating-average", ) _user_biography_locator = (By.CSS_SELECTOR, ".UserProfile-biography") _user_profile_edit_link_locator = (By.CSS_SELECTOR, ".UserProfile-edit-link") _user_extensions_card_locator = (By.CSS_SELECTOR, ".AddonsCard--vertical") _user_extensions_card_header_locator = ( By.CSS_SELECTOR, ".AddonsCard--vertical .Card-header-text", ) _user_extensions_results_locator = ( By.CSS_SELECTOR, ".AddonsCard--vertical .SearchResult", ) _user_themes_card_locator = (By.CSS_SELECTOR, ".AddonsByAuthorsCard--theme") _user_themes_card_header_locator = ( By.CSS_SELECTOR, ".AddonsByAuthorsCard--theme .Card-header-text", ) _user_themes_results_locator = (By.CLASS_NAME, "SearchResult--theme") _user_reviews_card_locator = (By.CSS_SELECTOR, ".UserProfile-reviews") _extensions_pagination_locator = ( By.CSS_SELECTOR, ".AddonsCard--vertical .Paginate", ) _extensions_next_page_locator = ( By.CSS_SELECTOR, ".AddonsCard--vertical .Paginate-item--next", ) _extensions_page_number_locator = ( By.CSS_SELECTOR, ".AddonsCard--vertical .Paginate-page-number", ) _themes_pagination_locator = ( By.CSS_SELECTOR, ".AddonsByAuthorsCard--theme .Paginate", ) _themes_next_page_locator = ( By.CSS_SELECTOR, ".AddonsByAuthorsCard--theme .Paginate-item--next", ) _themes_page_number_locator = ( By.CSS_SELECTOR, ".AddonsByAuthorsCard--theme .Paginate-page-number", ) _user_review_list_locator = (By.CSS_SELECTOR, ".AddonReviewCard-viewOnly") _user_abuse_report_button_locator = ( By.CSS_SELECTOR, ".ReportUserAbuse-show-more", ) _abuse_report_form_header_locator = (By.CSS_SELECTOR, ".Card-header-text") _abuse_report_form_help_text = ( By.CSS_SELECTOR, "section.Card:nth-child(2) > div:nth-child(2) > h3", ) _abuse_report_form_additional_help_text = ( By.ID, "feedbackText-help", ) _abuse_report_textarea_locator = ( By.CSS_SELECTOR, ".FeedbackForm--Card", ) _abuse_report_cancel_button_locator = ( By.CSS_SELECTOR, ".DismissibleTextForm-dismiss", ) _abuse_report_submit_disabled_button_locator = ( By.CSS_SELECTOR, ".FeedbackForm-button.Button--disabled", ) _abuse_report_form_provide_more_details = ( By.ID, "feedbackText" ) _abuse_report_submit_button_locator = ( By.CSS_SELECTOR, ".Button", ) _abuse_report_confirm_message_locator = ( By.CSS_SELECTOR, "p.FeedbackForm-success-first-paragraph", ) _feedback_category_spam_locator = ( By.ID, "feedbackCategoryfeedback_spam" ) def click_category_spam(self): self.wait.until( EC.visibility_of_element_located(self._feedback_category_spam_locator) ) self.find_element(*self._feedback_category_spam_locator).click() return self.find_element(*self._feedback_category_spam_locator) @property def user_profile_icon_placeholder(self): self.wait.until( EC.visibility_of_element_located(self._user_icon_placeholder_locator) ) return self.find_element(*self._user_icon_placeholder_locator) @property def user_profile_icon(self): return self.find_element(*self._user_profile_image_locator) @property def icon_source(self): return self.user_profile_icon.get_attribute("src") @property def developer_role(self): self.wait.until( EC.visibility_of_element_located(self._user_developer_role_locator) ) return self.find_element(*self._user_developer_role_locator) @property def developer_role_icon(self): self.wait.until( EC.visibility_of_element_located(self._user_developer_role_icon_locator) ) return self.find_element(*self._user_developer_role_icon_locator) @property def artist_role(self): self.wait.until( EC.visibility_of_element_located(self._user_artist_role_locator) ) return self.find_element(*self._user_artist_role_locator) @property def artist_role_icon(self): self.wait.until( EC.visibility_of_element_located(self._user_artist_role_icon_locator) ) return self.find_element(*self._user_artist_role_icon_locator) @property def user_homepage(self): self.wait.until( EC.visibility_of_element_located(self._user_homepage_locator) ) return self.find_element(*self._user_homepage_locator).get_attribute("href") @property def user_location(self): self.wait.until( EC.visibility_of_element_located(self._user_location_locator) ) return self.find_element(*self._user_location_locator).text @property def user_occupation(self): self.wait.until( EC.visibility_of_element_located(self._user_occupation_locator) ) return self.find_element(*self._user_occupation_locator).text @property def user_profile_creation_date(self): self.wait.until( EC.visibility_of_element_located(self._user_creation_date_locator) ) return self.find_element(*self._user_creation_date_locator) @property def user_addons_number(self): self.wait.until( EC.visibility_of_element_located(self._user_addons_count_locator) ) return self.find_element(*self._user_addons_count_locator) @property def user_addons_average_rating(self): self.wait.until( EC.visibility_of_element_located( self._user_addon_average_rating_locator ) ) return self.find_element(*self._user_addon_average_rating_locator) @property def user_biography(self): return self.find_element(*self._user_biography_locator).text @property def edit_profile_button(self): self.wait.until( EC.visibility_of_element_located(self._user_profile_edit_link_locator) ) return self.find_element(*self._user_profile_edit_link_locator) def click_edit_profile_button(self): self.wait.until( EC.element_to_be_clickable(self._user_profile_edit_link_locator) ) self.find_element(*self._user_profile_edit_link_locator).click() return User(self.driver, self.page.base_url).wait_for_page_to_load() @property def user_extensions(self): self.wait.until( EC.visibility_of_element_located(self._user_extensions_card_locator) ) self.find_element(*self._user_extensions_card_locator) return Search(self.driver, self.page.base_url).wait_for_page_to_load() @property def user_extensions_card_header(self): self.wait.until( EC.visibility_of_element_located( self._user_extensions_card_header_locator ) ) return self.find_element(*self._user_extensions_card_header_locator).text @property def user_extensions_results(self): self.wait.until( EC.visibility_of_element_located(self._user_extensions_results_locator) ) items = self.find_elements(*self._user_extensions_results_locator) return [ Search( self.driver, self.page.base_url ).SearchResultList.ResultListItems(self, el) for el in items ] @property def user_themes(self): self.wait.until( EC.visibility_of_element_located(self._user_themes_card_locator) ) self.find_element(*self._user_themes_card_locator) return Search(self.driver, self.page.base_url).wait_for_page_to_load() @property def user_themes_card_header(self): self.wait.until( EC.visibility_of_element_located(self._user_themes_card_header_locator) ) return self.find_element(*self._user_themes_card_header_locator).text @property def user_themes_results(self): self.wait.until( EC.visibility_of_element_located(self._user_themes_results_locator) ) items = self.find_elements(*self._user_themes_results_locator) return [ Search( self.driver, self.page.base_url ).SearchResultList.ResultListItems(self, el) for el in items ] @property def extensions_pagination(self): self.wait.until( EC.visibility_of_element_located(self._extensions_pagination_locator) ) return self.find_element(*self._extensions_pagination_locator) def extensions_next_page(self): self.wait.until( EC.element_to_be_clickable(self._extensions_next_page_locator) ) self.find_element(*self._extensions_next_page_locator).click() return User(self.driver, self.page.base_url).wait_for_page_to_load() @property def extensions_page_number(self): self.wait.until( EC.visibility_of_element_located(self._extensions_page_number_locator) ) return self.find_element(*self._extensions_page_number_locator).text @property def themes_pagination(self): return self.find_element(*self._themes_pagination_locator) def themes_next_page(self): self.wait.until(EC.element_to_be_clickable(self._themes_next_page_locator)) self.find_element(*self._themes_next_page_locator).click() return User(self.driver, self.page.base_url).wait_for_page_to_load() @property def themes_page_number(self): self.wait.until( EC.visibility_of_element_located(self._themes_page_number_locator) ) return self.find_element(*self._themes_page_number_locator).text def user_reviews_section_loaded(self): self.wait.until( EC.visibility_of_element_located(self._user_reviews_card_locator) ) @property def user_review_items(self): items = self.find_elements(*self._user_review_list_locator) reviews = Reviews(self.driver, self.page.base_url).wait_for_page_to_load() return [reviews.UserReview(self, el) for el in items] @property def abuse_report_form_provide_more_details(self): return self.find_element(*self._abuse_report_form_provide_more_details) def click_user_abuse_report(self): self.wait.until( EC.element_to_be_clickable(self._user_abuse_report_button_locator) ) self.find_element(*self._user_abuse_report_button_locator).click() self.wait.until( EC.element_to_be_clickable(self._abuse_report_textarea_locator) ) @property def abuse_report_form_header(self): self.wait.until( EC.visibility_of_element_located(self._abuse_report_form_header_locator) ) return self.find_element(*self._abuse_report_form_header_locator).text @property def abuse_report_form_help_text(self): self.wait.until( EC.visibility_of_element_located(self._abuse_report_form_help_text) ) return self.find_element(*self._abuse_report_form_help_text).text @property def abuse_report_form_additional_help_text(self): self.wait.until( EC.visibility_of_element_located( self._abuse_report_form_additional_help_text ) ) return self.find_element(*self._abuse_report_form_additional_help_text).text def user_abuse_report_input_text(self, value): self.wait.until( EC.visibility_of_element_located(self._abuse_report_textarea_locator) ) self.find_element(*self._abuse_report_textarea_locator).send_keys(value) def cancel_abuse_report_form(self): self.wait.until( EC.element_to_be_clickable(self._abuse_report_cancel_button_locator) ) self.find_element(*self._abuse_report_cancel_button_locator).click() self.wait.until( EC.element_to_be_clickable(self._user_abuse_report_button_locator) ) @property def abuse_report_submit_disabled(self): self.wait.until( EC.visibility_of_element_located( self._abuse_report_submit_disabled_button_locator ) ) return self.find_element(*self._abuse_report_submit_disabled_button_locator) def submit_user_abuse_report(self): self.wait.until( EC.element_to_be_clickable(self._abuse_report_submit_button_locator) ) self.find_element(*self._abuse_report_submit_button_locator).click() self.wait.until( EC.invisibility_of_element_located( self._abuse_report_submit_button_locator ) ) @property def user_abuse_confirmation_message(self): self.wait.until( EC.visibility_of_element_located( self._abuse_report_confirm_message_locator ) ) return self.find_element(*self._abuse_report_confirm_message_locator).text class EditProfile(Region): _view_profile_link_locator = (By.CSS_SELECTOR, ".UserProfileEdit-user-links a") _user_email_locator = (By.CSS_SELECTOR, ".UserProfileEdit-email") _user_email_help_text_locator = ( By.CSS_SELECTOR, ".UserProfileEdit-email--help", ) _user_email_help_link_locator = ( By.CSS_SELECTOR, ".UserProfileEdit-email--help a", ) _fxa_account_link_locator = ( By.CSS_SELECTOR, ".UserProfileEdit-manage-account-link", ) _edit_display_name_locator = (By.CSS_SELECTOR, ".UserProfileEdit-displayName") _edit_homepage_locator = (By.CSS_SELECTOR, ".UserProfileEdit-homepage") _edit_location_locator = (By.CSS_SELECTOR, ".UserProfileEdit-location") _edit_occupation_locator = (By.CSS_SELECTOR, ".UserProfileEdit-occupation") _profile_picture_placeholder_locator = (By.CSS_SELECTOR, ".Icon-anonymous-user") _upload_picture_button_locator = ( By.CSS_SELECTOR, ".UserProfileEditPicture-file-input", ) _uploaded_profile_picture_locator = (By.CSS_SELECTOR, ".UserAvatar-image") _delete_picture_button_locator = ( By.CSS_SELECTOR, ".UserProfileEditPicture-delete-button button", ) _cancel_delete_picture_locator = ( By.CSS_SELECTOR, ".ConfirmationDialog-cancel-button", ) _confirm_delete_picture_locator = ( By.CSS_SELECTOR, ".ConfirmationDialog-confirm-button", ) _picture_delete_success_text_locator = (By.CSS_SELECTOR, ".Notice-success p") _edit_biography_locator = (By.CSS_SELECTOR, ".UserProfileEdit-biography") _notifications_info_text_locator = ( By.CSS_SELECTOR, ".UserProfileEdit-notifications-aside", ) _notification_checkbox_locator = ( By.CSS_SELECTOR, ".UserProfileEditNotification-input", ) _notification_text_locator = ( By.CSS_SELECTOR, ".UserProfileEditNotification label", ) _notifications_help_text_locator = ( By.CSS_SELECTOR, ".UserProfileEdit-notifications--help", ) _edit_profile_submit_disabled_button_locator = ( By.CSS_SELECTOR, ".UserProfileEdit-submit-button.Button--disabled", ) _edit_profile_submit_button_locator = ( By.CSS_SELECTOR, ".UserProfileEdit-submit-button", ) _delete_profile_button_locator = ( By.CSS_SELECTOR, ".UserProfileEdit-delete-button", ) _delete_profile_overlay_locator = ( By.CSS_SELECTOR, ".UserProfileEdit-deletion-modal", ) _cancel_delete_profile_button_locator = ( By.CSS_SELECTOR, ".UserProfileEdit-deletion-modal .UserProfileEdit-cancel-button", ) _confirm_delete_profile_button_locator = ( By.CSS_SELECTOR, ".UserProfileEdit-deletion-modal .UserProfileEdit-confirm-button", ) _invalid_url_error_text_locator = ( By.CSS_SELECTOR, ".Notice-error .Notice-text", ) def click_view_profile_link(self): link = WebDriverWait( self.driver, 20, ignored_exceptions=StaleElementReferenceException ).until(EC.element_to_be_clickable(self._view_profile_link_locator)) link.click() self.wait.until( EC.visibility_of_element_located((By.CSS_SELECTOR, ".UserProfile-name")) ) @property def email_field(self): self.wait.until(EC.visibility_of_element_located(self._user_email_locator)) return self.find_element(*self._user_email_locator).get_attribute("value") @property def email_field_help_text(self): self.wait.until( EC.visibility_of_element_located(self._user_email_help_text_locator) ) return self.find_element(*self._user_email_help_text_locator).text def email_field_help_link(self): self.wait.until( EC.element_to_be_clickable(self._user_email_help_link_locator) ) self.find_element(*self._user_email_help_link_locator).click() # waits for the fxa support page to be opened self.wait.until( EC.visibility_of_element_located( (By.CSS_SELECTOR, ".sumo-page-heading") ) ) def link_to_fxa_account(self): self.wait.until(EC.element_to_be_clickable(self._fxa_account_link_locator)) self.find_element(*self._fxa_account_link_locator).click() # waits for the fxa account page to be opened - check logo visibility self.wait.until( EC.visibility_of_element_located((By.CSS_SELECTOR, ".flex h1 span")) ) def display_name(self, value): self.wait.until( EC.visibility_of_element_located(self._edit_display_name_locator) ) self.find_element(*self._edit_display_name_locator).send_keys(value) @property def display_name_field(self): self.wait.until( EC.visibility_of_element_located(self._edit_display_name_locator) ) return self.find_element(*self._edit_display_name_locator) def homepage_link(self, value): self.wait.until( EC.visibility_of_element_located(self._edit_homepage_locator) ) self.find_element(*self._edit_homepage_locator).send_keys(value) @property def homepage_link_field(self): self.wait.until( EC.visibility_of_element_located(self._edit_homepage_locator) ) return self.find_element(*self._edit_homepage_locator) def location(self, value): self.wait.until( EC.visibility_of_element_located(self._edit_location_locator) ) self.find_element(*self._edit_location_locator).send_keys(value) @property def location_field(self): self.wait.until( EC.visibility_of_element_located(self._edit_location_locator) ) return self.find_element(*self._edit_location_locator) def occupation(self, value): self.wait.until( EC.visibility_of_element_located(self._edit_occupation_locator) ) self.find_element(*self._edit_occupation_locator).send_keys(value) @property def profile_avatar_placeholder(self): self.wait.until( EC.visibility_of_element_located( self._profile_picture_placeholder_locator ) ) return self.find_element(*self._profile_picture_placeholder_locator) def upload_picture(self, image): self.wait.until( EC.visibility_of_element_located(self._upload_picture_button_locator) ) button = self.find_element(*self._upload_picture_button_locator) path = Path(os.getcwd()) img = str(path / "img" / image) button.send_keys(img) def profile_picture_is_displayed(self): self.wait.until( lambda _: self.is_element_displayed( *self._uploaded_profile_picture_locator ) ) return self @property def picture_source(self): self.wait.until( EC.visibility_of_element_located(self._uploaded_profile_picture_locator) ) return self.find_element( *self._uploaded_profile_picture_locator ).get_attribute("src") def delete_profile_picture(self): self.find_element(*self._delete_picture_button_locator).click() self.wait.until( EC.element_to_be_clickable(self._confirm_delete_picture_locator) ) def cancel_delete_picture(self): self.wait.until( EC.element_to_be_clickable(self._cancel_delete_picture_locator) ) self.find_element(*self._cancel_delete_picture_locator).click() self.wait.until( EC.element_to_be_clickable(self._delete_picture_button_locator) ) def confirm_delete_picture(self): self.wait.until( EC.element_to_be_clickable(self._confirm_delete_picture_locator) ) self.find_element(*self._confirm_delete_picture_locator).click() self.wait.until( EC.visibility_of_element_located( self._picture_delete_success_text_locator ) ) @property def picture_delete_success_message(self): self.wait.until( EC.visibility_of_element_located( self._picture_delete_success_text_locator ) ) return self.find_element(*self._picture_delete_success_text_locator).text def biography(self, value): self.wait.until( EC.visibility_of_element_located(self._edit_biography_locator) ) self.find_element(*self._edit_biography_locator).send_keys(value) @property def notifications_info_text(self): self.wait.until( EC.visibility_of_element_located(self._notifications_info_text_locator) ) return self.find_element(*self._notifications_info_text_locator).text @property def notifications_checkbox(self): """function used for developer notifications""" self.wait.until( lambda _: len(self.notification_text) == 8, message=f"There were {len(self.notification_text)} notifications displayed, expected 8", ) return self.find_elements(*self._notification_checkbox_locator) @property def notification_text(self): self.wait.until( EC.visibility_of_element_located(self._notification_text_locator) ) items = self.find_elements(*self._notification_text_locator) # the notifications endpoint takes a bit longer to respond, so a wait is helpful here self.wait.until( lambda _: len(items) > 0, message=f"Expected notifications list to be loaded but the list contains {len(items)} items", ) return items @property def notifications_help_text(self): self.wait.until( EC.visibility_of_element_located(self._notifications_help_text_locator) ) return self.find_element(*self._notifications_help_text_locator).text @property def submit_changes_button_disabled(self): return self.find_element(*self._edit_profile_submit_disabled_button_locator) def update_profile(self): """Updates a user profile and expects to remain on the Edit Profile page (likely due to an error)""" self.wait.until( EC.element_to_be_clickable(self._edit_profile_submit_button_locator) ) self.find_element(*self._edit_profile_submit_button_locator).click() def submit_changes(self): """Updates a user profile and expects to navigate to the View Profile page""" self.wait.until( EC.element_to_be_clickable(self._edit_profile_submit_button_locator) ) self.find_element(*self._edit_profile_submit_button_locator).click() self.wait.until( EC.visibility_of_element_located((By.CLASS_NAME, "UserProfile-name")) ) def delete_account(self): self.wait.until( EC.element_to_be_clickable(self._delete_profile_button_locator) ) self.find_element(*self._delete_profile_button_locator).click() self.wait.until( EC.visibility_of_element_located(self._delete_profile_overlay_locator) ) def cancel_delete_account(self): self.wait.until( EC.element_to_be_clickable(self._cancel_delete_profile_button_locator) ) self.find_element(*self._cancel_delete_profile_button_locator).click() self.wait.until( EC.invisibility_of_element_located( self._cancel_delete_profile_button_locator ) ) def confirm_delete_account(self): self.wait.until( EC.element_to_be_clickable(self._confirm_delete_profile_button_locator) ) self.find_element(*self._confirm_delete_profile_button_locator).click() return Home(self.driver, self.page.base_url).wait_for_page_to_load() @property def invalid_url_error_text(self): self.wait.until( EC.visibility_of_element_located(self._invalid_url_error_text_locator) ) return self.find_element(*self._invalid_url_error_text_locator).text