Библиотека на базе Selenium с расширенным функционалом. Предназначена для работы с любым веб-сайтом и его страницами
Project description
pageo
Библиотека на базе Selenium с расширенным функционалом. Предназначена для автоматической работы с любыми веб-страницами и их элементами. Вдохновлена статьёй на Хабре и упрощает написание автоматических тестов с реализацией паттерна PageObject. Ускорьте написание кода и упростите его дальнейшую поддержку.
Описание
Зачем нужна эта библиотека, если Selenium из коробки предоставляет инструменты для работы со страницами веб-сайтов? В процессе написания тестов, разработчик регулярно ищет элементы на странице, переходит на другие страницы, получает атрибуты и т.д. Все оборачивается в ожидания, чтобы избежать внезапных ошибок. Библиотека предоставляет базовый класс, методы которого позволяют скрыть часть этой логики и комбинируют в себе различные инструменты базового Selenium, тем самым расширяя функциональность. Благодаря этому ускоряется написание тестов, их понимание и последующая поддержка.
Преимущества перед использованием Selenium из коробки:
- Простое использование. Чтобы начать пользоваться просто отнаследуйтесь от базового класса.
- Быстрая настройка тестов. Установите настройки теста, просто передав их в аргументах класса страницы.
- Классы локаторов. Эти классы скрывают логику поиска элементов и возвращают объект
WebDriver
. - Быстрое использование Page Object. Легко создавать тесы используя паттерн Page Object.
Оглавление
- Установка
- Быстрый старт
- Документация базового класса
- Классы локаторов
- Динамическое добавление локаторов
- Использование в PageObject
Установка
Установите core-page через pip:
pip install pageo
Использование библиотеки подразумевает, что на вашем компьютере уже имеется chromedriver. Если нет, то следует ознакомиться с руководством.
Быстрый старт:
Cоздаем файл для тестируемой страницы и импортируем класс BasePage.
Создаем класс страницы и наследуемся от BasePage. Теперь нам доступны все методы базового класса.
Также импортируем класс локатора IdLocator
. С его помощью будет выполняться поиск элемента.
# about_page.py
from pageo import BasePage
from pageo import IdLocator
class AboutPage(BasePage):
base_url = 'https://www.python.org'
url_suffix = '/about'
search_field_element = IdLocator("id-search-field")
def is_search_field(self):
return True if self.search_field_element else False
Теперь создаем экземпляр класса AboutPage
в тесте и передаем некоторые настройки.
# test_about_page.py
from selenium import webdriver
from page_object.about_page import AboutPage
def test_search_field_exist():
page = AboutPage(driver=webdriver.Chrome(), window_size=(1600, 900))
search_field_exist = page.is_search_field()
assert search_field_exist
Подробнее этот пример описан в разделе про Page Object.
Документация базового класса
Создание объекта
атрибуты класса:
-
base_url - адрес страницы без относительного пути.
Адрес страницы может быть передан без протокола. В таком случае, будет установлен протокол по умолчанию (https). Если адрес страницы имеет протокол http, то его следует указать перед адресом страницы самостоятельно!
-
url_suffix - относительный путь к конкретной странице сайта.
Пример определения атрибутов класса:
from pageo import BasePage
from pageo import IdLocator
class SomePage(BasePage):
base_url = 'https://some_page.com'
url_suffix = '/some_page_on_site'
some_element = IdLocator("some_id")
...
Аргументы класса:
-
driver - объект
WebDriver
. Обязательный аргумент. -
base_url - адрес страницы без относительного пути. По умолчанию None. Необязательный аргумент.
- Передавайте URL в аргументах при создании объекта только в том случае, если адрес не был указан в атрибутах класса страницы.
- Если адрес страницы был указан и в атрибутах класса, и в аргументах при создании объекта, но они отличаются, то будет выброшено исключение UrlDisparityError.
- Если URL не был указан ни в атрибутах класса, ни в аргументах при создании объекта, то будет выброшено исключение UrlAvailabilityError.
Адрес страницы может быть передан без протокола. В таком случае, будет установлен протокол по умолчанию (https). Если адрес страницы имеет протокол http, то его следует указать перед адресом страницы!
-
url_suffix - относительный путь к конкретной странице сайта. По умолчанию None. Необязательный аргумент.
- Передавайте относительный путь в аргументах при создании объекта только в том случае, если относительный путь к конкретной странице не был указан в атрибутах класса страницы.
- Если относительный путь был указан и в атрибутах класса, и в аргументах при создании объекта, но они отличаются, то будет выброшено исключение UrlDisparityError.
-
window_size - размер страницы браузера в формате
(ширина, высота)
. По умолчанию установлено значение(1920, 1080)
. Необязательный аргумент. -
cookies - список с cookie, которые необходимо передать перед открытием страницы. По умолчанию
None
. Необязательный аргумент. -
is_open - булев тип, указывающий на необходимость открыть страницу сразу после создания объекта. По умолчанию
True
.
Рекомендуется предварительно создавать свой объект WebDriver
.
Для примера создадим свой объект WebDriver
и передадим ему опции:
from selenium import webdriver
from page_object.main_page import MainPage
options = webdriver.ChromeOptions()
options.add_argument('--headless')
driver = webdriver.Chrome(options=options)
page = MainPage(driver=driver, base_url='https://google.com')
Можно передавать его непосредственно в класс (без предварительного создания):
from selenium import webdriver
from page_object.main_page import MainPage
page = MainPage(driver=webdriver.Chrome(), base_url='https://google.com')
Метод find_elements
Метод find_elements
возвращает элементы, которые были найдены классом локатора, в виде списка.
Будет возвращен список, даже если был найден только один элемент.
Принимает следующие аргументы:
- locator - строка, которая содержит имя переменной локатора, хранящей веб-элемент.
from page_object.main_page import MainPage
def test_some_element():
page = MainPage(base_url='https://google.com', url_suffix='/doodles')
element = page.find_elements('some_locator_name')
...
Метод custom_wait_until
Метод custom_wait_until
позволяет задавать ожидания на основе пользовательских условий. В случае, когда условие
ожидания, которое нам нужно, не предусмотрено Selenium, пользователь может сам задать условие ожидания на основе какой-либо функции.
Принимает следующие аргументы:
- func_condition - функция предикат, в которой задано условие ожидания.
- duration - время в секундах, в течение которого будет выполняться ожидание.
from pageo import IdLocator
from page_object.main_page import MainPage
def test_some_element():
page = MainPage(base_url='https://google.com', url_suffix='/doodles')
link_button = IdLocator('about-link')
link_button.click()
page.custom_wait_until(lambda driver: driver.current_url != page.url)
...
Метод move_to_element
Метод move_to_element
имитирует наведение мыши на элемент. Комбинирует внутри себя создание объекта ActionChains
,
наведение на элемент и выполнение действия (метод perform).
Метод принимает один аргумент:
- element - объект
WebElement
, на который нужно выполнить наведение мыши.
from pageo import IdLocator
from page_object.main_page import MainPage
def test_some_element():
page = MainPage(base_url='https://google.com', url_suffix='/doodles')
about_button = IdLocator('about-link')
page.move_to_element(about_button)
...
Классы локаторов
Вспомогательные классы локаторов для BasePage
, инкапсулирующие логику поиска элементов по локаторам.
Каждый класс наследуется от абстрактного класса AbstractLocator
.
Использование классов локаторов позволяет создавать их экземпляры в классах страницы как атрибуты класса. Если селектор изменится
или нужно изменить стратегию поиска элемента, то достаточно просто изменить селектор элемента в аргументах класса или сам класс-стратегию.
Каждый класс локатора принимает следующие аргументы:
- selector - селектор искомого элемента. Обязательный аргумент.
- is_many - флаг, указывающий на множественность элементов.
Если False, то будет возвращен один найденный элемент (первый элемент, который соответствует локатору).
Если True, то будет возвращен список всех найденных элементов. - timeout - время в секундах, в течение которого будет выполняться ожидание. По умолчанию 5 секунд.
Каждый класс локатора возвращает объект WebElement
.
Пример использования класса локатора для поиска одного элемента:
from pageo import BasePage
from pageo import ClassNameLocator
class DoodlesPage(BasePage):
base_url = "http://google.com"
url_suffix = "doodles"
some_element = ClassNameLocator("cardlink", timeout=3)
Если элементов много и нужны все:
from pageo import BasePage
from pageo import ClassNameLocator
class DoodlesPage(BasePage):
base_url = "http://google.com"
url_suffix = "doodles"
some_elements = ClassNameLocator("cardlink", is_many=True, timeout=6)
Далее подробней описаны все доступные классы локаторов.
class_name_locator
Класс локатора, выполняющий поиск на основе имени класса элемента.
from pageo import BasePage
from pageo import ClassNameLocator
class DoodlesPage(BasePage):
base_url = "http://google.com"
url_suffix = "doodles"
some_element = ClassNameLocator("cardlink")
css_locator
Класс локатора, выполняющий поиск на основе css-локатора элемента.
from pageo import BasePage
from pageo import CSSLocator
class DoodlesPage(BasePage):
base_url = "http://google.com"
url_suffix = "doodles"
some_element = CSSLocator("#latest-title")
id_locator
Класс локатора, выполняющий поиск на основе атрибута id у тега элемента.
from pageo import BasePage
from pageo import IdLocator
class DoodlesPage(BasePage):
base_url = "http://google.com"
url_suffix = "doodles"
some_element = IdLocator("highlight")
link_text_locator
Класс локатора, выполняющий поиск на основе текста внутри ссылки элемента.
from pageo import BasePage
from pageo import LinkTextLocator
class DoodlesPage(BasePage):
base_url = "http://google.com"
url_suffix = "doodles"
some_element = LinkTextLocator("Подробности")
name_locator
Класс локатора, выполняющий поиск на основе атрибута name у тега элемента.
from pageo import BasePage
from pageo import NameLocator
class DoodlesPage(BasePage):
base_url = "http://google.com"
url_suffix = "doodles"
some_element = NameLocator("q")
partial_link_text_locator
Класс локатора, выполняющий поиск на основе вхождения текста внутри ссылки элемента.
from pageo import BasePage
from pageo import PartialLinkTextLocator
class DoodlesPage(BasePage):
base_url = "http://google.com"
url_suffix = "doodles"
some_element = PartialLinkTextLocator("Подробности")
tag_name_locator
Класс локатора, выполняющий поиск на основе имени тега элемента.
from pageo import BasePage
from pageo import TagNameLocator
class DoodlesPage(BasePage):
base_url = "http://google.com"
url_suffix = "doodles"
some_element = TagNameLocator("input")
xpath_locator
Класс локатора, выполняющий поиск на основе пути XPath до элемента.
from pageo import BasePage
from pageo import XPATHLocator
class DoodlesPage(BasePage):
base_url = "http://google.com"
url_suffix = "doodles"
some_element = XPATHLocator("//*[@id='searchinput'']")
Динамическое добавление локаторов
Может возникнуть ситуация, когда необходимо добавить новые локаторы в класс в самом тесте или в методах класса.
Например, нам нужно автоматически пройти тестирование. Варианты ответа на вопрос расположены вразброс:
from pageo import BasePage
from pageo import XPATHLocator
class ExamPage(BasePage):
pass
def pass_exam(self):
for _ in range(10):
self.add_locators(
answer_text=XPATHLocator(f"//*[text()='{answer}']"),
)
self.answer_text.click()
Такой способ добавления локаторов в класс страницы может быть полезен, когда нужный элемент может меняться и из-за этого необходимо изменять локатор.
Использование в PageObject
Использование паттерна PageObject позволяет упростить написание, поддержку и масштабирование тестов. Базовый класс может в этом помочь.
Допустим, нужно протестировать сайт https://www.python.org/
. Он содержит множество страниц и элементов.
Паттерн подразумевает, что каждая страница будет представлена как отдельный класс с методами страницы.
В таком случае, структура проекта может выглядеть следующим образом:
project/
├── page_object/
│ ├── __init__.py
│ ├── main_page.py
│ └── about_page.py
├── tests/
│ ├── __init__.py
│ ├── test_main_page.py
│ └── test_about_page.py
├── ...
└── ...
Рассмотрим файл about_page.py. Он должен описывать методы, содержащие поиск элементов и взаимодействие с ними.
В нашем случае, протестируем наличие поля для поиска по сайту.
Для поиска элемента на сайте будет использоваться IdLocator
.
# about_page.py
from pageo import BasePage
from pageo import IdLocator
class AboutPage(BasePage):
# Определяем в атрибутах класса базовый URL и относительный путь к конкретной странице.
base_url='https://www.python.org'
url_suffix='/about'
# Определяем в атрибутах класса переменную, которая будет содержать искомый элемент (объект типа WebElement).
search_field_element = IdLocator("id-search-field")
# Описываем метод, содержащий сценарий, который будет использоваться непосредственно в кейсе.
def is_search_field(self):
return True if self.search_field_element else False
Перейдем в файл test_about_page.py. Здесь мы создаем тест-кейс, в котором проверяем сценарий, описанный в классе страницы.
# test_about_page.py
from selenium import webdriver
from page_object.about_page import AboutPage
# Создаем тест, который проверяет наличие поля поиска по сайту.
def test_search_field_exist():
# Создаем экземпляр класса страницы. (base_url и url_suffix были определены в атрибутах класса, так что передавать в аргументах их не нужно.)
page = AboutPage(driver=webdriver.Chrome())
search_field_exist = page.is_search_field()
assert search_field_exist
Благодаря такой структуре проекта и использованию паттерна, мы можем легко поддерживать и писать гибкие сценарии. Даже при значительных изменениях тестируемой страницы, исправление тестов не займет много времени.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
File details
Details for the file pageo-0.3.1.tar.gz
.
File metadata
- Download URL: pageo-0.3.1.tar.gz
- Upload date:
- Size: 22.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/4.0.2 CPython/3.12.1
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 58e6fa016f97f0c9f0b6fead48606950fcb7e0e9c79a35f0fc34ce2c52c32ea1 |
|
MD5 | 64fb96ecbf97da246d2d07f67515b710 |
|
BLAKE2b-256 | e41ab5b98ca40ba4112786e28ebc144dff99122a6d96a7db7406aae3da9f1ec7 |
File details
Details for the file pageo-0.3.1-py3-none-any.whl
.
File metadata
- Download URL: pageo-0.3.1-py3-none-any.whl
- Upload date:
- Size: 23.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/4.0.2 CPython/3.12.1
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | f1e018093204e83832c3f49acaf7c4dcb80e94c9066f542a79425e89ccc3326b |
|
MD5 | d69f386757b2df3f7ccdd67e43fc2c2c |
|
BLAKE2b-256 | ab5449bbc8f85f509a46897ed9012d1a8fa85a5f2abdf61f178d5d12fad07a1c |