Библиотека на базе Selenium с расширенным функционалом. Предназначена для работы с любым веб-сайтом и его страницами
Project description
pageo
Библиотека на базе Selenium с расширенным функционалом. Предназначена для автоматической работы с любыми веб-страницами и их элементами. Вдохновлена статьёй на Хабре и упрощает написание автоматических тестов с реализацией паттерна PageObject. Ускорьте написание кода, а также сделайте его лаконичнее и яснее.
Описание
Зачем нужна эта библиотека, если есть Selenium из коробки, который и предоставляет методы для работы со страницами веб-сайтов? В процессе написания тестов, разработчик регулярно ищет элементы на странице, переходит на другие страницы, получает аттрибуты и т.д.. Все это, как правило, оборачивается в ожидания, чтобы избежать внезапных ошибок. Библиотека предоставляет базовый класс, методы которого позволяют скрыть часть этой логики, а также комбинируют в себе различные инструменты базового Selenium, тем самым расширяя функциональность. Благодаря этому ускоряется написание тестов, их понимание и последующая поддержка.
Преимущества перед использованием Selenium из коробки:
- Простое использование путем наследования от базового класса в классы конкретных страниц.
- Возможность установить настройки для теста, просто передав их в аргументах класса страницы.
- Базовые методы поиска элементов расширены и включают в себя явное ожидание.
- Классы локаторов, скрывающие логику поиска элементов и возвращающие объект
WebDriver
.
Оглавление
Установка
Установите core-page через pip:
pip install pageo
Использование библиотеки подразумевает, что на вашем компьютере уже имеется chromedriver. Если нет, то следует ознакомиться с руководством.
Быстрый старт:
Cоздаем файл для тестируемой страницы и импортируем класс BasePage.
Создаем класс страницы и наследуемся от BasePage. Теперь нам доступны все методы базового класса.
Также импортируем класс локатора IdLocator
. С его помощью будет выполняться поиск элемента.
# about_page.py
from pageo import BasePage
from pageo.locators import IdLocator
class AboutPage(BasePage):
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 about_page import AboutPage
def test_search_field_exist():
page = AboutPage(
driver=webdriver.Chrome(),
base_url='https://www.python.org',
url_suffix='/about',
)
search_field_exist = page.is_search_field()
print(page.is_search_field())
assert search_field_exist
Подробнее этот пример описан в разделе про Page Object.
Документация базового класса
Создание объекта
Все возможные аргументы класса:
- driver - объект
WebDriver
. Обязательный аргумент. - base_url - адрес страницы без относительного пути.
Перед адресом страницы должен быть указан протокол!
Пример:https://google.com
- window_size - размер страницы браузера в формате
(ширина, высота)
. По умолчанию установлено значение (1920, 1080). - url_suffix - относительный путь к конкретной странице сайта. По умолчанию относительный путь отсутствует. \
Рекомендуется предварительно создавать свой объект WebDriver
.
Для примера создадим свой объект WebDriver
и передадим ему опции:
from selenium import webdriver
from 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 main_page import MainPage
page = MainPage(driver=webdriver.Chrome(), base_url='https://google.com')
Метод find_element
Метод find_element
ищет элемент на странице по локатору в течение определенного времени. Если элемент найден, то возвращает его.
Иначе выбрасывает TimeoutException.
Принимает следующие аргументы:
- by - Стратегия для поиска элемента. Обязательный аргумент.
- selector - Селектор элемента, который необходимо найти. Обязательный аргумент.
- duration - время в секундах, в течение которого будет осуществляться поиск элемента. Значение по умолчанию - 5 секунд.
from selenium.webdriver.common.by import By
from page_objects import MainPage
def test_some_element():
page = MainPage(base_url='https://google.com', url_suffix='/doodles')
element = page.find_element(By.ID, 'about-link')
Метод find_elements
Метод find_element
ищет все элементы на странице по локатору
в течение определенного времени. Если элементы найдены, то возвращает список из этих элементов.
Иначе выбрасывает TimeoutException.
Принимает следующие аргументы:
- by - Стратегия для поиска элементов. Обязательный аргумент.
- selector - Селектор элементов, которые необходимо найти. Обязательный аргумент.
- duration - время в секундах, в течение которого будет осуществляться поиск элементов. Значение по умолчанию - 5 секунд.
from selenium.webdriver.common.by import By
from page_objects import MainPage
def test_some_element():
page = MainPage(base_url='https://google.com', url_suffix='/doodles')
element = page.find_elements(By.ID, 'nav-list')
Метод custom_wait_until
Метод custom_wait_until
позволяет задавать ожидания на основе пользовательских условий. В случае, когда условие
ожидания, которое нам нужно, не предусмотрено Selenium, пользователь может сам задать условие ожидания на основе какой-либо функции.
Принимает следующие аргументы:
- func_condition - функция предикат, в которой задано условие ожидания.
- duration - время в секундах, в течение которого будет выполняться ожидание.
from selenium.webdriver.common.by import By
from page_objects import MainPage
def test_some_element():
page = MainPage(base_url='https://google.com', url_suffix='/doodles')
page.find_element(By.ID, 'about-link').click()
page.custom_wait_until(lambda browser: browser.current_url != page.url)
...
Метод move_to_element
Метод move_to_element
имитирует наведение мыши на элемент. Комбинирует внутри себя создание объекта ActionChains
,
наведение на элемент и выполнение действия (метод perform).
Метод принимает один аргумент:
- element - объект
WebElement
, на который нужно выполнить наведение мыши.
from selenium.webdriver.common.by import By
from page_objects import MainPage
def test_some_element():
page = MainPage(base_url='https://google.com', url_suffix='/doodles')
about_button = page.find_element(By.ID, 'about-link')
page.move_to_element(about_button)
...
Классы локаторов
Вспомогательные классы локаторов для BasePage
, инкапсулирующие логику поиска элементов по локаторам.
Каждый класс наследуется от абстрактного класса AbstractLocator
.
Использование классов локаторов позволяет объявлять их в классах страницы как аттрибуты класса. Если селектор изменится
или нужно изменить стратегию поиска элемента, то достаточно просто изменить сам класс-стратегию или селектор элемента в аргументах.
Принимаемые аргументы:
- by - стратегия поиска элемента (например, по аттрибуту ID). Обязательный аргумент.
- locator - сам локатор. Обязательный аргумент.
Каждый класс локатора возвращает объект WebElement
.
class_name_locator
Класс локатора, выполняющий поиск на основе имени класса элемента.
from pageo import BasePage
from pageo import ClassNameLocator
class SomePage(BasePage):
some_element = ClassNameLocator("some-class-name")
...
css_locator
Класс локатора, выполняющий поиск на основе css-локатора элемента.
from pageo import BasePage
from pageo import CSSLocator
class SomePage(BasePage):
some_element = CSSLocator("some-css-locator")
...
id_locator
Класс локатора, выполняющий поиск на основе аттрибута id у тега элемента.
from pageo import BasePage
from pageo import IdLocator
class SomePage(BasePage):
some_element = IdLocator("some-id-attribute")
...
link_text_locator
Класс локатора, выполняющий поиск на основе текста внутри ссылки элемента.
from pageo import BasePage
from pageo import LinkTextLocator
class SomePage(BasePage):
some_element = LinkTextLocator("some-link-text")
...
name_locator
Класс локатора, выполняющий поиск на основе аттрибута name у тега элемента.
from pageo import BasePage
from pageo import NameLocator
class SomePage(BasePage):
some_element = NameLocator("some-name-attribute")
...
partial_link_text_locator
Класс локатора, выполняющий поиск на основе вхождения текста внутри ссылки элемента.
from pageo import BasePage
from pageo import PartialLinkTextLocator
class SomePage(BasePage):
some_element = PartialLinkTextLocator("some-partial-link-text")
...
tag_name_locator
Класс локатора, выполняющий поиск на основе имени тега элемента.
from pageo import BasePage
from pageo import TagNameLocator
class SomePage(BasePage):
some_element = TagNameLocator("some-tag-name")
...
xpath_locator
Класс локатора, выполняющий поиск на основе пути XPath до элемента.
from pageo import BasePage
from pageo import XPATHLocator
class SomePage(BasePage):
some_element = XPATHLocator("some-xpath")
...
Использование в 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):
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():
page = AboutPage(
driver=webdriver.Chrome(),
base_url='https://www.python.org',
url_suffix='/about',
)
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.1.2.tar.gz
.
File metadata
- Download URL: pageo-0.1.2.tar.gz
- Upload date:
- Size: 17.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/4.0.2 CPython/3.11.4
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 274274d84ce6bd5dc94899ba152142248fb2ba29004cdd3a27e79fef66c6c0ad |
|
MD5 | 382e92c13146a5a44dca59912ce30db2 |
|
BLAKE2b-256 | 5e5c2e7b160b3092320df1a4ec1a3777c875dfde143a161c4e4b7c855a0896c5 |
File details
Details for the file pageo-0.1.2-py3-none-any.whl
.
File metadata
- Download URL: pageo-0.1.2-py3-none-any.whl
- Upload date:
- Size: 19.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/4.0.2 CPython/3.11.4
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 462a48e6d614746b7a29e71998db165e7b890f4bb62d0e09b24ce3ee7f5eeffa |
|
MD5 | e6c8a594227a78579a71588dccf33497 |
|
BLAKE2b-256 | f7bf07f1448eeabddeaa97cf1ea30df3472d28dd88e6f61ae63817347cfb8a44 |