Updated UI tests to use the new AMO frontend. (#7565)

* Uses addons-frontend docker image to create an instance of the new frontend.
* Add testing for both mobile and desktop resolutions.
This commit is contained in:
Benjamin Forehand Jr 2018-03-01 14:05:40 -08:00 коммит произвёл GitHub
Родитель 14f80b6a88
Коммит 9747bb84fe
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
23 изменённых файлов: 574 добавлений и 332 удалений

Просмотреть файл

@ -81,5 +81,22 @@ services:
ports:
- "5900"
shm_size: 2g
links:
- "addons-frontend:olympia-frontend.test"
- "nginx:olympia.test"
addons-frontend:
<<: *env
environment:
- NODE_APP_INSTANCE=amo
- NODE_ENV=development
- API_HOST=http://olympia.test
- HOSTNAME=functional.test
ports:
- "4000:4000"
expose:
- "4000"
image: addons/addons-frontend
command: yarn build && yarn start
links:
- "nginx:olympia.test"

Просмотреть файл

@ -18,4 +18,3 @@ port=9001
[rpcinterface:supervisor]
supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface

Просмотреть файл

@ -1,3 +1,5 @@
# -*- coding: utf-8 -*-
from django.core.cache import cache
from django.core.management import call_command
from django.core.management.base import BaseCommand
@ -9,31 +11,40 @@ from olympia.landfill.serializers import GenerateAddonsSerializer
# Featured collections on the homepage.
# Needs to be updated as the homepage is updated
featured_collections = [
'dynamic-media-downloaders',
u'privacy-matters',
u're-imagine-search',
u'dynamic-media-downloaders',
]
# Featured collections on the homepage.
base_collections = [
'bookmark-managers',
'password-managers',
'ad-blockers',
'smarter-shopping',
'be-more-productive',
'watching-videos',
u'bookmark-managers',
u'password-managers',
u'ad-blockers',
u'smarter-shopping',
u'be-more-productive',
u'watching-videos',
]
# Addons that exist in the carousel.
# Needs to be updated as the homepage is updated
carousel_addons = [
'wikipedia-context-menu-search',
'momentumdash',
'undo-close-tab-button',
'grammarly-1',
'facebook-filter',
'gesturefy',
'multi-account-containers',
'tree-style-tab',
'lastpass-password-manager',
hero_addons = [
u'wikiwand-wikipedia-modernized',
u'onetab',
u'kindle-it',
u'search-site-we',
u'youtube-dark-purple',
u'temporary-containers',
u'momentumdash',
u'kimetrak',
u'mailvelope',
u'翻译侠-translate-man',
u'ublock-origin',
u'ghostery',
u'multi-account-containers',
u'searchpreview',
u'forget_me_not',
u'zoom',
]
@ -66,7 +77,7 @@ class Command(BaseCommand):
for addon in base_collections:
serializer.create_a_named_collection_and_addon(
addon, author='mozilla')
for addon in carousel_addons:
for addon in hero_addons:
serializer.create_named_addon_with_author(addon)
serializer.create_installable_addon()
cache.clear()

Просмотреть файл

@ -1,3 +1,5 @@
# -*- coding: utf-8 -*-
import mimetypes
import random
import waffle
@ -61,7 +63,7 @@ class GenerateAddonsSerializer(serializers.Serializer):
status=STATUS_PUBLIC,
users=[UserProfile.objects.get(username=author)],
name=u'{}'.format(name),
slug='{}'.format(name),
slug=u'{}'.format(name),
)
addon.save()
else:
@ -69,7 +71,7 @@ class GenerateAddonsSerializer(serializers.Serializer):
status=STATUS_PUBLIC,
users=[UserProfile.objects.get(username=author.username)],
name=u'{}'.format(name),
slug='{}'.format(name),
slug=u'{}'.format(name),
)
addon.save()
return addon

Просмотреть файл

@ -12,12 +12,19 @@ from olympia import amo
@pytest.fixture
def firefox_options(firefox_options):
"""Firefox options.
These options configure firefox to allow for addon installation,
as well as allowing it to run headless.
"""
firefox_options.set_preference(
'extensions.install.requireBuiltInCerts', False)
firefox_options.set_preference('xpinstall.signatures.required', False)
firefox_options.set_preference('extensions.webapi.testing', True)
firefox_options.set_preference('ui.popup.disable_autohide', True)
firefox_options.add_argument('-foreground')
firefox_options.add_argument('-headless')
firefox_options.log.level = 'trace'
return firefox_options
@ -27,6 +34,23 @@ def firefox_notifications(notifications):
return notifications
@pytest.fixture(scope='function',
params=[(1080, 1920), (414, 738)],
ids=['Resolution: 1080x1920', 'Resolution: 414x738'])
def selenium(selenium, request):
"""Fixture to set custom selenium parameters.
This fixture will also parametrize all of the tests to run them on both a
Desktop resolution and a mobile resolution.
Desktop size: 1920x1080
Mobile size: 738x414 (iPhone 7+)
"""
selenium.set_window_size(*request.param)
return selenium
@pytest.fixture
def fxa_account(base_url):
"""Account used to login to the AMO site."""

