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}"