pages/desktop/frontend/home.py (355 lines of code) (raw):

import requests from pypom import Region from selenium.webdriver.common.by import By from selenium.webdriver.support import expected_conditions as EC from scripts import custom_waits from pages.desktop.base import Base from pages.desktop.frontend.details import Detail class Home(Base): """Addons Home page""" _recommended_extensions_locator = (By.CLASS_NAME, "Home-Recommended-extensions") _recommended_themes_locator = (By.CLASS_NAME, "Home-Recommended-themes") _hero_locator = (By.CLASS_NAME, "HeroRecommendation") _secondary_hero_locator = (By.CLASS_NAME, "SecondaryHero") _popular_extensions_locator = (By.CLASS_NAME, "Home-PopularExtensions") _popular_themes_locator = (By.CLASS_NAME, "Home-Popular-themes") _themes_category_locator = (By.CLASS_NAME, "Home-CuratedThemes") _toprated_themes_locator = (By.CLASS_NAME, "Home-TopRatedThemes") _featured_collections_locator = (By.CLASS_NAME, "Home-FeaturedCollection") _shelves_titles_locator = (By.CSS_SELECTOR, ".CardList .Card-header-text") _shelves_see_more_links_locator = ( By.CSS_SELECTOR, ".Card-shelf-footer-in-header a", ) 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 @property def primary_hero(self): self.wait.until(EC.visibility_of_element_located(self._hero_locator)) return self.find_element(*self._hero_locator) @property def hero_banner(self): self.wait.until(EC.visibility_of_element_located(self._hero_locator)) el = self.find_element(*self._hero_locator) return self.PrimaryHero(self, el) @property def addon_shelf_titles(self): self.wait.until( EC.visibility_of_element_located(self._shelves_titles_locator) ) return [ title.text for title in self.find_elements(*self._shelves_titles_locator) ] @property def popular_extensions(self): self.wait.until( EC.visibility_of_element_located(self._popular_extensions_locator) ) el = self.find_element(*self._popular_extensions_locator) return self.Extensions(self, el) @property def recommended_extensions(self): self.wait.until( EC.visibility_of_element_located(self._recommended_extensions_locator) ) el = self.find_element(*self._recommended_extensions_locator) return self.Extensions(self, el) @property def recommended_themes(self): self.wait.until( EC.visibility_of_element_located(self._recommended_themes_locator) ) el = self.find_element(*self._recommended_themes_locator) return self.Themes(self, el) @property def popular_themes(self): self.wait.until(EC.visibility_of_element_located(self._popular_themes_locator)) el = self.find_element(*self._popular_themes_locator) return self.Themes(self, el) @property def toprated_themes(self): self.wait.until(EC.visibility_of_element_located(self._toprated_themes_locator)) el = self.find_element(*self._toprated_themes_locator) return self.Themes(self, el) @property def theme_category(self): self.wait.until(EC.visibility_of_element_located(self._themes_category_locator)) el = self.find_element(*self._themes_category_locator) return self.ThemeCategory(self, el) @property def secondary_hero(self): self.wait.until(EC.visibility_of_element_located(self._secondary_hero_locator)) el = self.find_element(*self._secondary_hero_locator) return self.SecondaryHero(self, el) @property def featured_collections(self): self.wait.until( EC.visibility_of_element_located(self._featured_collections_locator) ) el = self.find_element(*self._featured_collections_locator) return self.Extensions(self, el) @property def see_more_links_in_shelves(self): self.wait.until( EC.visibility_of_element_located(self._shelves_see_more_links_locator) ) return self.find_elements(*self._shelves_see_more_links_locator) def click_see_more_links(self, count): link = [el for el in self.see_more_links_in_shelves] target = link[count].get_attribute("target") # external links are opened in new tabs, so we need to account for multiple windows if target == "_blank": home_tab = self.driver.current_window_handle link[count].click() self.wait.until(EC.number_of_windows_to_be(2)) new_tab = self.driver.window_handles[1] self.driver.switch_to.window(new_tab) # see more external links can contain variable content we might not know in advance (especially on prod) # the solution used here is to verify that the content we link to is available (i.e. page response = 200) self.wait.until(custom_waits.url_not_contains("about:blank")) page = requests.head(self.driver.current_url) assert ( page.status_code == 200 ), f"The response status code was {page.status_code}" self.driver.close() self.driver.switch_to.window(home_tab) else: # similar to external links, internal links might contain unpredictable content; # in this case, we check that the content exists inside the AMO domain link[count].click() self.wait.until( EC.invisibility_of_element_located((By.CLASS_NAME, "LoadingText")) ) assert "addons" in self.driver.current_url page = requests.head(self.driver.current_url) assert ( page.status_code == 200 ), f"The response status code was {page.status_code}" self.driver.back() # waits for the homepage to reload self.wait.until( EC.invisibility_of_element_located((By.CLASS_NAME, "LoadingText")) ) class ThemeCategory(Region): _home_theme_category_locator = (By.CLASS_NAME, "Home-SubjectShelf-list-item") _shelf_summary_locator = (By.CLASS_NAME, "Home-SubjectShelf-subheading") @property def list(self): self.wait.until( EC.visibility_of_element_located(self._home_theme_category_locator) ) items = self.find_elements(*self._home_theme_category_locator) return [self.CategoryDetail(self.page, el) for el in items] @property def shelf_summary(self): self.wait.until( EC.visibility_of_element_located(self._shelf_summary_locator) ) return self.find_element(*self._shelf_summary_locator).text class CategoryDetail(Region): _category_link_locator = (By.CLASS_NAME, "Home-SubjectShelf-link") _category_name_locator = ( By.CSS_SELECTOR, ".Home-SubjectShelf-link span:nth-child(2)", ) _category_icon_locator = (By.CLASS_NAME, "CategoryIcon") @property def name(self): self.wait.until( EC.visibility_of_element_located(self._category_name_locator) ) return self.find_element(*self._category_name_locator).text @property def category_icon(self): self.wait.until( EC.visibility_of_element_located(self._category_icon_locator) ) return self.find_element(*self._category_icon_locator) def click(self): self.root.click() from pages.desktop.frontend.search import Search return Search(self.driver, self.page.base_url) class Extensions(Region): _browse_all_locator = (By.CSS_SELECTOR, ".Card-shelf-footer-in-header a") _extensions_locator = (By.CLASS_NAME, "SearchResult") _promo_card_header_locator = (By.CLASS_NAME, "Card-header-text") @property def list(self): self.wait.until(EC.visibility_of_element_located(self._extensions_locator)) items = self.find_elements(*self._extensions_locator) return [Home.PromoShelvesAddons(self.page, el) for el in items] def browse_all(self): self.wait.until(EC.visibility_of_element_located(self._browse_all_locator)) self.find_element(*self._browse_all_locator).click() from pages.desktop.frontend.search import Search search = Search(self.driver, self.page.base_url) return search.wait_for_page_to_load() @property def card_header(self): self.wait.until( EC.visibility_of_element_located(self._promo_card_header_locator) ) return self.find_element(*self._promo_card_header_locator).text def see_collection_details(self): self.wait.until(EC.visibility_of_element_located(self._browse_all_locator)) self.find_element(*self._browse_all_locator).click() # TODO: add additional validations when I'm covering collections class Themes(Region): _browse_all_locator = (By.CSS_SELECTOR, ".Card-shelf-footer-in-header a") _themes_locator = (By.CLASS_NAME, "SearchResult--theme") _promo_card_header_locator = (By.CLASS_NAME, "Card-header-text") @property def list(self): self.wait.until(EC.visibility_of_element_located(self._themes_locator)) items = self.find_elements(*self._themes_locator) return [Home.PromoShelvesAddons(self.page, el) for el in items] def browse_all(self): self.wait.until(EC.visibility_of_element_located(self._browse_all_locator)) self.find_element(*self._browse_all_locator).click() from pages.desktop.frontend.search import Search search = Search(self.driver, self.page.base_url) return search.wait_for_page_to_load() @property def card_header(self): self.wait.until( EC.visibility_of_element_located(self._promo_card_header_locator) ) return self.find_element(*self._promo_card_header_locator).text class PromoShelvesAddons(Region): _addon_link_locator = (By.CLASS_NAME, "SearchResult-link") _addon_name_locator = (By.CLASS_NAME, "SearchResult-name") _addon_icon_locator = (By.CLASS_NAME, "SearchResult-icon") _addon_users_locator = (By.CLASS_NAME, "SearchResult-users-text") _addon_rating_locator = (By.CLASS_NAME, "SearchResult-rating") @property def name(self): self.wait.until(EC.visibility_of_element_located(self._addon_name_locator)) return self.find_element(*self._addon_name_locator) def click(self): self.wait.until(EC.element_to_be_clickable(self._addon_link_locator)) self.find_element(*self._addon_link_locator).click() from pages.desktop.frontend.extensions import Extensions return Extensions(self.driver, self.page.base_url) @property def addon_icon_preview(self): self.wait.until(EC.visibility_of_element_located(self._addon_icon_locator)) return self.find_element(*self._addon_icon_locator) @property def addon_users_preview(self): self.wait.until(EC.visibility_of_element_located(self._addon_users_locator)) return self.find_element(*self._addon_users_locator) @property def addon_rating_preview(self): return self.find_element(*self._addon_rating_locator) def shelf_item_elements(self, item): assert item.name assert item.addon_icon_preview.is_displayed() assert item.addon_users_preview.is_displayed() class PrimaryHero(Region): _hero_locator = (By.CLASS_NAME, "HeroRecommendation") _hero_image_locator = (By.CLASS_NAME, "HeroRecommendation-image") _hero_title_locator = (By.CLASS_NAME, "HeroRecommendation-title-text") _hero_extension_name_locator = (By.CLASS_NAME, "HeroRecommendation-heading") _hero_extension_summary_locator = (By.CLASS_NAME, "HeroRecommendation-body") _extension_button_locator = (By.CLASS_NAME, "HeroRecommendation-link") _extension_link_locator = (By.CSS_SELECTOR, ".HeroRecommendation-info a") @property def primary_hero_banner(self): self.wait.until(EC.visibility_of_element_located(self._hero_locator)) return self.find_element(*self._hero_locator) @property def primary_hero_image(self): self.wait.until(EC.visibility_of_element_located(self._hero_image_locator)) return self.find_element(*self._hero_image_locator) @property def primary_hero_title(self): self.wait.until(EC.visibility_of_element_located(self._hero_title_locator)) return self.find_element(*self._hero_title_locator).text @property def primary_hero_extension_name(self): self.wait.until( EC.visibility_of_element_located(self._hero_extension_name_locator) ) return self.find_element(*self._hero_extension_name_locator).text @property def primary_hero_extension_summary(self): self.wait.until( EC.visibility_of_element_located(self._hero_extension_summary_locator) ) return self.find_element(*self._hero_extension_summary_locator) def click_hero_extension_link(self): self.wait.until(EC.element_to_be_clickable(self._extension_button_locator)) self.find_element(*self._extension_button_locator).click() return Detail(self.driver, self.page.base_url).wait_for_page_to_load() class SecondaryHero(Region): _secondary_headline_locator = (By.CLASS_NAME, "SecondaryHero-message-headline") _secondary_description_locator = ( By.CLASS_NAME, "SecondaryHero-message-description", ) _see_all_extensions_locator = (By.CLASS_NAME, "SecondaryHero-message-link") _modules_locator = (By.CLASS_NAME, "SecondaryHero-module") @property def secondary_hero_headline(self): self.wait.until( EC.visibility_of_element_located(self._secondary_headline_locator) ) return self.find_element(*self._secondary_headline_locator).text @property def secondary_hero_description(self): self.wait.until( EC.visibility_of_element_located(self._secondary_description_locator) ) return self.find_element(*self._secondary_description_locator).text def see_all_extensions(self): self.wait.until( EC.element_to_be_clickable(self._see_all_extensions_locator) ) self.find_element(*self._see_all_extensions_locator).click() from pages.desktop.frontend.extensions import Extensions return Extensions(self.driver, self.page.base_url).wait_for_page_to_load() @property def secondary_hero_modules(self): self.wait.until(EC.visibility_of_element_located(self._modules_locator)) element = self.find_elements(*self._modules_locator) return [self.SecondaryHeroModules(self.page, el) for el in element] class SecondaryHeroModules(Region): _module_icon_locator = (By.CLASS_NAME, "SecondaryHero-module-icon") _module_description_locator = ( By.CLASS_NAME, "SecondaryHero-module-description", ) _module_link_locator = (By.CSS_SELECTOR, ".SecondaryHero-module a") _module_link_text_locator = (By.CLASS_NAME, "SecondaryHero-module-linkText") @property def module_icon(self): self.wait.until( EC.visibility_of_element_located(self._module_icon_locator) ) return self.find_element(*self._module_icon_locator) @property def module_description(self): self.wait.until( EC.visibility_of_element_located(self._module_description_locator) ) return self.find_element(*self._module_description_locator) def click_secondary_module_link(self): link = self.find_element(*self._module_link_locator) target = link.get_attribute("target") # external links are opened in new tabs, so we need to account for multiple windows if target == "_blank": link.click() self.wait.until(EC.number_of_windows_to_be(2)) new_tab = self.driver.window_handles[1] self.driver.switch_to.window(new_tab) # editorial might change these links when they need to push new content and we don't know # in advance what that content might be; also, we want to avoid frequent maintenance for # these tests; the solution used is to verify that the content we link to is available # (i.e. we check that the page response status is 200) self.wait.until(custom_waits.url_not_contains("about:blank")) page = requests.head(self.driver.current_url) assert ( page.status_code == 200 ), f"The response status code was {page.status_code}" else: # this condition handles links that open on the amo domain; again, we might not know the # content in advance, so the best we can do is check that the page opens in AMO # and the status code we receive is 200 link.click() self.wait.until( EC.invisibility_of_element_located( (By.CLASS_NAME, "LoadingText") ) ) assert "addons" in self.driver.current_url page = requests.head(self.driver.current_url) assert ( page.status_code == 200 ), f"The response status code was {page.status_code}"