Просмотреть файл

@ -6,7 +6,7 @@ from selenium.webdriver.common.action_chains import ActionChains
class Base(Page):
_url = '{base_url}/{locale}'
_amo_header = (By.CLASS_NAME, 'amo-header')
_amo_header = (By.CLASS_NAME, 'Header-title')
def __init__(self, selenium, base_url, locale='en-US', **kwargs):
super(Base, self).__init__(
@ -19,7 +19,7 @@ class Base(Page):
@property
def header(self):
return self.Header(self)
return Header(self)
@property
def logged_in(self):
@ -36,33 +36,59 @@ class Base(Page):
def logout(self):
self.header.click_logout()
class Header(Region):
_root_locator = (By.CLASS_NAME, 'amo-header')
_login_locator = (By.CSS_SELECTOR, '#aux-nav .account a:nth-child(2)')
_logout_locator = (By.CSS_SELECTOR, '.logout > a')
_user_locator = (By.CSS_SELECTOR, '#aux-nav .account .user')
_search_button_locator = (By.CSS_SELECTOR, '.search-button')
_search_textbox_locator = (By.ID, 'search-q')
class Header(Region):
def click_login(self):
self.find_element(*self._login_locator).click()
from pages.desktop.login import Login
return Login(self.selenium, self.page.base_url, timeout=30)
_root_locator = (By.CLASS_NAME, 'Header')
_header_title_locator = (By.CLASS_NAME, 'Header-title')
_explore_locator = (By.CSS_SELECTOR, '.SectionLinks > li:nth-child(1) \
> a:nth-child(1)')
_firefox_logo_locator = (By.CLASS_NAME, 'Header-title')
_extensions_locator = (By.CSS_SELECTOR, '.SectionLinks \
> li:nth-child(2) > a:nth-child(1)')
_login_locator = (By.CSS_SELECTOR, '.Header-auth-button')
_logout_locator = (By.CSS_SELECTOR, '')
_themes_locator = (By.CSS_SELECTOR, '.SectionLinks > li:nth-child(3) > \
a:nth-child(1)')
_user_locator = (By.CSS_SELECTOR, '')
_search_textbox_locator = (By.CLASS_NAME, 'SearchForm-query')
def click_logout(self):
user = self.find_element(*self._user_locator)
logout = self.find_element(*self._logout_locator)
action = ActionChains(self.selenium)
action.move_to_element(user)
action.move_to_element(logout)
action.click()
action.perform()
self.wait.until(lambda s: self.is_element_displayed(
*self._login_locator))
def click_explore(self):
self.find_element(*self._firefox_logo_locator).click()
def search_for(self, term):
self.find_element(*self._search_textbox_locator).send_keys(term)
self.find_element(*self._search_button_locator).click()
from pages.desktop.search import SearchResultList
return SearchResultList(self.selenium, self.page.base_url)
def click_extensions(self):
self.find_element(*self._extensions_locator).click()
from pages.desktop.extensions import Extensions
return Extensions(
self.selenium, self.page.base_url).wait_for_page_to_load()
def click_themes(self):
self.find_element(*self._themes_locator).click()
from pages.desktop.themes import Themes
return Themes(
self.selenium, self.page.base_url).wait_for_page_to_load()
def click_login(self):
self.find_element(*self._login_locator).click()
from pages.desktop.login import Login
return Login(self.selenium, self.page.base_url, timeout=30)
def click_logout(self):
user = self.find_element(*self._user_locator)
logout = self.find_element(*self._logout_locator)
action = ActionChains(self.selenium)
action.move_to_element(user)
action.move_to_element(logout)
action.click()
action.perform()
self.wait.until(lambda s: self.is_element_displayed(
*self._login_locator))
def search_for(self, term):
textbox = self.find_element(*self._search_textbox_locator)
textbox.click()
textbox.send_keys(term)
# Send 'enter' since the mobile page does not have a submit button
textbox.send_keys(u'\ue007')
from pages.desktop.search import Search
return Search(self.selenium, self.page).wait_for_page_to_load()

Просмотреть файл

@ -0,0 +1,36 @@
from pypom import Region
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as expected
from pages.desktop.base import Base
class Categories(Base):
URL_TEMPLATE = 'extensions/categories/'
_categories_locator = (By.CLASS_NAME, 'Categories-item')
_mobile_categories_locator = (By.CLASS_NAME, 'LandingPage-button')
def wait_for_page_to_load(self):
self.wait.until(
expected.invisibility_of_element_located(
(By.CLASS_NAME, 'LoadingText')))
@property
def category_list(self):
categories = self.find_elements(*self._categories_locator)
return [self.CategoryItem(self, el) for el in categories]
class CategoryItem(Region):
_link_locator = (By.CLASS_NAME, 'Categories-link')
@property
def name(self):
return self.find_element(*self._link_locator).text
def click(self):
self.find_element(*self._link_locator).click()
from pages.desktop.category import Category
return Category(self.selenium, self.page)

Просмотреть файл

@ -0,0 +1,29 @@
from pypom import Region
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as expected
from pages.desktop.base import Base
class Category(Base):
_root_locator = (By.CLASS_NAME, 'Category')
_category_header_locator = (By.CLASS_NAME, 'CategoryHeader')
def wait_for_page_to_load(self):
self.wait.until(
expected.invisibility_of_element_located(
(By.CLASS_NAME, 'LoadingText')))
return self
@property
def header(self):
return self.Header(self)
class Header(Region):
_category_name_locator = (By.CLASS_NAME, 'CategoryHeader-name')
@property
def name(self):
return self.find_element(*self._category_name_locator).text

Просмотреть файл

@ -1,29 +1,24 @@
from pypom import Region
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as expected
from base import Base
from pages.desktop.base import Base
class Details(Base):
"""Details page."""
class Detail(Base):
_root_locator = (By.CLASS_NAME, 'Addon-extension')
_addon_name_locator = (By.CLASS_NAME, 'Addon-title')
_install_button_locator = (By.CLASS_NAME, 'InstallButton-button')
def wait_for_page_to_load(self):
self.wait.until(lambda _: self.description_header.name)
self.wait.until(
expected.invisibility_of_element_located(
(By.CLASS_NAME, 'LoadingText')))
return self
@property
def description_header(self):
return self.DescriptionHeader(self)
def name(self):
return self.find_element(*self._addon_name_locator).text
class DescriptionHeader(Region):
"""Represents the header of the detail page."""
_root_locator = (By.CLASS_NAME, 'addon-description-header')
_install_button_locator = (By.CLASS_NAME, 'add')
_name_locator = (By.TAG_NAME, 'h1')
@property
def name(self):
return self.find_element(*self._name_locator).text
@property
def install_button(self):
return self.find_element(*self._install_button_locator)
def install(self):
self.find_element(*self._install_button_locator).click()

Просмотреть файл

@ -0,0 +1,60 @@
from pypom import Region
from selenium.webdriver.common.by import By
from pages.desktop.base import Base
class Extensions(Base):
URL_TEMPLATE = 'extensions/'
_featured_addons_locator = (By.CLASS_NAME, 'FeaturedAddons')
_top_rated_locator = (By.CLASS_NAME, 'HighlyRatedAddons')
_title_locator = (By.CLASS_NAME, 'LandingPage-addonType-name')
_trending_addons_locator = (By.CLASS_NAME, 'TrendingAddons')
def wait_for_page_to_load(self):
self.wait.until(
lambda _: self.is_element_displayed(*self._title_locator))
element = self.find_element(*self._title_locator)
return element
@property
def extension_header(self):
return self.ExtensionHeader(self)
@property
def featured_extensions(self):
items = self.find_elements(*self._featured_addons_locator)
return [self.ExtensionDetail(self, el) for el in items]
@property
def categories(self):
from regions.desktop.categories import Categories
return Categories(self)
class ExtensionHeader(Region):
_root_locator = (By.CLASS_NAME, 'Category')
_header_locator = (By.CLASS_NAME, 'CategoryHeader')
_category_name_locator = (By.CLASS_NAME, 'CategoryHeader-name')
@property
def name(self):
return self.find_element(*self._category_name_locator).text
class ExtensionsList(Region):
_extensions_locator = (By.CLASS_NAME, 'SearchResult')
@property
def list(self):
items = self.find_elements(*self._extensions_locator)
return [self.ExtensionDetail(self.page, el) for el in items]
class ExtensionDetail(Region):
_extension_name_locator = (By.CLASS_NAME, 'SearchResult-name')
@property
def name(self):
return self.find_element(*self._extension_name_locator).text

Просмотреть файл

@ -1,144 +1,115 @@
from pypom import Region
from selenium.webdriver.common.by import By
from base import Base
from pages.desktop.base import Base
class Home(Base):
"""Addons Home page"""
_extensions_category_locator = (By.CLASS_NAME, 'Home-CuratedCollections')
_featured_extensions_locator = (By.CLASS_NAME, 'Home-FeaturedExtensions')
_featured_themes_locator = (By.CLASS_NAME, 'Home-FeaturedThemes')
_popular_extensions_locator = (By.CLASS_NAME, 'Home-PopularExtensions')
_popular_themes_locator = (By.CLASS_NAME, 'Home-PopularThemes')
_themes_category_locator = (By.CLASS_NAME, 'Home-CuratedThemes')
@property
def most_popular(self):
return self.MostPopular(self)
def popular_extensions(self):
el = self.find_element(*self._popular_extensions_locator)
return self.Extensions(self, el)
@property
def featured_extensions(self):
return self.FeaturedExtensions(self)
@property
def featured_collections(self):
return self.FeaturedCollections(self)
el = self.find_element(*self._featured_extensions_locator)
return self.Extensions(self, el)
@property
def featured_themes(self):
return self.FeaturedThemes(self)
el = self.find_element(*self._featured_themes_locator)
return self.Themes(self, el)
class MostPopular(Region):
"""Most popular extensions region"""
_root_locator = (By.ID, 'popular-extensions')
_extension_locator = (By.CSS_SELECTOR, '.toplist li')
@property
def popular_themes(self):
el = self.find_element(*self._popular_themes_locator)
return self.Themes(self, el)
@property
def extension_category(self):
el = self.find_element(*self._extensions_category_locator)
return self.Category(self, el)
@property
def theme_category(self):
el = self.find_element(*self._themes_category_locator)
return self.Category(self, el)
class Category(Region):
_extensions_locator = (By.CLASS_NAME, 'Home-SubjectShelf-list-item')
@property
def extensions(self):
extensions = self.find_elements(*self._extension_locator)
return [self.Extension(self.page, el) for el in extensions]
def list(self):
items = self.find_elements(*self._extensions_locator)
return [self.CategoryDetail(self.page, el) for el in items]
class Extension(Region):
class CategoryDetail(Region):
_extension_link_locator = (By.CLASS_NAME, 'Home-SubjectShelf-link')
_extension_name_locator = (
By.CSS_SELECTOR, '.Home-SubjectShelf-link span')
_name_locator = (By.CLASS_NAME, 'name')
_users_locator = (By.TAG_NAME, 'small')
def __repr__(self):
return '{0.name} ({0.users:,} users)'.format(self)
@property
def name(self):
return self.find_element(*self._extension_name_locator).text
def click(self):
"""Clicks on the addon."""
self.find_element(*self._name_locator).click()
from pages.desktop.details import Details
return Details(
self.selenium, self.page.base_url).wait_for_page_to_load()
self.root.click()
from pages.desktop.extensions import Extensions
return Extensions(self.selenium, self.page.base_url)
@property
def name(self):
"""Extension name"""
return self.find_element(*self._name_locator).text
@property
def users(self):
"""Number of users that have downloaded the extension"""
users_str = self.find_element(*self._users_locator).text
return int(users_str.split()[0].replace(',', ''))
class FeaturedExtensions(Region):
"""Featured Extension region"""
_root_locator = (By.ID, 'featured-extensions')
_extension_locator = (By.CSS_SELECTOR, 'section > li > .addon')
_see_all_locator = (By.CSS_SELECTOR, 'h2 > a')
class Extensions(Region):
_browse_all_locator = (By.CSS_SELECTOR, '.Card-footer-link > a')
_extensions_locator = (By.CLASS_NAME, 'SearchResult')
_extension_card_locator = (By.CSS_SELECTOR, '.Home-category-li')
@property
def extensions(self):
extentions = self.find_elements(*self._extension_locator)
return [self.Extension(self.page, el) for el in extentions]
class Extension(Region):
_name_locator = (By.CSS_SELECTOR, 'h3')
_link_locator = (By.CSS_SELECTOR, '.addon .summary a')
def click(self):
"""Clicks the addon link"""
self.find_element(*self._link_locator).click()
from pages.desktop.details import Details
return Details(
self.selenium, self.page.base_url).wait_for_page_to_load()
@property
def name(self):
return self.find_element(*self._name_locator).text
class FeaturedThemes(Region):
"""Featured Themes region"""
_root_locator = (By.ID, 'featured-themes')
_themes_locator = (By.CSS_SELECTOR, 'li')
_see_all_link = (By.CLASS_NAME, 'seeall')
def list(self):
items = self.find_elements(*self._extensions_locator)
return [Home.ExtensionsList(self.page, el) for el in items]
@property
def themes(self):
"""Represents all themes found within the Featured Themes region.
"""
themes = self.find_elements(*self._themes_locator)
return [self.Theme(self, el) for el in themes]
def browse_all(self):
self.find_element(*self._browse_all_locator).click()
from pages.desktop.search import Search
search = Search(self.selenium, self.page.base_url)
return search.wait_for_page_to_load()
def see_all(self):
"""Clicks the 'See All' link."""
self.find_element(*self._see_all_link).click()
from pages.desktop.themes import Themes
return Themes(
self.selenium, self.page.base_url).wait_for_page_to_load()
class Theme(Region):
_name_locator = (By.CSS_SELECTOR, 'h3')
@property
def name(self):
"""Theme Name"""
return self.find_element(*self._name_locator).text
class FeaturedCollections(Region):
"""Featured Collections region"""
_root_locator = (By.ID, 'featured-collections')
_items_locator = (By.CSS_SELECTOR, 'li')
_see_all_link = (By.CSS_SELECTOR, 'h2 a')
class Themes(Region):
_browse_all_locator = (By.CSS_SELECTOR, '.Card-footer-link > a')
_themes_locator = (By.CLASS_NAME, 'SearchResult--theme')
_theme_card_locator = (By.CSS_SELECTOR, '.Home-category-li')
@property
def collections(self):
"""Represents all Collections found within the Featured Collections
"""
collections = self.find_elements(*self._items_locator)
return[self.Collection(self.page, el) for el in collections]
def list(self):
items = self.find_elements(*self._themes_locator)
return [Home.ExtensionsList(self.page, el) for el in items]
def see_all(self):
"""Clicks the 'See All' link."""
self.find_element(*self._see_all_link).click()
from pages.desktop.collections import Collections
return Collections(
self.selenium, self.page.base_url).wait_for_page_to_load()
@property
def browse_all(self):
self.find_element(*self._browse_all_locator).click()
from pages.desktop.search import Search
search = Search(self.selenium, self.page.base_url)
return search.wait_for_page_to_load()
class Collection(Region):
"""Individual Collection region"""
_name_locator = (By.TAG_NAME, 'h3')
class ExtensionsList(Region):
@property
def name(self):
"""Collection name"""
return self.find_element(*self._name_locator).text
_extension_link_locator = (By.CLASS_NAME, 'SearchResult-link')
_extension_name_locator = (By.CLASS_NAME, 'SearchResult-name')
@property
def name(self):
return self.find_element(*self._extension_name_locator).text
def click(self):
self.find_element(*self._extension_link_locator).click()
from pages.desktop.extensions import Extensions
return Extensions(self.selenium, self.page.base_url)

Просмотреть файл

@ -1,18 +0,0 @@
from selenium.webdriver.common.by import By
import selenium.webdriver.support.expected_conditions as EC
from pypom import Region
class Sorter(Region):
"""Helper class for sorting."""
_root_locator = (By.ID, 'sorter')
_sort_by_type_locator = (By.CSS_SELECTOR, 'ul > li')
_updating_locator = (By.CSS_SELECTOR, '.updating')
def sort_by(self, sort):
"""Clicks the sort button for the requested sort-order."""
els = self.find_elements(*self._sort_by_type_locator)
next(el for el in els if el.text == sort).click()
self.wait.until(
EC.invisibility_of_element_located(self._updating_locator))

Просмотреть файл

@ -1,54 +1,77 @@
from pypom import Region
from selenium.common.exceptions import NoSuchElementException
from pypom import Page, Region
from selenium.webdriver.common.by import By
from base import Base
from selenium.webdriver.support import expected_conditions as expected
class SearchResultList(Base):
"""Search page"""
_results_locator = (By.CSS_SELECTOR, 'div.items div.item.addon')
_search_text_locator = (By.CSS_SELECTOR, '.primary > h1')
class Search(Page):
_search_box_locator = (By.CLASS_NAME, 'SearchForm-query')
_submit_button_locator = (By.CLASS_NAME, 'SearchForm-submit-button')
_search_filters_sort_locator = (By.ID, 'SearchFilters-Sort')
_search_filters_type_locator = (By.ID, 'SearchFilters-AddonType')
_search_filters_os_locator = (By.ID, 'SearchFilters-OperatingSystem')
def wait_for_page_to_load(self):
self.wait.until(lambda _: self.find_element(
self._search_text_locator).is_displayed())
self.wait.until(
expected.invisibility_of_element_located(
(By.CLASS_NAME, 'LoadingText')))
return self
@property
def results(self):
"""List of results"""
elements = self.selenium.find_elements(*self._results_locator)
return [self.SearchResultItem(self, el) for el in elements]
def result_list(self):
return self.SearchResultList(self)
def sort_by(self, category, attribute):
from pages.desktop.regions.sorter import Sorter
Sorter(self).sort_by(category)
def filter_by_sort(self, value):
self.find_element(*self._search_filters_sort_locator).click()
self.find_element(*self._search_filters_sort_locator).send_keys(value)
class SearchResultItem(Region):
"""Represents individual results on the search page."""
_name_locator = (By.CSS_SELECTOR, 'h3 > a')
_rating_locator = (By.CSS_SELECTOR, '.rating .stars')
_users_sort_locator = (By.CSS_SELECTOR, '.vitals .adu')
def filter_by_type(self, value):
self.find_element(*self._search_filters_type_locator).click()
self.find_element(*self._search_filters_type_locator).send_keys(value)
def filter_by_os(self, value):
self.find_element(*self._search_filters_os_locator).click()
self.find_element(*self._search_filters_os_locator).send_keys(value)
class SearchResultList(Region):
_result_locator = (By.CLASS_NAME, 'SearchResult')
_theme_locator = (By.CLASS_NAME, 'SearchResult--theme')
_extension_locator = (By.CLASS_NAME, 'SearchResult-name')
@property
def name(self):
"""Extension Name"""
return self.find_element(*self._name_locator).text
def extensions(self):
items = self.find_elements(*self._result_locator)
return [self.ResultListItems(self, el) for el in items]
@property
def users(self):
"""Extensions users"""
number = self.find_element(*self._users_sort_locator).text
if 'downloads' in number:
raise AssertionError('Found weekly downloads instead')
return int(number.split()[0].replace(',', ''))
def themes(self):
items = self.find_elements(*self._theme_locator)
return [self.ResultListItems(self, el) for el in items]
@property
def rating(self):
"""Returns the rating"""
try:
rating = self.find_element(*self._rating_locator).text
class ResultListItems(Region):
_rating_locator = (By.CSS_SELECTOR, '.Rating--small')
_search_item_name_locator = (By.CSS_SELECTOR,
'.SearchResult-contents > h2')
_users_locator = (By.CLASS_NAME, 'SearchResult-users-text')
@property
def name(self):
return self.find_element(*self._search_item_name_locator).text
def link(self):
self.find_element(*self._search_item_name_locator).click()
@property
def users(self):
users = self.find_element(*self._users_locator).text
return int(
users.split()[0].replace(',', '').replace('users', ''))
@property
def rating(self):
"""Returns the rating"""
rating = self.find_element(
*self._rating_locator).get_property('title')
return int(rating.split()[1])
except NoSuchElementException:
return 0

Просмотреть файл

@ -1,33 +1,20 @@
from pypom import Region
from selenium.webdriver.common.by import By
from base import Base
from pages.desktop.base import Base
class Themes(Base):
"""Themes page."""
URL_TEMPLATE = 'themes/'
_browse_all_locator = (By.CSS_SELECTOR, '.Card-footer-link > a')
_title_locator = (By.CLASS_NAME, 'LandingPage-addonType-name')
def wait_for_page_to_load(self):
self.wait.until(lambda _: self.featured.themes[0].name)
return self
self.wait.until(
lambda _: self.is_element_displayed(*self._title_locator))
return self.find_element(*self._title_locator)
@property
def featured(self):
return self.Featured(self)
class Featured(Region):
"""Represents the Featured region on the themes page."""
_root_locator = (By.CLASS_NAME, 'personas-featured')
_theme_locator = (By.CSS_SELECTOR, '.persona')
@property
def themes(self):
theme = self.find_elements(*self._theme_locator)
return [Themes.Theme(self.page, el) for el in theme]
class Theme(Region):
"""Represents an individual theme."""
_name_locator = (By.CSS_SELECTOR, 'h3')
@property
def name(self):
return self.find_element(*self._name_locator).text
def browse_all(self):
self.find_element(*self._browse_all_locator).click()

Просмотреть файл

Просмотреть файл

@ -0,0 +1,26 @@
from pypom import Region
from selenium.webdriver.common.by import By
class Categories(Region):
_root_locator = (By.CLASS_NAME, 'Categories')
_categories_locator = (By.CLASS_NAME, 'Categories-item')
_mobile_categories_locator = (By.CLASS_NAME, 'LandingPage-button')
@property
def category_list(self):
items = self.find_elements(*self._categories_locator)
return [self.CategoryList(self, el) for el in items]
class CategoryList(Region):
_name_locator = (By.CLASS_NAME, 'Categories-link')
@property
def name(self):
return self.find_element(*self._name_locator).text
def click(self):
self.root.click()
from pages.desktop.category import Category
return Category(self.selenium, self.page)

Просмотреть файл

@ -0,0 +1,34 @@
from pypom import Region
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as expected
class Search(Region):
_search_results_locator = (By.CLASS_NAME, 'SearchForm-suggestions-item')
def wait_for_region_to_load(self):
self.wait.until(
expected.invisibility_of_element_located(
(By.CLASS_NAME, 'LoadingText')))
return self
@property
def result_list(self):
items = self.find_elements(*self._search_results_locator)
return [self.SearchResultList(self.page, el) for el in items]
class SearchResultList(Region):
_search_item_name_locator = (By.CLASS_NAME, 'Suggestion-name')
_search_item_link_locator = (By.CLASS_NAME, 'Suggestion')
@property
def name(self):
return self.find_element(*self._search_item_name_locator).text
def link(self):
self.find_element(*self._search_item_link_locator).click()
from pages.desktop.detail import Detail
return Detail(
self.selenium, self.page.base_url).wait_for_page_to_load()

Просмотреть файл

@ -1,6 +1,6 @@
[tool:pytest]
addopts = -r=a -vs --showlocals --tb=short
addopts = -r=a -vs --showlocals --tb=short --html=ui-test.html --self-contained-html
sensitive_url = mozilla\.(com|org)
xfail_strict = true
DJANGO_SETTINGS_MODULE = settings
base_url = http://olympia.test:80
base_url = http://olympia-frontend.test:4000

Просмотреть файл

@ -1,70 +1,71 @@
import pytest
from pages.desktop.categories import Categories
from pages.desktop.extensions import Extensions
from pages.desktop.home import Home
@pytest.mark.nondestructive
def test_there_are_ten_most_popular_extensions(
base_url, selenium):
"""Ten most popular add-ons are listed"""
def test_there_are_6_extension_categories(base_url, selenium):
page = Home(selenium, base_url).open()
assert len(page.most_popular.extensions) == 10
assert len(page.extension_category.list) == 6
@pytest.mark.nondestructive
def test_most_popular_extensions_are_sorted_by_users(
base_url, selenium):
"""Most popular add-ons are sorted by popularity"""
def test_there_are_6_theme_categories(base_url, selenium):
page = Home(selenium, base_url).open()
extensions_page = page.most_popular.extensions
sorted_by_users = sorted(extensions_page,
key=lambda e: e.users, reverse=True)
assert sorted_by_users == extensions_page
@pytest.mark.smoke
@pytest.mark.nondestructive
def test_that_clicking_on_addon_name_loads_details_page(
base_url, selenium):
"""Details page addon name matches clicked addon"""
page = Home(selenium, base_url).open()
name = page.most_popular.extensions[0].name
extension_page = page.most_popular.extensions[0].click()
assert name in extension_page.description_header.name
@pytest.mark.smoke
@pytest.mark.nondestructive
def test_that_featured_themes_exist_on_the_home(
base_url, selenium):
"""Featured themes are displayed"""
page = Home(selenium, base_url).open()
assert len(page.featured_themes.themes) == 6
assert len(page.theme_category.list) == 6
@pytest.mark.nondestructive
def test_that_clicking_see_all_themes_link_works(
base_url, selenium):
"""Amount of featured themes matches on both pages"""
def test_extensions_section_load_correctly(base_url, selenium):
page = Home(selenium, base_url).open()
themes = page.featured_themes.themes
theme_page = page.featured_themes.see_all()
assert len(themes) == len(theme_page.featured.themes)
ext_page = page.header.click_extensions()
assert 'Extensions' in ext_page.text
@pytest.mark.nondestructive
def test_that_featured_extensions_exist_on_the_home(
base_url, selenium):
"""Featured extensions exist on home page"""
page = Home(selenium, base_url).open()
assert len(page.featured_extensions.extensions) >= 1
def test_explore_section_loads(base_url, selenium):
page = Extensions(selenium, base_url).open()
page.header.click_explore()
assert 'firefox/' in selenium.current_url
@pytest.mark.nondestructive
def test_that_clicking_see_all_collections_link_works(
base_url, selenium):
"""Amount of featured themes matches on both pages"""
def test_themes_section_loads(base_url, selenium):
page = Home(selenium, base_url).open()
collections = page.featured_collections.collections
collections_page = page.featured_collections.see_all()
assert len(collections_page.collections) >= len(collections)
themes_page = page.header.click_themes()
assert 'Themes' in themes_page.text
@pytest.mark.nondestructive
def test_browse_all_button_loads_correct_page(base_url, selenium):
page = Home(selenium, base_url).open()
page.featured_extensions.browse_all
assert 'type=extension' in selenium.current_url
@pytest.mark.nondestructive
def test_browse_all_themes_button_loads_correct_page(
base_url, selenium):
page = Home(selenium, base_url).open()
page.popular_themes.browse_all
assert 'type=persona' in selenium.current_url
@pytest.mark.nondestructive
def test_category_loads_extensions(base_url, selenium):
page = Home(selenium, base_url).open()
category = page.extension_category.list[0]
category_name = category.name
category.click()
assert category_name in selenium.current_url
@pytest.mark.nondestructive
def test_category_section_loads_correct_category(base_url, selenium):
page = Categories(selenium, base_url).open()
item = page.category_list[0]
name = item.name
category = item.click()
assert name in category.header.name

Просмотреть файл

@ -1,17 +1,17 @@
import pytest
from pages.desktop.details import Details
from pages.desktop.details import Detail
@pytest.mark.nondestructive
def test_addon_install(
base_url, selenium, firefox, firefox_notifications):
"""Test that navigates to an addon and installs it."""
selenium.get('{}/firefox/addon/ui-test-install'.format(base_url))
addon = Details(selenium, base_url)
assert 'Ui-Addon-Install' in addon.description_header.name
addon.description_header.install_button.click()
selenium.get('{}/addon/ui-test-install'.format(base_url))
addon = Detail(selenium, base_url)
assert 'Ui-Addon-Install' in addon.name
addon.install()
firefox.browser.wait_for_notification(
firefox_notifications.AddOnInstallBlocked).allow()
firefox.browser.wait_for_notification(

Просмотреть файл

@ -1,31 +1,50 @@
# -*- coding: utf-8 -*-
import pytest
from pages.desktop.home import Home
from pages.desktop.extensions import Extensions
from pages.desktop.themes import Themes
from pages.desktop.search import Search
@pytest.mark.smoke
@pytest.mark.nondestructive
def test_that_searching_for_addon_returns_addon_as_first_result(
base_url, es_test, selenium):
"""Test searching for an addon returns the addon."""
def test_search_loads_and_navigates_to_correct_page(base_url, selenium):
page = Home(selenium, base_url).open()
name = page.most_popular.extensions[0].name
search_page = page.search_for(name)
assert name in search_page.results[0].name
assert name in selenium.title
addon_name = page.featured_extensions.list[0].name
search = page.header.search_for(addon_name)
search_name = search.result_list.extensions[0].name
assert addon_name in search_name
assert search_name in search.result_list.extensions[0].name
@pytest.mark.native
@pytest.mark.nondestructive
def test_search_loads_correct_results(base_url, selenium):
page = Home(selenium, base_url).open()
addon_name = page.featured_extensions.list[0].name
items = page.search_for(addon_name)
assert addon_name in items.result_list.extensions[0].name
@pytest.mark.nondestructive
def test_legacy_extensions_do_not_load(base_url, selenium):
page = Home(selenium, base_url).open()
term = 'Video Download Manager'
items = page.search_for(term)
for item in items.result_list.extensions:
assert term not in item.name
@pytest.mark.parametrize('category, sort_attr', [
['Most Users', 'users'],
['Top Rated', 'rating']])
def test_sorting_by(
base_url, selenium, es_test, category, sort_attr):
"""Test searching for an addon and sorting."""
page = Home(selenium, base_url).open()
name = page.most_popular.extensions[0].name
search_page = page.search_for(name)
search_page.sort_by(category, sort_attr)
results = [getattr(i, sort_attr) for i in search_page.results]
Home(selenium, base_url).open()
addon_name = 'Ui-addon'
selenium.get('{}/search/?&q={}&sort={}'.format(
base_url, addon_name, sort_attr))
search_page = Search(selenium, base_url)
results = [getattr(i, sort_attr)
for i in search_page.result_list.extensions]
assert sorted(results, reverse=True) == results

Просмотреть файл

@ -56,7 +56,7 @@ commands =
commands =
make -f Makefile-docker update_deps
make -f Makefile-docker ui-tests
pytest --driver Firefox --variables tests/ui/variables.json --html=ui-test.html --self-contained-html tests/ui {posargs}
pytest --driver Firefox -v tests/ui/ {posargs}
[testenv:assets]
commands =