From d975648fc0d458a1e46f75fce7c60820d12428ea Mon Sep 17 00:00:00 2001
From: Radislav
Date: Thu, 24 Jul 2025 08:49:16 +0300
Subject: [PATCH] =?UTF-8?q?docs:=20=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?=
=?UTF-8?q?=D1=82=D1=8C=20=D1=81=D1=82=D0=B0=D0=BD=D0=B4=D0=B0=D1=80=D1=82?=
=?UTF-8?q?=D0=B8=D0=B7=D0=B8=D1=80=D0=BE=D0=B2=D0=B0=D0=BD=D0=BD=D1=8B?=
=?UTF-8?q?=D0=B5=20docstrings=20=D0=B4=D0=BB=D1=8F=20=D0=BE=D1=81=D0=BD?=
=?UTF-8?q?=D0=BE=D0=B2=D0=BD=D1=8B=D1=85=20=D0=BC=D0=BE=D0=B4=D1=83=D0=BB?=
=?UTF-8?q?=D0=B5=D0=B9?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Добавлены полные docstrings в основные модули проекта для улучшения документации кода.
---
alert_component.py | 98 ++
components/alert_component.py | 54 +-
components/base_component.py | 69 +-
components/card_component.py | 19 +-
components/confirm_component.py | 39 +-
components/json_container_component.py | 46 +-
components/modal_window_component.py | 60 +-
components/navbar_component.py | 50 +-
components/table_component.py | 57 +-
components/toolbar_component.py | 38 +-
data/constants.py | 16 +-
data/environment.py | 45 +-
data/roles_dict.py | 7 +-
docs/config/README_форматирование_кода.md | 25 -
docs/config/add_docstring.md | 14 +
elements/base_element.py | 36 +-
elements/button_element.py | 16 +-
elements/checkbox_element.py | 25 +-
elements/dropdown_list_element.py | 26 +-
elements/text_element.py | 16 +-
elements/text_input_element.py | 32 +-
elements/tooltip_button_element.py | 25 +-
fixtures/pages.py | 49 +-
locators/button_locators.py | 14 +
locators/confirm_locators.py | 17 +-
locators/event_panel_locators.py | 13 +-
locators/input_locators.py | 21 +-
locators/json_container_locators.py | 15 +-
locators/modal_window_locators.py | 25 +-
locators/navigation_panel_locators.py | 22 +-
locators/table_locators.py | 17 +-
locators/text_locators.py | 15 +-
locators/toolbar_locators.py | 23 +-
modal_windows/modal_add_user.py | 45 +-
modal_windows/modal_edit_user.py | 48 +-
pages/base_page.py | 72 +-
pages/license_tab.py | 58 +-
pages/login_page.py | 33 +-
pages/main_page.py | 34 +-
pages/service_status_tab.py | 42 +-
pages/session_tab.py | 51 +-
pages/users_tab.py | 121 +-
site/components/alert_component/index.html | 232 ++--
site/components/base_component/index.html | 326 +++--
site/components/card_component/index.html | 61 +-
site/components/confirm_component/index.html | 322 ++---
.../modal_window_component/index.html | 1197 +++--------------
site/components/navbar_component/index.html | 249 ++--
site/components/table_component/index.html | 506 ++++---
site/components/toolbar_component/index.html | 352 ++---
.../index.html | 78 +-
site/data/constants/index.html | 37 +-
site/data/environment/index.html | 349 ++---
site/data/roles_dict/index.html | 3 +
site/elements/base_element/index.html | 823 +++---------
site/elements/button_element/index.html | 41 +-
site/elements/checkbox_element/index.html | 123 +-
.../elements/dropdown_list_element/index.html | 107 +-
site/elements/text_element/index.html | 43 +-
site/elements/text_input_element/index.html | 161 ++-
.../tooltip_button_element/index.html | 85 +-
site/fixtures/pages/index.html | 279 ++--
site/locators/confirm_locators/index.html | 44 +-
site/locators/event_panel_locators/index.html | 36 +-
.../locators/modal_window_locators/index.html | 59 +-
.../navigation_panel_locators/index.html | 50 +-
site/locators/table_locators/index.html | 41 +-
site/locators/toolbar_locators/index.html | 46 +-
site/objects.inv | Bin 2569 -> 2581 bytes
site/pages/base_page/index.html | 810 +++--------
site/pages/login_page/index.html | 322 ++---
site/pages/main_page/index.html | 246 ++--
site/pages/service_status_tab/index.html | 344 +++--
site/pages/users_tab/index.html | 1168 +++++++++-------
site/search/search_index.json | 2 +-
site/sitemap.xml.gz | Bin 127 -> 127 bytes
.../components/test_json_container/index.html | 173 +--
.../test_navigation_panel/index.html | 147 +-
.../components/test_services_table/index.html | 248 ++--
.../test_user_modal_window/index.html | 975 ++++++--------
site/tests/e2e/test_license_tab/index.html | 901 ++++++-------
site/tests/e2e/test_login/index.html | 125 +-
.../e2e/test_service_status_tab/index.html | 235 ++--
site/tests/e2e/test_users_tab/index.html | 1076 ++++++---------
site/tools/fix_python_project/index.html | 228 ++--
site/tools/logger/index.html | 46 +-
tests/components/test_json_container.py | 25 +-
tests/components/test_navigation_panel.py | 25 +-
tests/components/test_services_table.py | 28 +-
tests/components/test_user_modal_window.py | 38 +-
tests/e2e/test_license_tab.py | 36 +-
tests/e2e/test_login.py | 29 +-
tests/e2e/test_service_status_tab.py | 46 +-
tests/e2e/test_sessions_tab.py | 29 +-
tests/e2e/test_users_tab.py | 78 +-
tools/fix_python_project.py | 66 +-
tools/logger.py | 22 +-
97 files changed, 6698 insertions(+), 7968 deletions(-)
create mode 100644 alert_component.py
delete mode 100644 docs/config/README_форматирование_кода.md
create mode 100644 docs/config/add_docstring.md
rename site/config/{README_форматирование_кода => add_docstring}/index.html (91%)
diff --git a/alert_component.py b/alert_component.py
new file mode 100644
index 0000000..3c4d876
--- /dev/null
+++ b/alert_component.py
@@ -0,0 +1,98 @@
+from elements.text_element import Text
+from playwright.sync_api import Page, expect
+from tools.logger import get_logger
+
+from components.base_component import BaseComponent
+
+logger = get_logger("ALERT")
+
+
+class AlertComponent(BaseComponent):
+ """Компонент для работы с alert-окнами.
+
+ Поддерживает различные типы alert-окон: error, success, info, warning.
+
+ Атрибуты:
+ page: экземпляр страницы Playwright
+ alert_type: тип alert-окна (error/success/info/warning)
+ text: текстовый элемент сообщения alert-окна
+ """
+
+ def __init__(self, page: Page, alert_type: str):
+ """Инициализация компонента alert-окна.
+
+ Args:
+ page: экземпляр страницы Playwright
+ alert_type: тип alert-окна (error/success/info/warning)
+
+ Raises:
+ ValueError: если передан неподдерживаемый тип alert-окна
+ """
+ super().__init__(page)
+
+ alert_types = ["error", "success", "info", "warning"]
+ if alert_type not in alert_types:
+ raise ValueError("Unsupported type of alert window")
+
+ self.alert_type = alert_type
+ self.text = Text(page,
+ f"//div[@class='v-alert {self.alert_type}']/div",
+ "Alert message")
+
+ # Действия:
+ def get_text(self) -> str:
+ """Получение текста сообщения из alert-окна.
+
+ Returns:
+ str: текст сообщения alert-окна
+ """
+ return self.text.get_text(0)
+
+ # Проверки:
+ def check_presence(self, text: str)-> None:
+ """Проверка наличия alert-окна с заданным текстом.
+
+ Args:
+ text: текст для проверки (если пустая строка - проверяется только наличие окна)
+
+ Raises:
+ AssertionError: если alert-окно не найдено
+ """
+ msg = f"No {self.alert_type} alert window on page"
+ if text == "":
+ expect(self.page.get_by_role("alert")).to_be_visible(), msg
+ else:
+ expect(
+ self.page.get_by_role("alert").filter(
+ has_text=text)).to_be_visible(), msg
+
+ def check_absence(self, text: str, timeout: int = 30000):
+ """Проверка отсутствия alert-окна с заданным текстом.
+
+ Args:
+ text: текст для проверки
+ timeout: время ожидания исчезновения (в миллисекундах)
+
+ Raises:
+ AssertionError: если alert-окно не исчезает в течение заданного времени
+ """
+ seconds = int(timeout / 1000)
+ msg = f"Alert {
+ self.alert_type} window should disappear after {seconds} seconds"
+ expect(
+ self.page.get_by_role("alert").filter(
+ has_text=text)).to_be_hidden(
+ timeout=timeout), msg
+
+ def check_text(self, alert_text: str):
+ """Проверка точного соответствия текста в alert-окне.
+
+ Args:
+ alert_text: ожидаемый текст сообщения
+
+ Raises:
+ AssertionError: если текст не соответствует ожидаемому
+ """
+ self.text.check_have_text(
+ alert_text, f"Unexpected message in alert {
+ self.alert_type} window")
diff --git a/components/alert_component.py b/components/alert_component.py
index eb6b332..6b782cb 100644
--- a/components/alert_component.py
+++ b/components/alert_component.py
@@ -1,3 +1,9 @@
+"""Модуль для работы с компонентом alert-окна в Playwright.
+
+Содержит класс AlertComponent для взаимодействия с различными типами
+alert-окон (error, success, info, warning) и проверки их состояния.
+"""
+
from playwright.sync_api import Page, expect
from tools.logger import get_logger
from elements.text_element import Text
@@ -7,25 +13,21 @@ logger = get_logger("ALERT")
class AlertComponent(BaseComponent):
- """Компонент для работы с alert-окнами.
+ """Компонент для работы с alert-окнами Playwright.
- Поддерживает различные типы alert-окон: error, success, info, warning.
-
- Атрибуты:
- page: экземпляр страницы Playwright
- alert_type: тип alert-окна (error/success/info/warning)
- text: текстовый элемент сообщения alert-окна
+ Поддерживает типы: error, success, info, warning.
+ Позволяет проверять наличие, отсутствие и текст сообщений.
"""
def __init__(self, page: Page, alert_type: str):
- """Инициализация компонента alert-окна.
+ """Инициализирует компонент alert-окна.
Args:
- page: экземпляр страницы Playwright
- alert_type: тип alert-окна (error/success/info/warning)
+ page: Экземпляр страницы Playwright.
+ alert_type: Тип alert-окна (error/success/info/warning).
Raises:
- ValueError: если передан неподдерживаемый тип alert-окна
+ ValueError: Если передан неподдерживаемый тип alert-окна.
"""
super().__init__(page)
@@ -37,25 +39,24 @@ class AlertComponent(BaseComponent):
self.alert_type = alert_type
self.text = Text(page, f"//div[@class='v-alert {self.alert_type}']/div", "Alert message")
- # Действия:
def get_text(self) -> str:
- """Получение текста сообщения из alert-окна.
+ """Возвращает текст сообщения из alert-окна.
Returns:
- str: текст сообщения alert-окна
+ str: Текст сообщения.
"""
return self.text.get_text(0)
- # Проверки:
def check_alert_presence(self, text: str):
- """Проверка наличия alert-окна с заданным текстом.
+ """Проверяет наличие alert-окна с заданным текстом.
Args:
- text: текст для проверки (если пустая строка - проверяется только наличие окна)
+ text: Текст для проверки. Если пустая строка - проверяет только
+ наличие окна.
Raises:
- AssertionError: если alert-окно не найдено
+ AssertionError: Если alert-окно не найдено.
"""
msg = f"No {self.alert_type} alert window on page"
@@ -65,28 +66,29 @@ class AlertComponent(BaseComponent):
expect(self.page.get_by_role("alert").filter(has_text=text)).to_be_visible(), msg
def check_alert_absence(self, text: str, timeout: int = 30000):
- """Проверка отсутствия alert-окна с заданным текстом.
+ """Проверяет отсутствие alert-окна с заданным текстом.
Args:
- text: текст для проверки
- timeout: время ожидания исчезновения (в миллисекундах)
+ text: Текст для проверки.
+ timeout: Время ожидания исчезновения (мс).
Raises:
- AssertionError: если alert-окно не исчезает в течение заданного времени
+ AssertionError: Если окно не исчезает в течение заданного времени.
"""
+
seconds = int(timeout/1000)
msg = f"Alert {self.alert_type} window should disappear after {seconds} seconds"
expect(self.page.get_by_role("alert").filter(has_text=text)).to_be_hidden(timeout=timeout), msg
def check_text(self, alert_text: str):
- """Проверка точного соответствия текста в alert-окне.
+ """Проверяет точное соответствие текста в alert-окне.
Args:
- alert_text: ожидаемый текст сообщения
+ alert_text: Ожидаемый текст сообщения.
Raises:
- AssertionError: если текст не соответствует ожидаемому
+ AssertionError: Если текст не соответствует ожидаемому.
"""
self.text.check_have_text(alert_text,
- f"Unexpected message in alert {self.alert_type} window")
+ f"Unexpected message in alert {self.alert_type} window")
diff --git a/components/base_component.py b/components/base_component.py
index bbe395e..98e11bf 100644
--- a/components/base_component.py
+++ b/components/base_component.py
@@ -1,3 +1,8 @@
+"""Базовый модуль для работы с компонентами страницы.
+
+Содержит базовый класс для взаимодействия с элементами страницы через Playwright.
+"""
+
from playwright.sync_api import Page, Locator, expect
from tools.logger import get_logger
@@ -11,17 +16,15 @@ class BaseComponent:
- получение локаторов
- проверка видимости элементов
- работа с прокруткой
-
- Атрибуты:
- page: экземпляр страницы Playwright
"""
def __init__(self, page: Page):
"""Инициализация базового компонента.
Args:
- page: экземпляр страницы Playwright
+ page: экземпляр страницы Playwright.
"""
+
self.page = page
# Действия:
@@ -29,14 +32,15 @@ class BaseComponent:
"""Получение объекта Locator из строки или существующего Locator.
Args:
- locator: строка с CSS/XPath селектором или объект Locator
+ locator: строка с CSS/XPath селектором или объект Locator.
Returns:
- Locator: объект для работы с элементом
+ Locator: объект для работы с элементом.
Raises:
- TypeError: если передан некорректный тип локатора
+ TypeError: если передан некорректный тип локатора.
"""
+
if isinstance(locator, Locator):
return locator
elif isinstance(locator, str):
@@ -55,53 +59,57 @@ class BaseComponent:
# return elements
# Проверки:
- def check_presence(self, locator, msg):
+ def check_presence(self, locator: str | Locator, msg: str) -> None:
"""Проверка видимости элемента на странице.
Args:
- locator: локатор элемента (строка или объект Locator)
- msg: сообщение об ошибке при неудачной проверке
+ locator: локатор элемента (строка или объект Locator).
+ msg: сообщение об ошибке при неудачной проверке.
Raises:
- AssertionError: если элемент не виден на странице
+ AssertionError: если элемент не виден на странице.
"""
+
loc = self.get_locator(locator)
expect(loc).to_be_visible(visible=True, timeout=12000), msg
- def is_scrollable_vertically(self, locator) -> bool:
+ def is_scrollable_vertically(self, locator: str | Locator) -> bool:
"""Проверка возможности вертикальной прокрутки элемента.
Args:
- locator: локатор элемента
+ locator: локатор элемента.
Returns:
- bool: True если элемент можно прокрутить вертикально
+ bool: True если элемент можно прокрутить вертикально.
"""
+
loc = self.get_locator(locator)
return loc.evaluate("el => el.scrollHeight > el.clientHeight")
- def is_scrollable_horizontally(self, locator) -> bool:
+ def is_scrollable_horizontally(self, locator: str | Locator) -> bool:
"""Проверка возможности горизонтальной прокрутки элемента.
Args:
- locator: локатор элемента
+ locator: локатор элемента.
Returns:
- bool: True если элемент можно прокрутить горизонтально
+ bool: True если элемент можно прокрутить горизонтально.
"""
+
loc = self.get_locator(locator)
return loc.evaluate("el => el.scrollWidth > el.clientWidth")
# Методы прокрутки:
- def scroll_up(self, locator):
+ def scroll_up(self, locator: str | Locator) -> None:
"""Прокрутка элемента вверх.
Args:
- locator: локатор элемента
+ locator: локатор элемента.
Raises:
- AssertionError: если прокрутка не выполнена до конца
+ AssertionError: если прокрутка не выполнена до конца.
"""
+
loc = self.get_locator(locator)
loc.evaluate("el => el.scrollTo(0, 0)")
loc.wait_for(timeout=2000)
@@ -110,15 +118,16 @@ class BaseComponent:
scroll_position = loc.evaluate("el => el.scrollTop")
assert scroll_position == 0, "Invalid postion after scroll up"
- def scroll_down(self, locator):
+ def scroll_down(self, locator: str | Locator) -> None:
"""Прокрутка элемента вниз.
Args:
- locator: локатор элемента
+ locator: локатор элемента.
Raises:
- AssertionError: если прокрутка не выполнена до конца
+ AssertionError: если прокрутка не выполнена до конца.
"""
+
loc = self.get_locator(locator)
loc.evaluate("el => el.scrollTo(0, el.scrollHeight)")
loc.wait_for(timeout=2000)
@@ -127,15 +136,16 @@ class BaseComponent:
scroll_position = loc.evaluate("el => el.scrollTop")
assert scroll_position > 0, "Invalid postion after scroll down"
- def scroll_left(self, locator):
+ def scroll_left(self, locator: str | Locator) -> None:
"""Прокрутка элемента влево.
Args:
- locator: локатор элемента
+ locator: локатор элемента.
Raises:
- AssertionError: если прокрутка не выполнена до конца
+ AssertionError: если прокрутка не выполнена до конца.
"""
+
loc = self.get_locator(locator)
width = loc.evaluate("el => el.scrollWidth")
@@ -148,15 +158,16 @@ class BaseComponent:
scroll_position = loc.evaluate("el => el.scrollLeft")
assert scroll_position == 0, "Invalid postion after scroll left"
- def scroll_right(self, locator):
+ def scroll_right(self, locator: str | Locator) -> None:
"""Прокрутка элемента вправо.
Args:
- locator: локатор элемента
+ locator: локатор элемента.
Raises:
- AssertionError: если прокрутка не выполнена до конца
+ AssertionError: если прокрутка не выполнена до конца.
"""
+
loc = self.get_locator(locator)
width = loc.evaluate("el => el.scrollWidth")
diff --git a/components/card_component.py b/components/card_component.py
index 68721a2..07b03df 100644
--- a/components/card_component.py
+++ b/components/card_component.py
@@ -1,3 +1,8 @@
+"""Модуль компонента карточки пользователя.
+
+Содержит класс для работы с карточкой пользователя через Playwright.
+"""
+
from playwright.sync_api import Page
from tools.logger import get_logger
from elements.button_element import Button
@@ -9,19 +14,16 @@ logger = get_logger("USER_CARD")
class CardComponent(BaseComponent):
"""Компонент карточки пользователя.
- Предоставляет методы для взаимодействия с элементами карточки пользователя.
-
- Атрибуты:
- page: экземпляр страницы Playwright
- logout_button: кнопка выхода из системы
+ Предоставляет методы для взаимодействия с элементами карточки.
"""
def __init__(self, page: Page):
- """Инициализация компонента карточки пользователя.
+ """Инициализирует компонент карточки пользователя.
Args:
- page: экземпляр страницы Playwright
+ page: Экземпляр страницы Playwright.
"""
+
super().__init__(page)
self.logout_button = Button(
@@ -32,10 +34,11 @@ class CardComponent(BaseComponent):
# Действия:
def click_logout_button(self):
- """Нажатие кнопки выхода из системы.
+ """Нажимает кнопку выхода из системы.
Выполняет клик по кнопке 'Выйти' в карточке пользователя.
"""
+
self.logout_button.click()
# Проверки:
diff --git a/components/confirm_component.py b/components/confirm_component.py
index c9e54d1..78bf60f 100644
--- a/components/confirm_component.py
+++ b/components/confirm_component.py
@@ -1,3 +1,9 @@
+"""Модуль компонента окна подтверждения действий.
+
+Содержит класс ConfirmComponent для взаимодействия с окном подтверждения,
+включая кнопки подтверждения, отмены и закрытия, а также проверки текста.
+"""
+
from playwright.sync_api import Page
from tools.logger import get_logger
from locators.confirm_locators import ConfirmLocators
@@ -12,6 +18,14 @@ class ConfirmComponent(BaseComponent):
"""Компонент окна подтверждения действий."""
def __init__(self, page: Page, cancel_button_text: str, allow_button_text: str):
+ """Инициализация компонента.
+
+ Args:
+ page: Экземпляр страницы Playwright.
+ cancel_button_text: Текст кнопки отмены.
+ allow_button_text: Текст кнопки подтверждения.
+ """
+
super().__init__(page)
self.title = Text(page, ConfirmLocators.TITLE, "confirm title")
@@ -31,22 +45,37 @@ class ConfirmComponent(BaseComponent):
# Действия:
def click_allow_button(self) -> None:
- """Нажатие кнопки подтверждения действия."""
+ """Нажимает кнопку подтверждения действия."""
+
self.allow_button.click()
def click_cancel_button(self) -> None:
- """Нажатие кнопки отмены действия."""
+ """Нажимает кнопку отмены действия."""
+
self.cancel_button.click()
def click_close_button(self) -> None:
- """Нажатие кнопки закрытия окна подтверждения."""
+ """Нажимает кнопку закрытия окна подтверждения."""
+
self.close_button.click()
# Проверки:
def check_title(self, title: str, msg: str) -> None:
- """Проверка текста заголовка окна подтверждения."""
+ """Проверяет текст заголовка окна подтверждения.
+
+ Args:
+ title: Ожидаемый текст заголовка.
+ msg: Сообщение при ошибке.
+ """
+
self.title.check_have_text(title, msg)
def check_text(self, text: str, msg: str) -> None:
- """Проверка текста сообщения в окне подтверждения."""
+ """Проверяет текст сообщения в окне подтверждения.
+
+ Args:
+ text: Ожидаемый текст сообщения.
+ msg: Сообщение при ошибке.
+ """
+
self.text.check_have_text(text, msg)
diff --git a/components/json_container_component.py b/components/json_container_component.py
index 335c04b..d593952 100644
--- a/components/json_container_component.py
+++ b/components/json_container_component.py
@@ -1,3 +1,9 @@
+"""Модуль для работы с JSON-контейнерами на веб-страницах.
+
+Содержит компонент для чтения и проверки JSON-данных в контейнерах.
+Использует playwright для взаимодействия с элементами страницы.
+"""
+
import json
import jsondiff
from playwright.sync_api import Page
@@ -10,43 +16,46 @@ logger = get_logger("JSON_CONTAINER")
class JsonContainerComponent(BaseComponent):
"""Компонент для работы с JSON-данными на странице.
- Предоставляет методы для чтения и проверки JSON-данных,
- отображаемых в специальных контейнерах на странице.
- Атрибуты:
- page: экземпляр страницы Playwright
+
+
+ Предоставляет методы чтения и проверки JSON-данных в контейнерах.
+
"""
def __init__(self, page: Page):
- """Инициализация JSON-контейнера.
+ """Инициализирует JSON-контейнер.
Args:
- page: экземпляр страницы Playwright
+ page: Экземпляр страницы Playwright.
"""
+
super().__init__(page)
# Действия:
def read_data(self, locator):
- """Чтение и форматирование JSON-данных из указанного локатора.
+ """Читает и форматирует JSON-данные из указанного локатора.
Args:
- locator: локатор элемента, содержащего JSON-данные
+ locator: Локатор элемента с JSON-данными.
Returns:
- dict: распарсенный JSON-объект
+ dict: Распарсенный JSON-объект.
Raises:
- json.JSONDecodeError: если данные не могут быть преобразованы в JSON
+ json.JSONDecodeError: Если данные не могут быть преобразованы в JSON.
"""
+
def format_json_string(json_string):
- """Вспомогательная функция для форматирования строки JSON.
+ """Форматирует строку JSON для корректного парсинга.
Args:
- json_string: сырая строка с JSON-данными
+ json_string: Сырая строка с JSON-данными.
Returns:
- str: отформатированная строка JSON
+ str: Отформатированная строка JSON.
"""
+
substrings = json_string.splitlines()
formatted_string_list = []
last_substring = substrings.pop()
@@ -85,15 +94,16 @@ class JsonContainerComponent(BaseComponent):
# Проверки:
def check_json_equals(self, actual, expected, msg):
- """Сравнение JSON-объектов на идентичность.
+ """Сравнивает JSON-объекты на идентичность.
Args:
- actual: фактический JSON-объект
- expected: ожидаемый JSON-объект
- msg: сообщение об ошибке
+ actual: Фактический JSON-объект.
+ expected: Ожидаемый JSON-объект.
+ msg: Сообщение об ошибке.
Raises:
- AssertionError: если объекты не идентичны
+ AssertionError: Если объекты не идентичны.
"""
+
diff = jsondiff.diff(expected, actual, syntax='symmetric')
assert len(diff) == 0, f"{msg}. DIFF is {diff}"
diff --git a/components/modal_window_component.py b/components/modal_window_component.py
index c35c56b..f78fff1 100644
--- a/components/modal_window_component.py
+++ b/components/modal_window_component.py
@@ -1,3 +1,6 @@
+"""Модуль компонента модального окна. Содержит класс для работы с модальными окнами,
+их элементами и проверками."""
+
from playwright.sync_api import Page
from tools.logger import get_logger
from locators.modal_window_locators import ModalWindowLocators
@@ -9,7 +12,8 @@ logger = get_logger("MODAL_WINDOW")
class ModalWindowComponent(BaseComponent):
- """Компонент модального окна."""
+ """Компонент модального окна. Предоставляет методы для взаимодействия с окном,
+ его содержимым и проверок."""
def __init__(self, page: Page):
super().__init__(page)
@@ -19,83 +23,101 @@ class ModalWindowComponent(BaseComponent):
# Действия:
def add_content_item(self, name: str, item: object) -> None:
- """Добавление элемента содержимого в окно."""
+ """Добавляет элемент содержимого в окно по заданному имени."""
+
self.content_items[name] = item
def get_content_item(self, name: str) -> object | None:
- """Получение элемента содержимого по имени."""
+ """Возвращает элемент содержимого по имени или None, если не найден."""
+
return self.content_items.get(name)
def add_toolbar_title(self, title: str) -> None:
- """Добавление заголовка в панель инструментов."""
+ """Добавляет заголовок в панель инструментов модального окна."""
+
self.toolbar.add_title(title)
def add_toolbar_button(self, locator: str, name: str) -> None:
- """Добавление кнопки в панель инструментов."""
+ """Добавляет кнопку в панель инструментов модального окна."""
+
self.toolbar.add_button(locator, name)
def add_button(self, locator: str, name: str) -> None:
- """Добавление кнопки в окно."""
+ """Добавляет кнопку в модальное окно."""
+
self.buttons.append(Button(self.page, locator, name))
def get_button_by_name(self, name: str) -> Button | None:
- """Поиск кнопки по имени."""
+ """Ищет и возвращает кнопку по имени или None, если не найдена."""
+
for button in self.buttons:
if button.name == name:
return button
return None
def click_button(self, name: str) -> None:
- """Нажатие кнопки по имени."""
+ """Кликает по кнопке с заданным именем. Вызывает ошибку, если не найдена."""
+
button = self.get_button_by_name(name)
if button is None:
assert False, f"Button with name '{name}' not found"
button.click()
def click_toolbar_close_button(self) -> None:
- """Нажатие кнопки закрытия в панели инструментов."""
+ """Кликает по кнопке закрытия в панели инструментов."""
+
self.toolbar.click_button("close")
def scroll_window_down(self) -> None:
- """Прокрутка содержимого окна вниз."""
+ """Прокручивает содержимое окна вниз."""
+
self.scroll_down(ModalWindowLocators.MODAL_WINDOW)
def scroll_window_up(self) -> None:
- """Прокрутка содержимого окна вверх."""
+ """Прокручивает содержимое окна вверх."""
+
self.scroll_up(ModalWindowLocators.MODAL_WINDOW)
def scroll_window_left(self) -> None:
- """Прокрутка содержимого окна влево."""
+ """Прокручивает содержимое окна влево."""
+
self.scroll_left(ModalWindowLocators.MODAL_WINDOW)
def scroll_window_right(self) -> None:
- """Прокрутка содержимого окна вправо."""
+ """Прокручивает содержимое окна вправо."""
+
self.scroll_right(ModalWindowLocators.MODAL_WINDOW)
# Проверки:
def check_window_vertical_scrolling(self) -> bool:
- """Проверка возможности вертикальной прокрутки."""
+ """Проверяет возможность вертикальной прокрутки окна."""
+
return self.is_scrollable_vertically(ModalWindowLocators.MODAL_WINDOW)
def check_window_horizontal_scrolling(self) -> bool:
- """Проверка возможности горизонтальной прокрутки."""
+ """Проверяет возможность горизонтальной прокрутки окна."""
+
return self.is_scrollable_horizontally(ModalWindowLocators.MODAL_WINDOW)
def check_by_window_title(self) -> None:
- """Проверка наличия окна по заголовку."""
+ """Проверяет наличие окна по заголовку."""
+
self.toolbar.check_toolbar_presence(f"Modal window with '{self.toolbar.title}' is missing")
def check_button_presence(self, name: str) -> None:
- """Проверка наличия кнопки по имени."""
+ """Проверяет наличие кнопки по имени. Вызывает ошибку, если не найдена."""
+
button = self.get_button_by_name(name)
if button is None:
assert False, f"Button with name '{name}' not found"
button.check_presence(f"Button with name '{name}' is missing")
def check_toolbar_button_presence(self, name: str) -> None:
- """Проверка наличия кнопки в панели инструментов."""
+ """Проверяет наличие кнопки в панели инструментов."""
+
self.toolbar.check_button_presence(name)
def check_toolbar_button_tooltip(self, name: str, tooltip: str) -> None:
- """Проверка подсказки кнопки в панели инструментов."""
+ """Проверяет подсказку у кнопки в панели инструментов."""
+
self.toolbar.check_button_tooltip(name, tooltip)
diff --git a/components/navbar_component.py b/components/navbar_component.py
index 6d9721a..4c2d99b 100644
--- a/components/navbar_component.py
+++ b/components/navbar_component.py
@@ -1,3 +1,5 @@
+"""Модуль компонента панели навигации. Содержит класс для работы с элементами навигации."""
+
from playwright.sync_api import Page, Locator
from tools.logger import get_logger
from locators.navigation_panel_locators import NavigationPanelLocators
@@ -7,24 +9,54 @@ logger = get_logger("NAVIGATION_PANEL")
class NavigationPanelComponent(BaseComponent):
- """Компонент панели навигации."""
+ """Компонент панели навигации. Предоставляет методы для взаимодействия с ней."""
def __init__(self, page: Page):
+ """Инициализирует компонент панели навигации.
+
+ Args:
+ page: Экземпляр страницы Playwright.
+ """
+
super().__init__(page)
# Действия:
def get_item_names(self, locator: str | Locator) -> list[str]:
- """Получает тексты всех элементов по указанному локатору."""
+ """Возвращает тексты всех элементов по указанному локатору.
+
+ Args:
+ locator: Локатор элементов или строка с CSS/XPath.
+
+ Returns:
+ Список текстов элементов.
+ """
+
loc = self.get_locator(locator)
return loc.all_inner_texts()
def click_item(self, locator: str | Locator, item_name: str) -> None:
- """Кликает по элементу с указанным текстом."""
+ """Кликает по элементу с указанным текстом.
+
+ Args:
+ locator: Локатор элемента или строка с CSS/XPath.
+ item_name: Текст элемента для клика.
+ """
+
loc = self.get_locator(locator)
loc.get_by_text(item_name).click()
def click_sub_item(self, locator: str | Locator, sublevel_number: int, item_name: str) -> None:
- """Кликает по вложенному элементу с указанным текстом."""
+ """Кликает по вложенному элементу с указанным текстом.
+
+ Args:
+ locator: Локатор родительского элемента.
+ sublevel_number: Уровень вложенности (1 или 2).
+ item_name: Текст элемента для клика.
+
+ Raises:
+ ValueError: Если уровень вложенности не 1 или 2.
+ """
+
root_locator = self.get_locator(NavigationPanelLocators.NODE_ROOT)
children_locator = self.get_locator(NavigationPanelLocators.NODE_CHILDREN)
@@ -39,7 +71,15 @@ class NavigationPanelComponent(BaseComponent):
# Проверки:
def check_item_visibility(self, locator: str | Locator, item_name: str) -> None:
- """Проверяет видимость элемента с указанным текстом."""
+ """Проверяет видимость элемента с указанным текстом.
+
+ Args:
+ locator: Локатор элемента или строка с CSS/XPath.
+ item_name: Текст элемента для проверки.
+
+ Note:
+ Временная обработка для элементов с текстом 'Шаблоны'.
+ """
msg = f"Navigation panel item '{item_name}' is not visible"
diff --git a/components/table_component.py b/components/table_component.py
index d6b8d83..74f8807 100644
--- a/components/table_component.py
+++ b/components/table_component.py
@@ -1,19 +1,37 @@
+"""Модуль компонента таблицы. Содержит класс для работы с табличными данными."""
+
from playwright.sync_api import Page, expect, Locator
from tools.logger import get_logger
from components.base_component import BaseComponent
+
logger = get_logger("TABLE")
class TableComponent(BaseComponent):
- """Компонент таблицы."""
+ """Компонент таблицы. Предоставляет методы для работы с табличными данными."""
def __init__(self, page: Page):
+ """Инициализирует компонент таблицы.
+
+ Args:
+ page: Экземпляр страницы Playwright.
+ """
+
super().__init__(page)
# Действия:
- def get_row_locator(self, table_locator, row_index) -> Locator | None:
- """Конструирует локатор для строки с заданным индексом."""
+ def get_row_locator(self, table_locator: str | Locator, row_index: int) -> Locator | None:
+ """Возвращает локатор строки по индексу.
+
+ Args:
+ table_locator: Локатор таблицы.
+ row_index: Индекс строки.
+
+ Returns:
+ Локатор строки или None, если индекс вне диапазона.
+ """
+
table = self.get_locator(table_locator)
rows = table.locator("//tbody/tr")
@@ -24,9 +42,16 @@ class TableComponent(BaseComponent):
return None
def read(self, locator: str | Locator) -> list[list[str]]:
- """Читает данные из таблицы."""
- table_data = []
+ """Читает данные таблицы, включая заголовки.
+ Args:
+ locator: Локатор таблицы.
+
+ Returns:
+ Двумерный список с данными таблицы.
+ """
+
+ table_data = []
table = self.get_locator(locator)
# Чтение заголовка таблицы
@@ -50,19 +75,35 @@ class TableComponent(BaseComponent):
# Проверки:
def check_first_row_visibility(self, locator: str | Locator) -> None:
- """Проверяет видимость первой строки таблицы."""
+ """Проверяет видимость первой строки таблицы.
+
+ Args:
+ locator: Локатор таблицы.
+ """
+
table = self.get_locator(locator)
first_row = table.locator("//tbody/tr").first
expect(first_row).to_be_visible(), "The first table row is not visible"
def check_last_row_visibility(self, locator: str | Locator) -> None:
- """Проверяет видимость последней строки таблицы."""
+ """Проверяет видимость последней строки таблицы.
+
+ Args:
+ locator: Локатор таблицы.
+ """
+
table = self.get_locator(locator)
last_row = table.locator("//tbody/tr").last
expect(last_row).to_be_visible(), "The last table row is not visible"
def check_row_highlighting(self, locator: str | Locator, row_index: int) -> None:
- """Проверяет подсветку строки при наведении."""
+ """Проверяет изменение цвета строки при наведении.
+
+ Args:
+ locator: Локатор таблицы.
+ row_index: Индекс проверяемой строки.
+ """
+
table = self.get_locator(locator)
row = table.locator("//tbody/tr").nth(row_index)
diff --git a/components/toolbar_component.py b/components/toolbar_component.py
index a056aaa..06d146d 100644
--- a/components/toolbar_component.py
+++ b/components/toolbar_component.py
@@ -1,3 +1,11 @@
+"""Модуль компонента тулбара (панели инструментов).
+
+Содержит класс ToolbarComponent для работы с элементами тулбара:
+- Управление кнопками и их подсказками
+- Проверка видимости элементов
+- Взаимодействие с панелью инструментов
+"""
+
from playwright.sync_api import Page, expect, Locator
from tools.logger import get_logger
from locators.toolbar_locators import ToolbarLocators
@@ -8,12 +16,12 @@ logger = get_logger("TOOLBAR")
class ToolbarComponent(BaseComponent):
- """Компонент тулбара (панели инструментов).
- Предоставляет методы для работы с панелью инструментов:
- - Добавление/управление кнопками
- - Проверка видимости элементов
- - Взаимодействие с элементами тулбара
+
+ """Компонент тулбара. Предоставляет методы для работы с панелью инструментов.
+
+
+
Args:
page (Page): Экземпляр страницы Playwright
@@ -21,17 +29,19 @@ class ToolbarComponent(BaseComponent):
"""
def __init__(self, page: Page, title: str):
- """Инициализация компонента тулбара."""
+ """Инициализирует компонент тулбара с указанным заголовком."""
+
super().__init__(page)
self.title = title
self.buttons = []
def add_title(self, title: str) -> None:
- """Устанавливает заголовок тулбара.
+ """Устанавливает новый заголовок тулбара.
Args:
- title (str): Новый заголовок тулбара
+ title (str): Новый заголовок
"""
+
self.title = title
def add_button(self, locator: Locator, name: str) -> None:
@@ -41,6 +51,7 @@ class ToolbarComponent(BaseComponent):
locator (Locator): Локатор кнопки
name (str): Уникальное имя кнопки
"""
+
self.buttons.append(TooltipButton(self.page, locator, name))
def get_button_by_name(self, name: str) -> TooltipButton | None:
@@ -50,8 +61,9 @@ class ToolbarComponent(BaseComponent):
name (str): Имя кнопки
Returns:
- TooltipButton | None: Экземпляр кнопки или None если не найдена
+ TooltipButton | None: Найденная кнопка или None
"""
+
for button in self.buttons:
if button.name == name:
return button
@@ -66,6 +78,7 @@ class ToolbarComponent(BaseComponent):
Raises:
AssertionError: Если кнопка не найдена
"""
+
button = self.get_button_by_name(name)
if button is None:
raise AssertionError(f"Unsupported button name {name}")
@@ -83,6 +96,7 @@ class ToolbarComponent(BaseComponent):
Raises:
AssertionError: Если имя кнопки не поддерживается
"""
+
button = self.get_button_by_name(name)
if button is None:
raise AssertionError(f"Unsupported button name {name}")
@@ -100,6 +114,7 @@ class ToolbarComponent(BaseComponent):
Raises:
AssertionError: Если имя кнопки не поддерживается
"""
+
button = self.get_button_by_name(name)
if button is None:
raise AssertionError(f"Unsupported button name {name}")
@@ -111,6 +126,7 @@ class ToolbarComponent(BaseComponent):
Args:
message (str): Сообщение об ошибке если тулбар не виден
"""
+
locator = self.get_locator(ToolbarLocators.TITLE).filter(has_text=self.title)
expect(locator).to_be_visible(), message
@@ -123,6 +139,7 @@ class ToolbarComponent(BaseComponent):
Raises:
AssertionError: Если кнопка не найдена или не видна
"""
+
button = self.get_button_by_name(name)
if button is None:
raise AssertionError(f"Unsupported button name {name}")
@@ -136,8 +153,9 @@ class ToolbarComponent(BaseComponent):
tooltip (str): Ожидаемый текст подсказки
Raises:
- AssertionError: Если кнопка не найдена или текст подсказки не совпадает
+ AssertionError: Если текст подсказки не совпадает
"""
+
button = self.get_button_by_name(name)
if button is None:
raise AssertionError(f"Unsupported button name {name}")
diff --git a/data/constants.py b/data/constants.py
index bd81b39..1b1d24e 100644
--- a/data/constants.py
+++ b/data/constants.py
@@ -1,14 +1,20 @@
+"""Модуль constants содержит настройки и константы приложения.
+
+Основной класс Constants предоставляет доступ к переменным окружения,
+используемым для аутентификации и других настроек.
+"""
+
import os
class Constants:
- """Класс для хранения констант и переменных окружения.
+ """Хранит константы и переменные окружения.
- Содержит переменные, используемые для аутентификации и других настроек.
- Получает значения из переменных окружения.
+
+ Получает значения из переменных окружения. Используется для аутентификации.
Атрибуты:
- login (str): Логин для аутентификации
- password (str): Пароль для аутентификации
+ login (str): Логин для аутентификации.
+ password (str): Пароль для аутентификации.
"""
try:
diff --git a/data/environment.py b/data/environment.py
index 7a735a7..348a3fd 100644
--- a/data/environment.py
+++ b/data/environment.py
@@ -1,8 +1,20 @@
+"""Модуль environment содержит настройки окружения и URL-адресов.
+
+Класс Environment предоставляет методы для работы с окружением,
+токенами и URL-адресами API.
+"""
+
import os
from typing import Dict
class Environment:
- """Класс для работы с окружением и URL-адресами."""
+ """Управление окружением, URL-адресами и токенами.
+
+ Атрибуты класса:
+ TEST (str): Константа для тестового окружения.
+ DEVELOP (str): Константа для dev-окружения.
+ URLS (Dict[str, str]): Словарь URL для разных окружений.
+ """
TEST: str = 'test'
DEVELOP: str = 'develop'
@@ -13,7 +25,8 @@ class Environment:
}
def __init__(self) -> None:
- """Инициализация объекта окружения."""
+ """Инициализирует объект окружения и токены."""
+
try:
self.env: str = os.getenv('ENV', self.TEST)
self.access_token: str = ""
@@ -22,7 +35,12 @@ class Environment:
self.env: str = self.TEST
def get_base_url(self) -> str:
- """Возвращает базовый URL для текущего окружения."""
+ """Возвращает базовый URL для текущего окружения.
+
+ Возвращает:
+ str: Базовый URL с путем для теста или без него.
+ """
+
if self.env in self.URLS:
if self.env == self.TEST:
return self.URLS[self.env] + "e-nms-ui/"
@@ -30,17 +48,32 @@ class Environment:
raise Exception(f"Unknown value of ENV variable {self.env}")
def get_request_url(self) -> str:
- """Возвращает URL для API-запросов."""
+ """Возвращает URL для API-запросов.
+
+ Возвращает:
+ str: URL для API-запросов.
+ """
+
if self.env in self.URLS:
return self.URLS[self.env]
raise Exception(f"Unknown value of ENV variable {self.env}")
def set_access_token(self, token: str) -> None:
- """Устанавливает токен доступа."""
+ """Устанавливает токен доступа.
+
+ Аргументы:
+ token (str): Токен для установки.
+ """
+
self.token = token
def get_access_token(self) -> str:
- """Возвращает текущий токен доступа."""
+ """Возвращает текущий токен доступа.
+
+ Возвращает:
+ str: Текущий токен доступа.
+ """
+
return self.token
diff --git a/data/roles_dict.py b/data/roles_dict.py
index 832bf3e..0511763 100644
--- a/data/roles_dict.py
+++ b/data/roles_dict.py
@@ -1,7 +1,12 @@
+"""Модуль roles_dict содержит словарь соответствия ролей.
+
+Содержит сопоставление системных названий ролей с их отображаемыми названиями.
+"""
+
# Словарь соответствия системных названий ролей их отображаемым названиям
roles_dict = {
"administrator": "Администратор",
- "manager": "Контактное лицо",
+ "manager": "Контактное лицо",
"operator": "Оператор",
"inform_secur_user": "Специалист информационной безопасности",
"user": "Пользователь"
diff --git a/docs/config/README_форматирование_кода.md b/docs/config/README_форматирование_кода.md
deleted file mode 100644
index 7fc008e..0000000
--- a/docs/config/README_форматирование_кода.md
+++ /dev/null
@@ -1,25 +0,0 @@
-# Форматирование кода в соответствии с PEP 8 и Google Python Style Guide
-
-## Требования к форматированию
-
-1. **Добавление Docstring**:
- - Для класса: описание назначения и атрибутов в Google-формате на русском языке
- - Для методов: описание аргументов, возвращаемых значений и возможных исключений
-
-2. **Сохранение комментариев**:
- - Разделительные комментарии (например, `#actions:`, `# assertions:`) остаются без изменений
- - Закомментированный код сохраняется в оригинальном виде
- - Технические комментарии в методах не изменяются
-
-3. **Перевод комментариев**:
- - Разделительные комментарии переводятся (например, `# Действия:`, `# Проверки:`)
- - Пояснительные комментарии к логике кода переводятся
- - Не переводятся:
- - Технические сообщения в `assert`, `raise` и других системных конструкциях
- - Закомментированный код
- - Сообщения в логах и ошибках
-
-4. **Форматирование кода**:
- - Соответствие PEP 8 (отступы, пробелы вокруг операторов)
- - Сохранение исходной структуры кода
- - Без изменений рабочей логики программы
\ No newline at end of file
diff --git a/docs/config/add_docstring.md b/docs/config/add_docstring.md
new file mode 100644
index 0000000..ac1faed
--- /dev/null
+++ b/docs/config/add_docstring.md
@@ -0,0 +1,14 @@
+**Добавление Docstring**
+
+Изменить строго соблюдая требования:
+1. Добавить недостающие и улучшить имеющиеся docstrings язык русский.
+2. Сделать docstring более компактными, сохранив всю важную информацию.
+3. Ограничить в docstring длину строк 79 символами.
+4. Добавить docstring перед импортами.
+5. Должна быть пустая строка после каждого docstring.
+6. Сохранить все текущие комментарии.
+7. Запрещено изменять код (изменять только docstring).
+8. Не удалять пустые строки.
+9. В конце кода должна быть одна пустая строка.
+
+Вывести полный изменённый код и отчет о выполнении требований
\ No newline at end of file
diff --git a/elements/base_element.py b/elements/base_element.py
index 8c5a907..72f1659 100644
--- a/elements/base_element.py
+++ b/elements/base_element.py
@@ -1,12 +1,30 @@
+"""Модуль base_element содержит базовый класс для работы с элементами страницы.
+
+Класс BaseElement предоставляет основные методы взаимодействия с элементами
+и их проверки через Playwright.
+"""
+
from playwright.sync_api import Page, Locator, expect, TimeoutError
from tools.logger import get_logger
logger = get_logger("BASE_ELEMENT")
class BaseElement:
- """Базовый класс для работы с элементами страницы."""
+ """Базовый класс для работы с элементами страницы через Playwright.
+
+ Предоставляет основные методы взаимодействия с элементами:
+ клики, получение текста, ожидание и проверки состояния.
+ """
def __init__(self, page: Page, locator: str | Locator, name: str) -> None:
+ """Инициализирует базовый элемент страницы.
+
+ Args:
+ page: Экземпляр страницы Playwright
+ locator: Локатор элемента (строка или объект Locator)
+ name: Имя элемента для логирования
+ """
+
self.page = page
self.name = name
self.locator: Locator
@@ -20,32 +38,46 @@ class BaseElement:
@property
def type_of(self) -> str:
+ """Возвращает тип элемента (для логирования)."""
+
return "base element"
# Действия:
def click(self) -> None:
+ """Выполняет клик по элементу."""
+
logger.info(f"Clicking {self.type_of} '{self.name}'")
self.locator.click()
def get_text(self, index: int) -> str:
+ """Возвращает текст элемента по указанному индексу."""
+
logger.info(f"Get text for {self.type_of} '{self.name}'")
return self.locator.nth(index).text_content()
def wait_for_element(self, timeout: int = 12000) -> None:
+ """Ожидает появление элемента в течение заданного времени."""
+
logger.info(f"Wait for {self.type_of} '{self.name}'")
self.locator.wait_for(timeout=timeout)
# Проверки:
def check_have_text(self, text: str, msg: str) -> None:
+ """Проверяет наличие указанного текста в элементе."""
+
logger.info(f"Check that {self.type_of} '{self.name}' has text '{text}'")
expect(self.locator).to_have_text(text), msg
def check_presence(self, msg: str) -> None:
+ """Проверяет видимость элемента на странице."""
+
logger.info(f"Check that {self.type_of} '{self.name}' is present")
print(self.locator)
expect(self.locator).to_be_visible(visible=True, timeout=12000), msg
def is_present(self, timeout: int = 5000) -> bool:
+ """Проверяет наличие элемента в течение заданного времени."""
+
logger.info(f"Check that {self.type_of} '{self.name}' is present")
try:
self.locator.wait_for(timeout=timeout)
@@ -54,6 +86,8 @@ class BaseElement:
return True
def is_not_present(self, timeout: int = 5000) -> bool:
+ """Проверяет отсутствие элемента в течение заданного времени."""
+
logger.info(f"Check that {self.type_of} '{self.name}' is missing")
try:
self.locator.wait_for(timeout=timeout)
diff --git a/elements/button_element.py b/elements/button_element.py
index 39434a7..8569d1b 100644
--- a/elements/button_element.py
+++ b/elements/button_element.py
@@ -1,3 +1,9 @@
+"""Модуль button_element содержит класс для работы с кнопками на странице.
+
+Класс Button наследует базовый функционал BaseElement и предоставляет
+специфичные методы для работы с элементами типа 'кнопка'.
+"""
+
from tools.logger import get_logger
from elements.base_element import BaseElement
@@ -5,18 +11,20 @@ logger = get_logger("BUTTON")
class Button(BaseElement):
- """Класс для работы с элементами типа 'кнопка' на странице.
+ """Класс для работы с кнопками на странице.
- Наследует функциональность базового элемента и добавляет специфичные для кнопок методы.
+ Наследует функциональность BaseElement и добавляет специфичные
+ для кнопок методы и проверки.
"""
@property
def type_of(self) -> str:
- """Возвращает тип элемента - 'кнопка'.
+ """Возвращает тип элемента ('кнопка').
Returns:
- Строка с типом элемента.
+ str: Тип элемента - 'кнопка'.
"""
+
return "button"
# Действия:
diff --git a/elements/checkbox_element.py b/elements/checkbox_element.py
index a1ad559..8811d1d 100644
--- a/elements/checkbox_element.py
+++ b/elements/checkbox_element.py
@@ -1,3 +1,9 @@
+"""Модуль checkbox_element содержит класс для работы с чекбоксами.
+
+Класс Checkbox наследует базовый функционал BaseElement и добавляет
+специфичные методы для работы с элементами типа 'чекбокс'.
+"""
+
from tools.logger import get_logger
from elements.base_element import BaseElement
@@ -5,28 +11,32 @@ logger = get_logger("CHECKBOX")
class Checkbox(BaseElement):
- """Класс для работы с элементами типа 'чекбокс' на странице.
+ """Класс для работы с чекбоксами на странице.
- Наследует функциональность базового элемента и добавляет специфичные для чекбоксов методы.
+ Наследует функциональность BaseElement и добавляет методы для
+ взаимодействия с чекбоксами и проверки их состояния.
"""
@property
def type_of(self) -> str:
- """Возвращает тип элемента - 'чекбокс'.
+ """Возвращает тип элемента ('чекбокс').
Returns:
- Строка с типом элемента.
+ str: Тип элемента - 'чекбокс'.
"""
+
return "checkbox"
# Действия:
def check(self) -> None:
- """Устанавливает чекбокс в отмеченное состояние."""
+ """Отмечает чекбокс (устанавливает галочку)."""
+
logger.info(f"Checking checkbox '{self.name}'")
self.locator.check()
def uncheck(self) -> None:
- """Снимает отметку с чекбокса."""
+ """Снимает отметку с чекбокса (убирает галочку)."""
+
logger.info(f"Unchecking checkbox '{self.name}'")
self.locator.uncheck()
@@ -35,7 +45,8 @@ class Checkbox(BaseElement):
"""Проверяет, отмечен ли чекбокс.
Returns:
- True, если чекбокс отмечен, иначе False.
+ bool: True если отмечен, False если нет.
"""
+
logger.info(f"Checking if checkbox '{self.name}' is checked")
return self.locator.is_checked()
diff --git a/elements/dropdown_list_element.py b/elements/dropdown_list_element.py
index 4de02e3..1a98c4a 100644
--- a/elements/dropdown_list_element.py
+++ b/elements/dropdown_list_element.py
@@ -1,43 +1,53 @@
+"""Модуль dropdown_list_element содержит класс для работы с выпадающими списками.
+
+Класс DropdownList наследует базовый функционал BaseElement и добавляет
+методы для взаимодействия с выпадающими списками на странице.
+"""
+
from tools.logger import get_logger
from elements.base_element import BaseElement
logger = get_logger("DROPDOWN_LIST")
class DropdownList(BaseElement):
- """Класс для работы с выпадающими списками на странице.
+ """Класс для работы с выпадающими списками.
- Наследует функциональность базового элемента и добавляет специфичные для dropdown-списков методы.
+ Наследует функциональность BaseElement и добавляет специфичные
+ методы для выбора и проверки элементов списка.
"""
@property
def type_of(self) -> str:
- """Возвращает тип элемента - 'выпадающий список'.
+ """Возвращает тип элемента ('выпадающий список').
Returns:
- Строка с типом элемента.
+ str: Тип элемента - 'выпадающий список'.
"""
+
return "dropdown list"
# Действия:
def click_item_with_text(self, text: str) -> None:
- """Кликает на элемент списка с указанным текстом.
+ """Выбирает элемент списка по указанному тексту.
Args:
- text: Текст элемента, который нужно выбрать.
+ text (str): Текст элемента для выбора.
"""
+
logger.info(f'Selecting item with text "{text}" from dropdown "{self.name}"')
self.page.get_by_role("listitem").filter(has_text=text).click()
# Проверки:
def check_item_with_text(self, text: str) -> None:
- """Проверяет наличие и доступность элемента с указанным текстом.
+ """Проверяет наличие и доступность элемента списка.
Args:
- text: Текст элемента, который нужно проверить.
+ text (str): Текст элемента для проверки.
Raises:
AssertionError: Если элемент отсутствует или недоступен.
"""
+
logger.info(f'Checking item with text "{text}" in dropdown "{self.name}"')
enabled = self.page.get_by_role("listitem").filter(has_text=text).is_enabled()
if not enabled:
diff --git a/elements/text_element.py b/elements/text_element.py
index 99f0de9..f20a1ce 100644
--- a/elements/text_element.py
+++ b/elements/text_element.py
@@ -1,21 +1,29 @@
+"""Модуль text_element содержит класс для работы с текстовыми элементами.
+
+Класс Text наследует базовый функционал BaseElement и предоставляет
+методы для работы с текстовыми элементами на странице.
+"""
+
from tools.logger import get_logger
from elements.base_element import BaseElement
logger = get_logger("TEXT")
class Text(BaseElement):
- """Класс для работы с текстовыми элементами на странице.
+ """Класс для работы с текстовыми элементами страницы.
- Наследует функциональность базового элемента и добавляет специфичные для текста методы.
+ Наследует функциональность BaseElement и добавляет специфичные
+ методы для взаимодействия с текстовыми элементами.
"""
@property
def type_of(self) -> str:
- """Возвращает тип элемента - 'текст'.
+ """Возвращает тип элемента ('текст').
Returns:
- Строка с типом элемента.
+ str: Тип элемента - 'текст'.
"""
+
return "text"
# Действия:
diff --git a/elements/text_input_element.py b/elements/text_input_element.py
index ea1ced7..10a3720 100644
--- a/elements/text_input_element.py
+++ b/elements/text_input_element.py
@@ -1,3 +1,9 @@
+"""Модуль text_input_element содержит класс для работы с текстовыми полями ввода.
+
+Класс TextInput наследует базовый функционал BaseElement и предоставляет
+методы для взаимодействия с текстовыми полями ввода на странице.
+"""
+
from playwright.sync_api import expect
from tools.logger import get_logger
from elements.base_element import BaseElement
@@ -6,54 +12,60 @@ logger = get_logger("TEXT_INPUT")
class TextInput(BaseElement):
- """Класс для работы с текстовыми полями ввода на странице.
+ """Класс для работы с текстовыми полями ввода.
- Наследует функциональность базового элемента и добавляет специфичные для текстовых полей методы.
+ Наследует функциональность BaseElement и добавляет методы
+ для ввода, очистки и проверки текстовых полей.
"""
@property
def type_of(self) -> str:
- """Возвращает тип элемента - 'текстовое поле ввода'.
+ """Возвращает тип элемента ('текстовое поле ввода').
Returns:
- Строка с типом элемента.
+ str: Тип элемента - 'текстовое поле ввода'.
"""
+
return "text input"
# Действия:
def get_input_value(self) -> str:
- """Получает текущее значение текстового поля.
+ """Возвращает текущее значение поля ввода.
Returns:
- Текущее значение поля ввода.
+ str: Текущее значение в поле.
"""
+
logger.info(f'Getting value from text input "{self.name}"')
return self.locator.input_value()
def input_value(self, value: str) -> None:
- """Вводит указанное значение в текстовое поле.
+ """Вводит указанное значение в поле.
Args:
- value: Значение для ввода.
+ value (str): Значение для ввода.
"""
+
logger.info(f'Inputting value "{value}" to text input "{self.name}"')
self.locator.fill(value)
def clear(self) -> None:
"""Очищает содержимое текстового поля."""
+
logger.info(f'Clearing text input "{self.name}"')
self.locator.press('Control+A')
self.locator.press('Backspace')
# Проверки:
def check_empty_input(self, msg: str) -> None:
- """Проверяет, что текстовое поле пустое.
+ """Проверяет, что поле ввода пустое.
Args:
- msg: Сообщение об ошибке при неудачной проверке.
+ msg (str): Сообщение об ошибке при неудачной проверке.
Raises:
AssertionError: Если поле не пустое.
"""
+
logger.info(f'Checking that text input "{self.name}" is empty')
expect(self.locator).to_be_empty(), msg
diff --git a/elements/tooltip_button_element.py b/elements/tooltip_button_element.py
index 45f148a..935ad54 100644
--- a/elements/tooltip_button_element.py
+++ b/elements/tooltip_button_element.py
@@ -1,33 +1,42 @@
+"""Модуль tooltip_button_element содержит класс для работы с кнопками с подсказками.
+
+Класс TooltipButton наследует базовый функционал BaseElement и добавляет
+методы для проверки всплывающих подсказок у кнопок.
+"""
+
from tools.logger import get_logger
from elements.base_element import BaseElement
logger = get_logger("TOOLTIP_BUTTON")
class TooltipButton(BaseElement):
- """Класс элемента кнопки с всплывающей подсказкой.
+ """Класс для работы с кнопками, имеющими всплывающие подсказки.
- Наследует функциональность базового элемента и добавляет методы для работы с подсказками.
+ Наследует функциональность BaseElement и добавляет методы
+ для взаимодействия с подсказками кнопок.
"""
@property
def type_of(self) -> str:
- """Возвращает тип элемента.
+ """Возвращает тип элемента ('tooltip_button').
Returns:
- str: Тип элемента ('tooltip_button')
+ str: Тип элемента - кнопка с подсказкой.
"""
+
return "tooltip_button"
def check_tooltip_with_text(self, tooltip_locator: str, expected_text: str) -> None:
- """Проверяет текст всплывающей подсказки.
+ """Проверяет соответствие текста всплывающей подсказки.
Args:
- tooltip_locator (str): Локатор элемента подсказки
- expected_text (str): Ожидаемый текст подсказки
+ tooltip_locator (str): Локатор элемента подсказки.
+ expected_text (str): Ожидаемый текст подсказки.
Raises:
- AssertionError: Если текст подсказки не соответствует ожидаемому
+ AssertionError: Если текст подсказки не соответствует ожидаемому.
"""
+
# Наведение на элемент для отображения подсказки
self.locator.hover()
diff --git a/fixtures/pages.py b/fixtures/pages.py
index af326ac..050c6ca 100644
--- a/fixtures/pages.py
+++ b/fixtures/pages.py
@@ -1,8 +1,10 @@
-"""Модуль для работы с Playwright в тестах pytest.
+"""Модуль pages содержит фикстуры и функции для работы с Playwright.
-Содержит фикстуры и вспомогательные функции для управления браузером.
+Предоставляет инструменты для управления браузером, контекстами и страницами
+в тестах pytest, включая настройку параметров запуска.
"""
+
import pytest
from playwright.sync_api import Browser, BrowserContext, Page, sync_playwright, Playwright
from _pytest.config.argparsing import Parser
@@ -10,19 +12,20 @@ from _pytest.fixtures import FixtureRequest
def pytest_addoption(parser: Parser):
- """Добавляет пользовательские опции командной строки для настройки браузера.
+ """Добавляет опции командной строки для настройки браузера.
Args:
parser: Парсер pytest для добавления опций.
- Доступные опции:
- --bn: Выбор браузера (chrome, remote_chrome или firefox)
+ Опции:
+ --bn: Браузер (chrome, remote_chrome, firefox)
--h: Режим headless (True/False)
- --s: Размер окна в формате {'width': int, 'height': int}
- --slow: Задержка между действиями (slow_mo)
+ --s: Размер окна {'width': int, 'height': int}
+ --slow: Задержка между действиями (мс)
--t: Таймаут по умолчанию (мс)
--l: Локаль браузера
"""
+
parser.addoption('--bn', action='store', default="chrome",
help="Choose browser: chrome, remote_chrome or firefox")
parser.addoption('--h', action='store', default=False,
@@ -48,7 +51,7 @@ def pytest_addoption(parser: Parser):
@pytest.fixture(scope='class')
def browser(request: FixtureRequest) -> Page:
- """Фикстура для создания и управления экземпляром браузера.
+ """Фикстура для управления экземпляром браузера.
Args:
request: Объект запроса pytest для доступа к конфигурации.
@@ -57,11 +60,12 @@ def browser(request: FixtureRequest) -> Page:
Page: Экземпляр страницы браузера.
Yields:
- Page: Экземпляр страницы для использования в тестах.
+ Page: Страница для использования в тестах.
Note:
- Автоматически закрывает браузер и контексты после завершения тестов.
+ Автоматически закрывает браузер после тестов.
"""
+
playwright = sync_playwright().start()
# Выбор браузера на основе параметра командной строки
@@ -96,11 +100,12 @@ def get_firefox_browser(playwright: Playwright, request: FixtureRequest) -> Brow
Args:
playwright: Экземпляр Playwright.
- request: Объект запроса pytest для доступа к конфигурации.
+ request: Объект запроса pytest.
Returns:
- Browser: Экземпляр Firefox браузера.
+ Browser: Экземпляр Firefox.
"""
+
return playwright.firefox.launch(
headless=request.config.getoption("h"),
slow_mo=request.config.getoption("slow"),
@@ -112,11 +117,12 @@ def get_chrome_browser(playwright: Playwright, request: FixtureRequest) -> Brows
Args:
playwright: Экземпляр Playwright.
- request: Объект запроса pytest для доступа к конфигурации.
+ request: Объект запроса pytest.
Returns:
- Browser: Экземпляр Chrome браузера.
+ Browser: Экземпляр Chrome.
"""
+
return playwright.chromium.launch(
headless=request.config.getoption("h"),
slow_mo=request.config.getoption("slow"),
@@ -125,15 +131,16 @@ def get_chrome_browser(playwright: Playwright, request: FixtureRequest) -> Brows
def get_remote_chrome(playwright: Playwright, request: FixtureRequest) -> Browser:
- """Создает и возвращает экземпляр Chrome браузера для удаленного запуска.
+ """Создает экземпляр Chrome для удаленного запуска.
Args:
playwright: Экземпляр Playwright.
- request: Объект запроса pytest для доступа к конфигурации.
+ request: Объект запроса pytest.
Returns:
- Browser: Экземпляр Chrome браузера в режиме headless.
+ Browser: Экземпляр Chrome в headless режиме.
"""
+
return playwright.chromium.launch(
headless=True,
slow_mo=request.config.getoption("slow")
@@ -145,12 +152,13 @@ def get_context(browser: Browser, request: FixtureRequest, start: str) -> Browse
Args:
browser: Экземпляр браузера.
- request: Объект запроса pytest для доступа к конфигурации.
+ request: Объект запроса pytest.
start: Тип запуска ('local' или 'remote').
Returns:
- BrowserContext: Настроенный контекст браузера.
+ BrowserContext: Настроенный контекст.
"""
+
if start == 'local':
context = browser.new_context(
# no_viewport=True,
@@ -179,9 +187,10 @@ def get_context(browser: Browser, request: FixtureRequest, start: str) -> Browse
@pytest.fixture(scope="function")
def return_back(browser: Page):
- """Фикстура для возврата на предыдущую страницу в браузере.
+ """Фикстура для возврата на предыдущую страницу.
Args:
browser: Экземпляр страницы браузера.
"""
+
browser.go_back()
diff --git a/locators/button_locators.py b/locators/button_locators.py
index f20d313..c2b6040 100644
--- a/locators/button_locators.py
+++ b/locators/button_locators.py
@@ -1,4 +1,18 @@
+"""Модуль button_locators содержит локаторы для кнопок и элементов интерфейса.
+
+Класс ButtonLocators хранит XPath и CSS локаторы для взаимодействия
+с кнопками и всплывающими подсказками в тестах.
+"""
+
class ButtonLocators:
+ """Класс для хранения локаторов кнопок и связанных элементов.
+
+ Содержит локаторы в формате XPath и CSS для поиска элементов:
+ - Кнопка обновления лицензии
+ - Всплывающая подсказка
+ - Кнопка удаления сессии
+ """
+
BUTTON_LICENSE_UPDATE = "//div[@class='scrollarea__footer']//button"
TOOLTIP = "//div[contains(@class,'v-tooltip__content menuable__content__active')]"
BUTTON_DELETE_SESSION = "button.v-btn--icon svg[fill='#4caf50']"
diff --git a/locators/confirm_locators.py b/locators/confirm_locators.py
index 7f6783e..75c0e2f 100644
--- a/locators/confirm_locators.py
+++ b/locators/confirm_locators.py
@@ -1,12 +1,19 @@
+"""Модуль confirm_locators содержит локаторы элементов диалогов подтверждения.
+
+Класс ConfirmLocators предоставляет XPath локаторы для взаимодействия
+с диалоговыми окнами подтверждения действий в тестах.
+"""
+
class ConfirmLocators:
"""Локаторы элементов диалогов подтверждения.
- Атрибуты:
- CONFIRM (str): XPath локатор активного диалогового окна.
- TITLE (str): XPath локатор заголовка диалогового окна.
- BUTTON_CLOSE (str): XPath локатор кнопки закрытия диалога.
- TEXT (str): XPath локатор текстового содержимого диалога (формируется динамически).
+ Содержит XPath локаторы для:
+ CONFIRM (str): активного диалогового окна.
+ TITLE (str): заголовка диалогового окна.
+ BUTTON_CLOSE (str): кнопки закрытия диалога.
+ TEXT (str): текстового содержимого диалога (формируется динамически).
"""
+
CONFIRM = "//div[contains(@class, 'v-dialog--active')]"
TITLE = "//div[@class='v-card__title']/h3"
BUTTON_CLOSE = "//div[@class='vuedl-layout__closeBtn']"
diff --git a/locators/event_panel_locators.py b/locators/event_panel_locators.py
index 4483d86..7ff31d2 100644
--- a/locators/event_panel_locators.py
+++ b/locators/event_panel_locators.py
@@ -1,8 +1,15 @@
+"""Модуль event_panel_locators содержит локаторы элементов панели событий.
+
+Класс EventPanelLocators предоставляет XPath локаторы для взаимодействия
+с элементами панели событий в тестах.
+"""
+
class EventPanelLocators:
"""Локаторы элементов панели событий.
- Атрибуты:
- BUTTONS_BLOCK (str): XPath локатор блока кнопок в панели инструментов.
- Находится во втором блоке элементов toolbar'а внутри контентной области.
+
+ Содержит XPath локаторы для:
+ BUTTONS_BLOCK (str): блока кнопок в панели инструментов
"""
+
BUTTONS_BLOCK = "//nav/div[@class='v-toolbar__content']/div[@class='v-toolbar__items'][2]"
diff --git a/locators/input_locators.py b/locators/input_locators.py
index 658335c..d2d9e15 100644
--- a/locators/input_locators.py
+++ b/locators/input_locators.py
@@ -1,12 +1,19 @@
+"""Модуль input_locators содержит локаторы полей ввода на странице.
+
+Класс InputLocators предоставляет XPath локаторы для взаимодействия
+с текстовыми полями ввода в тестах.
+"""
+
class InputLocators:
"""Локаторы для полей ввода на странице.
- Атрибуты:
- LICENSE_ID_UPDATE (str): XPath локатор текстового поля для ввода/обновления
- идентификатора лицензии, расположенного в подвале страницы.
- Состоит из нескольких частей:
- - Блок подвала (scrollarea__footer)
- - Контейнер поля ввода (v-input__control)
- - Непосредственно текстовое поле (textarea)
+
+ Содержит XPath локаторы для:
+ LICENSE_ID_UPDATE (str): поля ввода идентификатора лицензии в подвале
+
+
+
+
"""
+
LICENSE_ID_UPDATE = "//div[@class='scrollarea__footer']//div[@class='v-input__control']//textarea"
diff --git a/locators/json_container_locators.py b/locators/json_container_locators.py
index e4630b8..0f073bb 100644
--- a/locators/json_container_locators.py
+++ b/locators/json_container_locators.py
@@ -1,11 +1,16 @@
+"""Модуль json_container_locators содержит локаторы контейнеров JSON-данных.
+
+Класс JsonContainerLocators предоставляет XPath локаторы для работы
+с контейнерами JSON-данных на странице.
+"""
+
class JsonContainerLocators:
"""Локаторы для контейнеров JSON-данных на странице.
- Атрибуты:
- CONTAINER (str): XPath локатор основного контейнера JSON-данных.
- Ищет div с классом, содержащим 'jv-container'.
- SCROLL_CONTAINER (str): XPath локатор прокручиваемой области контейнера.
- Ищет div с классом, содержащим 'scrollarea__body'.
+ Содержит XPath локаторы для:
+ CONTAINER (str): основного контейнера JSON-данных
+ SCROLL_CONTAINER (str): прокручиваемой области контейнера
"""
+
CONTAINER = "//div[contains(@class,'jv-container')]"
SCROLL_CONTAINER = "//div[contains(@class, 'scrollarea__body')]"
diff --git a/locators/modal_window_locators.py b/locators/modal_window_locators.py
index 441da20..ddba607 100644
--- a/locators/modal_window_locators.py
+++ b/locators/modal_window_locators.py
@@ -1,16 +1,23 @@
+"""Модуль modal_window_locators содержит локаторы элементов модальных окон.
+
+Класс ModalWindowLocators предоставляет XPath локаторы для взаимодействия
+с элементами модальных окон в тестах.
+"""
+
class ModalWindowLocators:
"""Локаторы для элементов модальных окон.
- Атрибуты:
- MODAL_WINDOW (str): XPath локатор активного модального окна.
- INPUT_FORM_USER_DATA (str): XPath локатор формы для ввода пользовательских данных.
- TEXT_FIELD_INPUT_FORM_USER_DATA (str): Относительный XPath текстового поля ввода
- внутри формы пользовательских данных.
- ROLES_FIELD_INPUT_FORM_USER_DATA (str): Относительный XPath поля выбора ролей
- внутри формы пользовательских данных.
- ROLES_MENU_INPUT_FORM_USER_DATA (str): XPath локатор активного меню выбора ролей.
- LABEL_INPUT_FORM_USER_DATA (str): XPath локатор метки поля ввода в форме.
+ Содержит XPath локаторы для:
+ MODAL_WINDOW (str): активного модального окна
+ INPUT_FORM_USER_DATA (str): формы ввода пользовательских данных
+ TEXT_FIELD_INPUT_FORM_USER_DATA (str): текстового поля ввода
+
+ ROLES_FIELD_INPUT_FORM_USER_DATA (str): поля выбора ролей
+
+ ROLES_MENU_INPUT_FORM_USER_DATA (str): меню выбора ролей
+ LABEL_INPUT_FORM_USER_DATA (str): метки поля ввода
"""
+
MODAL_WINDOW = "//div[contains(@class, 'v-dialog--active')]"
INPUT_FORM_USER_DATA = "//form[@class='v-form']"
diff --git a/locators/navigation_panel_locators.py b/locators/navigation_panel_locators.py
index 39956d2..a299cea 100644
--- a/locators/navigation_panel_locators.py
+++ b/locators/navigation_panel_locators.py
@@ -1,17 +1,19 @@
+"""Модуль navigation_panel_locators содержит локаторы навигационной панели.
+
+Класс NavigationPanelLocators предоставляет XPath локаторы для работы
+с элементами навигационной панели в тестах.
+"""
+
class NavigationPanelLocators:
"""Локаторы элементов навигационной панели.
- Атрибуты:
- PANEL_MAIN (str): XPath локатор основной панели навигации.
- Ищет элемент ul с классом, содержащим 'v-expansion-panel'.
- PANEL_SCROLL_CONTAINER (str): XPath локатор контейнера с прокруткой,
- содержащего навигационную панель. Ищет div с классом 'scrollarea__body',
- внутри которого находится панель навигации.
- NODE_ROOT (str): XPath локатор корневого узла дерева навигации.
- Ищет div с классом, содержащим 'v-treeview-node__root'.
- NODE_CHILDREN (str): XPath локатор дочерних элементов узла дерева.
- Ищет div с классом, содержащим 'v-treeview-node__children'.
+ Содержит XPath локаторы для:
+ PANEL_MAIN (str): основной панели навигации
+ PANEL_SCROLL_CONTAINER (str): контейнера с прокруткой
+ NODE_ROOT (str): корневого узла дерева
+ NODE_CHILDREN (str): дочерних элементов узла
"""
+
PANEL_MAIN = "//ul[contains(@class, 'v-expansion-panel')]"
PANEL_SCROLL_CONTAINER = "//div[contains(@class, 'scrollarea__body') and .//ul[contains(@class, 'v-expansion-panel')]]"
diff --git a/locators/table_locators.py b/locators/table_locators.py
index 01c27c7..1320232 100644
--- a/locators/table_locators.py
+++ b/locators/table_locators.py
@@ -1,13 +1,16 @@
+"""Модуль table_locators содержит локаторы табличных элементов.
+
+Класс TableLocators предоставляет XPath локаторы для работы
+с таблицами в рабочей области приложения.
+"""
+
class TableLocators:
"""Локаторы для табличных элементов в рабочей области.
- Атрибуты:
- TABLE_WORK_AREA (str): XPath локатор основной таблицы в рабочей области.
- Ищет элемент table, находящийся по пути:
- scrollarea__body -> div -> div -> div -> table
- TABLE_SCROLL_CONTAINER (str): XPath локатор контейнера с прокруткой таблицы.
- Ищет tbody внутри div с классом scrollarea__body,
- содержащего таблицу с классом scrolltable__container.
+ Содержит XPath локаторы для:
+ TABLE_WORK_AREA (str): основной таблицы в рабочей области
+ TABLE_SCROLL_CONTAINER (str): контейнера с прокруткой таблицы
"""
+
TABLE_WORK_AREA = "//div[@class='scrollarea__body']/div/div/div/table"
TABLE_SCROLL_CONTAINER = "//div[contains(@class, 'scrollarea__body') and .//table[@class='scrolltable__container']]//tbody"
diff --git a/locators/text_locators.py b/locators/text_locators.py
index 28a3bd9..15d0d5d 100644
--- a/locators/text_locators.py
+++ b/locators/text_locators.py
@@ -1,11 +1,16 @@
+"""Модуль text_locators содержит локаторы текстовых элементов.
+
+Класс TextLocators предоставляет XPath локаторы для работы
+с текстовыми элементами на страницах приложения.
+"""
+
class TextLocators:
"""Локаторы для текстовых элементов на странице.
- Атрибуты:
- TITLE_LICENSE_INPUT_FORM (str): XPath локатор заголовка формы ввода лицензии.
- Ищет span с классом 'title'.
- LICENSE_ID (str): XPath локатор отображаемого идентификатора лицензии.
- Ищет span с классами 'title' и 'text_select' (выделяемый текст).
+ Содержит XPath локаторы для:
+ TITLE_LICENSE_INPUT_FORM (str): заголовка формы ввода лицензии
+ LICENSE_ID (str): отображаемого ID лицензии (выделяемый текст)
"""
+
TITLE_LICENSE_INPUT_FORM = "//span[@class='title']"
LICENSE_ID = "//span[@class='title text_select']"
diff --git a/locators/toolbar_locators.py b/locators/toolbar_locators.py
index a16603d..1897fe8 100644
--- a/locators/toolbar_locators.py
+++ b/locators/toolbar_locators.py
@@ -1,15 +1,16 @@
-class ToolbarLocators:
- """Локаторы элементов тулбара (панели инструментов).
+"""Модуль toolbar_locators содержит локаторы элементов панели инструментов.
- Атрибуты:
- TITLE (str): XPath локатор заголовка тулбара.
- Находится в навигационной панели (nav) внутри элемента с классом,
- содержащим 'v-toolbar__title'.
-
- TOOLTIP (str): XPath локатор активного всплывающего подсказывающего элемента.
- Ищет div с классами, содержащими:
- - 'v-tooltip__content' (основа тултипа)
- - 'menuable__content__active' (показанное состояние)
+Класс ToolbarLocators предоставляет XPath локаторы для взаимодействия
+с элементами тулбара и всплывающими подсказками.
+"""
+
+class ToolbarLocators:
+ """Локаторы элементов панели инструментов (тулбара).
+
+ Содержит XPath локаторы для:
+ TITLE (str): заголовка тулбара
+ TOOLTIP (str): активной всплывающей подсказки
"""
+
TITLE = "//nav//div[contains(@class, 'v-toolbar__title')]"
TOOLTIP = "//div[contains(@class,'v-tooltip__content menuable__content__active')]"
diff --git a/modal_windows/modal_add_user.py b/modal_windows/modal_add_user.py
index 97c8b5d..0bbeecf 100644
--- a/modal_windows/modal_add_user.py
+++ b/modal_windows/modal_add_user.py
@@ -1,3 +1,9 @@
+"""Модуль modal_add_user содержит класс для работы с модальным окном добавления пользователя.
+
+Класс AddUserModalWindow наследует базовый функционал ModalWindowComponent
+и реализует специфичные методы для работы с формами добавления пользователей.
+"""
+
import re
from playwright.sync_api import Page
from tools.logger import get_logger
@@ -15,20 +21,18 @@ logger = get_logger("ADD_USER_MODAL_WINDOW")
class AddUserModalWindow(ModalWindowComponent):
- """Класс модального окна добавления нового пользователя.
+ """Модальное окно добавления нового пользователя.
- Наследует функциональность базового модального окна и добавляет специфичные элементы:
- - Поля ввода данных пользователя
- - Чекбоксы
+ Наследует ModalWindowComponent и добавляет элементы формы:
+ - Поля ввода (имя, пароль, email и др.)
+ - Чекбоксы (Active Directory, Push-уведомления)
- Выпадающий список ролей
- Кнопки действий
-
- Args:
- page (Page): Экземпляр страницы Playwright
"""
def __init__(self, page: Page):
- """Инициализация компонентов модального окна добавления пользователя."""
+ """Инициализирует элементы формы добавления пользователя."""
+
super().__init__(page)
# Локаторы элементов формы
@@ -117,19 +121,9 @@ class AddUserModalWindow(ModalWindowComponent):
"""Заполняет форму и добавляет нового пользователя.
Args:
- user_data (dict): Словарь с данными пользователя. Может содержать ключи:
- - active_directory_checked (bool): Состояние чекбокса Active Directory
- - name (str): Имя пользователя
- - role (str): Роль пользователя
- - password (str): Пароль пользователя
- - commentary (str): Комментарий
- - email (str): Email
- - phone_number (str): Номер телефона
- - push_notification_checked (bool): Состояние чекбокса Push-уведомлений
-
- Raises:
- AssertionError: Если подтверждающее окно не отображается
+ user_data (dict): Данные пользователя (имя, роль, пароль и др.)
"""
+
fields = user_data.keys()
if "active_directory_checked" in fields:
@@ -187,20 +181,19 @@ class AddUserModalWindow(ModalWindowComponent):
self.new_user_confirm.click_allow_button()
def close_window(self):
- """Закрывает модальное окно с помощью кнопки 'Закрыть'."""
+ """Закрывает модальное окно через кнопку 'Закрыть'."""
+
close_button = self.get_button_by_name("close")
close_button.click()
def close_window_by_toolbar_button(self):
- """Закрывает модальное окно с помощью кнопки закрытия в тулбаре."""
+ """Закрывает модальное окно через кнопку в тулбаре."""
+
self.click_toolbar_close_button()
def check_content(self):
- """Проверяет наличие и корректность всех элементов модального окна.
+ """Проверяет наличие и корректность всех элементов формы."""
- Raises:
- AssertionError: Если какой-либо элемент отсутствует или содержит некорректные данные
- """
self.check_by_window_title()
self.check_toolbar_button_presence("close")
diff --git a/modal_windows/modal_edit_user.py b/modal_windows/modal_edit_user.py
index 07ab645..549c743 100644
--- a/modal_windows/modal_edit_user.py
+++ b/modal_windows/modal_edit_user.py
@@ -1,3 +1,9 @@
+"""Модуль modal_edit_user содержит класс для работы с окном редактирования пользователя.
+
+Класс EditUserModalWindow наследует базовый функционал ModalWindowComponent
+и реализует методы для редактирования данных пользователя.
+"""
+
import re
from playwright.sync_api import Page
from tools.logger import get_logger
@@ -13,21 +19,18 @@ logger = get_logger("EDIT_USER_MODAL_WINDOW")
class EditUserModalWindow(ModalWindowComponent):
- """Класс модального окна редактирования пользователя.
+ """Модальное окно редактирования пользователя.
- Наследует функциональность базового модального окна и добавляет:
- - Поля редактирования данных пользователя
+ Наследует ModalWindowComponent и добавляет:
+ - Поля редактирования данных
- Чекбоксы настроек
- Выпадающий список ролей
- - Кнопки действий (Сохранить, Удалить, Сбросить пароль)
-
- Args:
- page (Page): Экземпляр страницы Playwright
- user_name (str): Имя редактируемого пользователя (используется в заголовке)
+ - Кнопки действий (Сохранить, Удалить и др.)
"""
def __init__(self, page: Page, user_name: str):
- """Инициализация компонентов модального окна редактирования пользователя."""
+ """Инициализирует элементы формы редактирования пользователя."""
+
super().__init__(page)
# Локаторы элементов формы
@@ -104,20 +107,19 @@ class EditUserModalWindow(ModalWindowComponent):
self.delete_user_confirm = ConfirmComponent(page, " Отмена ", " Удалить ")
def close_window(self):
- """Закрывает модальное окно с помощью кнопки 'Закрыть'."""
+ """Закрывает окно через кнопку 'Закрыть'."""
+
close_button = self.get_button_by_name("close")
close_button.click()
def close_window_by_toolbar_button(self):
- """Закрывает модальное окно с помощью кнопки закрытия в тулбаре."""
+ """Закрывает окно через кнопку в тулбаре."""
+
self.click_toolbar_close_button()
def delete_user(self):
- """Удаляет пользователя с подтверждением действия.
+ """Удаляет пользователя с подтверждением."""
- Raises:
- AssertionError: Если окно подтверждения не отображается
- """
delete_button = self.get_button_by_name("delete")
delete_button.click()
@@ -132,14 +134,9 @@ class EditUserModalWindow(ModalWindowComponent):
"""Редактирует данные пользователя.
Args:
- user_data (dict): Словарь с обновляемыми данными пользователя. Может содержать:
- - name (str): Имя пользователя
- - role (str): Роль пользователя
- - commentary (str): Комментарий
- - email (str): Email
- - phone_number (str): Номер телефона
- - push_notification_checked (bool): Состояние чекбокса уведомлений
+ user_data (dict): Данные для обновления (имя, роль и др.)
"""
+
fields = user_data.keys()
if "name" in fields:
@@ -185,19 +182,18 @@ class EditUserModalWindow(ModalWindowComponent):
def reset_password(self):
"""Инициирует сброс пароля пользователя."""
+
reset_password_button = self.get_button_by_name("reset_password")
reset_password_button.click()
def check_content(self, user_name, role):
- """Проверяет наличие и корректность всех элементов окна.
+ """Проверяет наличие и корректность элементов окна.
Args:
user_name (str): Ожидаемое имя пользователя
role (str): Ожидаемая роль пользователя
-
- Raises:
- AssertionError: Если какой-либо элемент отсутствует или содержит некорректные данные
"""
+
self.check_by_window_title()
self.check_toolbar_button_presence("close")
self.check_toolbar_button_tooltip("close", "Закрыть")
diff --git a/pages/base_page.py b/pages/base_page.py
index f64b8c1..017b370 100644
--- a/pages/base_page.py
+++ b/pages/base_page.py
@@ -1,4 +1,8 @@
-"""Базовый класс страницы для работы с Playwright."""
+"""Модуль base_page содержит базовый класс для работы со страницами.
+
+Класс BasePage предоставляет общие методы для взаимодействия
+со страницами через Playwright и выполнения API-запросов.
+"""
import json
from typing import Any, Dict, List, Optional
@@ -10,28 +14,56 @@ logger = get_logger("BASE_PAGE")
class BasePage:
- """Базовый класс для работы со страницами через Playwright."""
+ """Базовый класс для работы со страницами через Playwright.
+
+ Содержит общие методы для:
+ - Навигации по страницам
+ - Выполнения API-запросов
+ - Проверок состояния страницы
+ """
def __init__(self, page: Page) -> None:
+ """Инициализирует базовую страницу.
+
+ Args:
+ page: Экземпляр страницы Playwright
+ """
+
self.page = page
# Действия:
def current_url(self) -> str:
+ """Возвращает текущий URL страницы."""
+
return self.page.url
def open(self, uri: str) -> Optional[Response]:
+ """Открывает указанный URI на базовом URL."""
+
return self.page.goto(f"{host.get_base_url()}{uri}", wait_until='domcontentloaded')
def page_reload(self) -> None:
+ """Перезагружает текущую страницу."""
+
self.page.reload()
def wait_for_timeout(self, timeout: int) -> None:
+ """Ожидает указанное количество миллисекунд."""
+
self.page.wait_for_timeout(timeout)
def get_api_request_context(self) -> APIRequestContext:
+ """Возвращает контекст для выполнения API-запросов."""
+
return self.page.context.request
def send_get_api_request(self, uri: str) -> Response:
+ """Отправляет GET-запрос к API.
+
+ Args:
+ uri: URI для запроса
+ """
+
api_request_context = self.get_api_request_context()
token = host.get_access_token()
headers = {"Accept": "application/json", "Authorization": f"Bearer {token}"}
@@ -42,6 +74,13 @@ class BasePage:
return response
def send_post_api_request(self, uri: str, payload: Dict[str, Any]) -> Response:
+ """Отправляет POST-запрос к API.
+
+ Args:
+ uri: URI для запроса
+ payload: Тело запроса
+ """
+
api_request_context = self.get_api_request_context()
token = host.get_access_token()
headers = {"Accept": "application/json", "Authorization": f"Bearer {token}"}
@@ -53,6 +92,12 @@ class BasePage:
return response
def get_response_body(self, response: Response) -> Optional[Dict[str, Any]]:
+ """Возвращает тело ответа в формате JSON.
+
+ Args:
+ response: Объект ответа
+ """
+
try:
response_body = response.json()
except json.JSONDecodeError:
@@ -62,15 +107,38 @@ class BasePage:
# Проверки:
def check_URL(self, uri: str, msg: str) -> None:
+ """Проверяет соответствие текущего URL ожидаемому.
+
+ Args:
+ uri: Ожидаемый URI
+ msg: Сообщение об ошибке
+ """
+
expect(self.page).to_have_url(
f"{host.get_base_url()}{uri}",
timeout=60000
), msg
def check_equals(self, actual: Any, expected: Any, msg: str) -> None:
+ """Проверяет равенство фактического и ожидаемого значений.
+
+ Args:
+ actual: Фактическое значение
+ expected: Ожидаемое значение
+ msg: Сообщение об ошибке
+ """
+
assert actual == expected, msg
def check_lists_equals(self, actual: List[Any], expected: List[Any], msg: str) -> None:
+ """Рекурсивно проверяет равенство двух списков.
+
+ Args:
+ actual: Фактический список
+ expected: Ожидаемый список
+ msg: Сообщение об ошибке
+ """
+
def compare_lists(list1: List[Any], list2: List[Any]) -> bool:
if len(list1) != len(list2):
return False
diff --git a/pages/license_tab.py b/pages/license_tab.py
index 0d21a06..739bb6a 100644
--- a/pages/license_tab.py
+++ b/pages/license_tab.py
@@ -1,3 +1,9 @@
+"""Модуль license_tab содержит класс для работы с вкладкой 'Лицензии'.
+
+Класс LicenseTab наследует BasePage и реализует методы для взаимодействия
+с элементами вкладки лицензий и проверки их состояния.
+"""
+
from playwright.sync_api import Page
from locators.text_locators import TextLocators
from locators.input_locators import InputLocators
@@ -14,23 +20,19 @@ from pages.base_page import BasePage
class LicenseTab(BasePage):
"""Класс для работы с вкладкой 'Лицензии'.
- Атрибуты:
- page (Page): Экземпляр страницы Playwright.
- toolbar (ToolbarComponent): Компонент панели инструментов.
- json_container (JsonContainerComponent): Компонент контейнера с JSON-данными.
- input_form_title (Text): Заголовок формы ввода.
- license_id (Text): Текстовый элемент с идентификатором лицензии.
- license_id_input (TextInput): Поле ввода идентификатора лицензии.
- update_button (Button): Кнопка обновления лицензии.
- error_alert (AlertComponent): Компонент алерта с ошибкой.
+ Содержит методы для:
+ - Взаимодействия с формой ввода лицензии
+ - Проверки содержимого JSON-контейнера
+ - Работы с элементами управления
"""
def __init__(self, page: Page) -> None:
"""Инициализирует элементы вкладки 'Лицензии'.
Args:
- page: Экземпляр страницы Playwright.
+ page: Экземпляр страницы Playwright
"""
+
super().__init__(page)
self.toolbar = ToolbarComponent(page, "Лицензии")
@@ -45,37 +47,42 @@ class LicenseTab(BasePage):
# Действия:
def fill_license_input_form(self, value: str) -> None:
- """Заполняет форму ввода идентификатора лицензии и нажимает кнопку обновления.
+ """Заполняет форму ввода лицензии указанным значением.
Args:
- value: Значение для ввода в поле идентификатора лицензии.
+ value: Значение для ввода
"""
+
self.license_id_input.clear()
self.license_id_input.input_value(value)
self.update_button.click()
def scroll_json_container_up(self) -> None:
"""Прокручивает JSON-контейнер вверх."""
+
loc = self.page.locator(JsonContainerLocators.SCROLL_CONTAINER).first
self.json_container.scroll_up(loc)
def scroll_json_container_down(self) -> None:
"""Прокручивает JSON-контейнер вниз."""
+
loc = self.page.locator(JsonContainerLocators.SCROLL_CONTAINER).first
self.json_container.scroll_down(loc)
# Проверки:
def check_json_container_verticall_scrolling(self) -> bool:
- """Проверяет возможность вертикальной прокрутки JSON-контейнера.
+ """Проверяет возможность вертикальной прокрутки контейнера.
Returns:
- bool: True если контейнер можно прокручивать, иначе False.
+ bool: Доступность прокрутки
"""
+
loc = self.page.locator(JsonContainerLocators.SCROLL_CONTAINER).first
return self.json_container.is_scrollable_vertically(loc)
def check_content(self) -> None:
- """Проверяет наличие всех основных элементов на вкладке."""
+ """Проверяет наличие всех основных элементов вкладки."""
+
self.should_be_toolbar()
self.should_be_json_container()
self.should_be_input_form_title()
@@ -83,27 +90,31 @@ class LicenseTab(BasePage):
self.should_be_update_button()
def should_be_error_alert_window_with_text(self, text: str) -> None:
- """Проверяет наличие и отсутствие алерта с указанным текстом.
+ """Проверяет наличие/отсутствие алерта с указанным текстом.
Args:
- text: Текст для проверки в алерте.
+ text: Текст для проверки
"""
+
self.error_alert.check_alert_presence(text)
self.error_alert.check_alert_absence(text)
def should_be_toolbar(self) -> None:
"""Проверяет наличие панели инструментов."""
+
self.toolbar.check_toolbar_presence("Toolbar is missing")
def should_be_json_container(self) -> None:
- """Проверяет наличие JSON-контейнера с информацией о лицензии."""
+ """Проверяет наличие JSON-контейнера."""
+
self.json_container.check_presence(
JsonContainerLocators.CONTAINER,
"Json container with license info is missing"
)
def should_be_input_form_title(self) -> None:
- """Проверяет заголовок формы ввода и соответствие ID лицензии."""
+ """Проверяет заголовок формы и соответствие ID лицензии."""
+
self.input_form_title.check_have_text(
"Идентификатор:",
"Input lisence id form title 'Идентификатор:' is missing"
@@ -122,11 +133,13 @@ class LicenseTab(BasePage):
)
def should_be_empty_input_form(self) -> None:
- """Проверяет, что форма ввода идентификатора лицензии пуста."""
+ """Проверяет пустоту формы ввода лицензии."""
+
self.license_id_input.check_empty_input("Input lisence id form is missing or not empty")
def should_be_update_button(self) -> None:
- """Проверяет наличие кнопки обновления лицензии с правильным текстом."""
+ """Проверяет наличие кнопки обновления лицензии."""
+
button_text = "Обновить лицензию"
self.update_button.check_have_text(
button_text,
@@ -134,7 +147,8 @@ class LicenseTab(BasePage):
)
def verify_json_container_content(self) -> None:
- """Проверяет соответствие содержимого JSON-контейнера данным из API."""
+ """Проверяет соответствие данных контейнера данным из API."""
+
actual_data = self.json_container.read_data(JsonContainerLocators.CONTAINER)
# send request to backend to get license info
diff --git a/pages/login_page.py b/pages/login_page.py
index 536a770..81b9622 100644
--- a/pages/login_page.py
+++ b/pages/login_page.py
@@ -1,3 +1,9 @@
+"""Модуль страницы авторизации.
+
+Содержит класс LoginPage для работы с элементами страницы входа в систему.
+Использует Playwright для взаимодействия с UI и обработки ответов сервера.
+"""
+
from playwright.sync_api import Page
from elements.text_input_element import TextInput
from elements.button_element import Button
@@ -10,11 +16,11 @@ class LoginPage(BasePage):
"""Класс для работы со страницей авторизации.
Атрибуты:
- page (Page): Экземпляр страницы Playwright.
- login_input (TextInput): Поле ввода логина.
- password_input (TextInput): Поле ввода пароля.
- login_button (Button): Кнопка входа.
- error_alert (AlertComponent): Компонент алерта с ошибкой.
+ page: Экземпляр страницы Playwright.
+ login_input: Поле ввода логина.
+ password_input: Поле ввода пароля.
+ login_button: Кнопка входа.
+ error_alert: Компонент алерта с ошибкой.
"""
def __init__(self, page: Page) -> None:
@@ -23,6 +29,7 @@ class LoginPage(BasePage):
Args:
page: Экземпляр страницы Playwright.
"""
+
super().__init__(page)
self.login_input = TextInput(page, page.get_by_label("Имя пользователя"), "login input")
@@ -34,16 +41,17 @@ class LoginPage(BasePage):
def do_login(self, username: str = None, password: str = None) -> None:
"""Выполняет вход в систему.
- Если username/password не указаны, использует значения из Constants.
+ Использует переданные учетные данные или значения из Constants.
Обрабатывает ответ сервера для получения токена доступа.
Args:
- username: Логин пользователя. Если None, используется значение из Constants.
- password: Пароль пользователя. Если None, используется значение из Constants.
+ username: Логин пользователя. По умолчанию из Constants.
+ password: Пароль пользователя. По умолчанию из Constants.
Raises:
AssertionError: Если после входа открылась неожиданная страница.
"""
+
def handle_response(response):
if "login" in response.url:
response_body = self.get_response_body(response)
@@ -72,13 +80,14 @@ class LoginPage(BasePage):
def do_unsuccessful_login(self, username: str = "someuser", password: str = "password") -> None:
"""Выполняет попытку входа с неверными учетными данными.
- Можно передать свои неверные данные или использовать значения по умолчанию.
- Проверяет наличие сообщения об ошибке.
+ Проверяет наличие сообщения об ошибке. Можно передать свои данные
+ или использовать значения по умолчанию.
Args:
- username: Неверный логин пользователя. По умолчанию "someuser".
- password: Неверный пароль пользователя. По умолчанию "password".
+ username: Неверный логин. По умолчанию "someuser".
+ password: Неверный пароль. По умолчанию "password".
"""
+
self.open("")
self.login_input.clear()
diff --git a/pages/main_page.py b/pages/main_page.py
index ec5ae82..eda1406 100644
--- a/pages/main_page.py
+++ b/pages/main_page.py
@@ -1,3 +1,9 @@
+"""Модуль главной страницы приложения.
+
+Содержит класс MainPage для работы с элементами главной страницы.
+Включает взаимодействие с панелью навигации, кнопками и карточкой пользователя.
+"""
+
from playwright.sync_api import Page
from locators.navigation_panel_locators import NavigationPanelLocators
from locators.event_panel_locators import EventPanelLocators
@@ -10,10 +16,10 @@ class MainPage(BasePage):
"""Класс для работы с главной страницей приложения.
Атрибуты:
- page (Page): Экземпляр страницы Playwright.
- navigation_panel (NavigationPanelComponent): Компонент панели навигации.
- user_button (Button): Кнопка пользователя.
- user_card (CardComponent): Карточка пользователя.
+ page: Экземпляр страницы Playwright.
+ navigation_panel: Компонент панели навигации.
+ user_button: Кнопка пользователя.
+ user_card: Карточка пользователя.
"""
def __init__(self, page: Page) -> None:
@@ -22,6 +28,7 @@ class MainPage(BasePage):
Args:
page: Экземпляр страницы Playwright.
"""
+
super().__init__(page)
self.navigation_panel = NavigationPanelComponent(page)
@@ -39,45 +46,53 @@ class MainPage(BasePage):
Args:
item_name: Название элемента для клика.
"""
+
self.navigation_panel.click_item(NavigationPanelLocators.PANEL_MAIN, item_name)
def click_configuration_navigation_panel_item(self, item_name: str) -> None:
- """Кликает по элементу подраздела 'Конфигурация' в панели навигации.
+ """Кликает по элементу подраздела 'Конфигурация'.
Args:
item_name: Название элемента для клика.
"""
+
self.navigation_panel.click_sub_item(NavigationPanelLocators.PANEL_MAIN, 1, item_name)
def click_maintenance_navigation_panel_item(self, item_name: str) -> None:
- """Кликает по элементу подраздела 'Обслуживание' в панели навигации.
+ """Кликает по элементу подраздела 'Обслуживание'.
Args:
item_name: Название элемента для клика.
"""
+
self.navigation_panel.click_sub_item(NavigationPanelLocators.PANEL_MAIN, 2, item_name)
def click_user_button(self) -> None:
"""Кликает по кнопке пользователя."""
+
self.user_button.click()
def do_logout(self) -> None:
"""Выполняет выход из системы."""
+
self.should_be_user_button()
self.click_user_button()
self.user_card.click_logout_button()
def scroll_navigation_panel_up(self) -> None:
"""Прокручивает панель навигации вверх."""
+
self.navigation_panel.scroll_up(NavigationPanelLocators.PANEL_SCROLL_CONTAINER)
def scroll_navigation_panel_down(self) -> None:
"""Прокручивает панель навигации вниз."""
+
self.navigation_panel.scroll_down(NavigationPanelLocators.PANEL_SCROLL_CONTAINER)
# Проверки:
def should_be_navigation_panel(self) -> None:
"""Проверяет наличие панели навигации."""
+
self.navigation_panel.check_presence(
NavigationPanelLocators.PANEL_MAIN,
"Navigation panel is missing"
@@ -85,14 +100,16 @@ class MainPage(BasePage):
def should_be_user_button(self) -> None:
"""Проверяет наличие кнопки пользователя."""
+
self.user_button.check_presence("User button is missing on event panel")
def check_navigation_panel_verticall_scrolling(self) -> bool:
- """Проверяет возможность вертикальной прокрутки панели навигации.
+ """Проверяет возможность вертикальной прокрутки панели.
Returns:
- bool: True если панель можно прокручивать, иначе False.
+ bool: True если прокрутка возможна, иначе False.
"""
+
return self.navigation_panel.is_scrollable_vertically(
NavigationPanelLocators.PANEL_SCROLL_CONTAINER
)
@@ -103,6 +120,7 @@ class MainPage(BasePage):
Args:
item_name: Название элемента для проверки.
"""
+
self.navigation_panel.check_item_visibility(
NavigationPanelLocators.PANEL_MAIN,
item_name
diff --git a/pages/service_status_tab.py b/pages/service_status_tab.py
index 08650dc..bcf9bca 100644
--- a/pages/service_status_tab.py
+++ b/pages/service_status_tab.py
@@ -1,3 +1,9 @@
+"""Модуль вкладки 'Статус обслуживания'.
+
+Содержит класс ServiceStatusTab для работы с таблицей сервисов.
+Позволяет проверять состояние и взаимодействовать с элементами вкладки.
+"""
+
from playwright.sync_api import Page
from locators.table_locators import TableLocators
from components.toolbar_component import ToolbarComponent
@@ -8,21 +14,23 @@ from pages.base_page import BasePage
class ServiceStatusTab(BasePage):
"""Класс для работы с вкладкой 'Статус обслуживания'.
- Предоставляет методы для взаимодействия с таблицей сервисов и проверки её состояния.
+ Предоставляет методы для взаимодействия с таблицей сервисов и проверки
+ её состояния.
Args:
- page (Page): Экземпляр страницы Playwright.
+ page: Экземпляр страницы Playwright.
"""
def __init__(self, page: Page) -> None:
- """Инициализация компонентов вкладки 'Статус обслуживания'."""
+ """Инициализирует компоненты вкладки 'Статус обслуживания'."""
+
super().__init__(page)
self.toolbar = ToolbarComponent(page, "Статус обслуживания")
self.services_table = TableComponent(page)
def get_rows_count(self) -> int:
- """Возвращает количество строк в таблице сервисов (без учёта заголовка).
+ """Возвращает количество строк в таблице (без заголовка).
Returns:
int: Количество строк с данными.
@@ -30,6 +38,7 @@ class ServiceStatusTab(BasePage):
Raises:
AssertionError: Если таблица пуста.
"""
+
table_content = self.services_table.read(TableLocators.TABLE_WORK_AREA)
rows_count = len(table_content)
@@ -40,23 +49,26 @@ class ServiceStatusTab(BasePage):
def scroll_services_table_up(self) -> None:
"""Прокручивает таблицу сервисов вверх."""
+
self.services_table.scroll_up(TableLocators.TABLE_SCROLL_CONTAINER)
def scroll_services_table_down(self) -> None:
"""Прокручивает таблицу сервисов вниз."""
+
self.services_table.scroll_down(TableLocators.TABLE_SCROLL_CONTAINER)
def check_services_table_content(self) -> None:
"""Проверяет содержимое таблицы сервисов.
- Проверяет:
- - Наличие заголовков таблицы
- - Соответствие заголовков ожидаемым значениям
- - Наличие хотя бы одной строки с данными
+ Проверяет заголовки и наличие данных в таблице.
+
+
+
Raises:
- AssertionError: Если таблица пуста или заголовки не соответствуют ожидаемым.
+ AssertionError: Если таблица пуста или заголовки неверны.
"""
+
expected_headers = [
'Контейнер',
'Время создания',
@@ -88,6 +100,7 @@ class ServiceStatusTab(BasePage):
Returns:
bool: True если прокрутка возможна, иначе False.
"""
+
return self.services_table.is_scrollable_vertically(
TableLocators.TABLE_SCROLL_CONTAINER
)
@@ -96,27 +109,30 @@ class ServiceStatusTab(BasePage):
"""Проверяет видимость первой строки таблицы.
Raises:
- AssertionError: Если первая строка не видна.
+ AssertionError: Если строка не видна.
"""
+
self.services_table.check_first_row_visibility(TableLocators.TABLE_WORK_AREA)
def check_services_table_last_row_visibility(self) -> None:
"""Проверяет видимость последней строки таблицы.
Raises:
- AssertionError: Если последняя строка не видна.
+ AssertionError: Если строка не видна.
"""
+
self.services_table.check_last_row_visibility(TableLocators.TABLE_WORK_AREA)
def check_services_table_row_highlighting(self, row_index: int) -> None:
"""Проверяет выделение указанной строки таблицы.
Args:
- row_index (int): Индекс проверяемой строки.
+ row_index: Индекс проверяемой строки.
Raises:
AssertionError: Если строка не выделена.
"""
+
self.services_table.check_row_highlighting(
TableLocators.TABLE_WORK_AREA,
row_index
@@ -128,6 +144,7 @@ class ServiceStatusTab(BasePage):
Raises:
AssertionError: Если тулбар отсутствует.
"""
+
self.toolbar.check_toolbar_presence("Toolbar is missing")
def should_be_services_table(self) -> None:
@@ -136,6 +153,7 @@ class ServiceStatusTab(BasePage):
Raises:
AssertionError: Если таблица отсутствует.
"""
+
self.services_table.check_presence(
TableLocators.TABLE_WORK_AREA,
"Service statuses table is missing"
diff --git a/pages/session_tab.py b/pages/session_tab.py
index c10e9e2..85e7794 100644
--- a/pages/session_tab.py
+++ b/pages/session_tab.py
@@ -1,3 +1,9 @@
+"""Модуль вкладки 'Сессия'.
+
+Содержит класс SessionsTab для работы с таблицей сессий.
+Позволяет проверять состояние и взаимодействовать с элементами вкладки.
+"""
+
from playwright.sync_api import Page, Locator
from locators.table_locators import TableLocators
from locators.button_locators import ButtonLocators
@@ -10,21 +16,23 @@ from pages.base_page import BasePage
class SessionsTab(BasePage):
"""Класс для работы с вкладкой 'Сессия'.
- Предоставляет методы для взаимодействия с таблицей сессий и проверки её состояния.
+ Предоставляет методы для взаимодействия с таблицей сессий и проверки
+ её состояния.
Args:
- page (Page): Экземпляр страницы Playwright.
+ page: Экземпляр страницы Playwright.
"""
def __init__(self, page: Page) -> None:
- """Инициализация компонентов вкладки 'Сессия'."""
+ """Инициализирует компоненты вкладки 'Сессия'."""
+
super().__init__(page)
self.toolbar = ToolbarComponent(page, "Сессия")
self.sessions_table = TableComponent(page)
def get_rows_count(self) -> int:
- """Возвращает количество строк в таблице сессий (без учёта заголовка).
+ """Возвращает количество строк в таблице (без заголовка).
Returns:
int: Количество строк с данными.
@@ -32,6 +40,7 @@ class SessionsTab(BasePage):
Raises:
AssertionError: Если таблица пуста.
"""
+
table_content = self.sessions_table.read(TableLocators.TABLE_WORK_AREA)
rows_count = len(table_content)
@@ -44,14 +53,15 @@ class SessionsTab(BasePage):
"""Возвращает кнопку удаления сессии для указанной строки.
Args:
- row_index (int): Индекс строки в таблице
+ row_index: Индекс строки в таблице.
Returns:
- TooltipButton: Экземпляр кнопки с подсказкой
+ TooltipButton: Кнопка с подсказкой.
Raises:
AssertionError: Если строка не найдена.
"""
+
row_locator = self.sessions_table.get_row_locator(
TableLocators.TABLE_WORK_AREA,
row_index
@@ -63,21 +73,24 @@ class SessionsTab(BasePage):
def scroll_sessions_table_up(self) -> None:
"""Прокручивает таблицу сессий вверх."""
+
self.sessions_table.scroll_up(TableLocators.TABLE_SCROLL_CONTAINER)
def scroll_sessions_table_down(self) -> None:
"""Прокручивает таблицу сессий вниз."""
+
self.sessions_table.scroll_down(TableLocators.TABLE_SCROLL_CONTAINER)
def check_sessions_table_content(self, verify: bool = False) -> None:
"""Проверяет содержимое таблицы сессий.
Args:
- verify (bool, optional): Проверять соответствие данных из БД. По умолчанию False.
+ verify: Проверять соответствие данных из БД. По умолчанию False.
Raises:
- AssertionError: Если таблица пуста или заголовки не соответствуют.
+ AssertionError: Если таблица пуста или заголовки неверны.
"""
+
expected_headers = [
'ID сессии',
'ID пользователя',
@@ -115,6 +128,7 @@ class SessionsTab(BasePage):
Returns:
bool: True если прокрутка возможна, иначе False.
"""
+
return self.sessions_table.is_scrollable_vertically(
TableLocators.TABLE_SCROLL_CONTAINER
)
@@ -123,27 +137,30 @@ class SessionsTab(BasePage):
"""Проверяет видимость первой строки таблицы.
Raises:
- AssertionError: Если первая строка не видна.
+ AssertionError: Если строка не видна.
"""
+
self.sessions_table.check_first_row_visibility(TableLocators.TABLE_WORK_AREA)
def check_sessions_table_last_row_visibility(self) -> None:
"""Проверяет видимость последней строки таблицы.
Raises:
- AssertionError: Если последняя строка не видна.
+ AssertionError: Если строка не видна.
"""
+
self.sessions_table.check_last_row_visibility(TableLocators.TABLE_WORK_AREA)
def check_sessions_table_row_highlighting(self, row_index: int) -> None:
"""Проверяет выделение указанной строки таблицы.
Args:
- row_index (int): Индекс проверяемой строки.
+ row_index: Индекс проверяемой строки.
Raises:
AssertionError: Если строка не выделена.
"""
+
self.sessions_table.check_row_highlighting(
TableLocators.TABLE_WORK_AREA,
row_index
@@ -155,6 +172,7 @@ class SessionsTab(BasePage):
Raises:
AssertionError: Если тулбар отсутствует.
"""
+
self.toolbar.check_toolbar_presence("Toolbar is missing")
def should_be_sessions_table(self) -> None:
@@ -163,6 +181,7 @@ class SessionsTab(BasePage):
Raises:
AssertionError: Если таблица отсутствует.
"""
+
self.sessions_table.check_presence(
TableLocators.TABLE_WORK_AREA,
"Sessions table is missing"
@@ -176,12 +195,13 @@ class SessionsTab(BasePage):
"""Проверяет наличие кнопки удаления в строке таблицы.
Args:
- row_index (int): Индекс проверяемой строки
- tooltip (str): Ожидаемый текст подсказки
+ row_index: Индекс проверяемой строки.
+ tooltip: Ожидаемый текст подсказки.
Raises:
- AssertionError: Если кнопка отсутствует или подсказка не соответствует.
+ AssertionError: Если кнопка отсутствует или подсказка неверна.
"""
+
delete_button = self.get_delete_session_button_from_row(row_index)
delete_button.check_presence(
f"Delete session button is missing on {row_index} row"
@@ -192,11 +212,12 @@ class SessionsTab(BasePage):
"""Сверяет данные таблицы с данными из БД.
Args:
- sessions_table (list): Данные из таблицы на странице
+ sessions_table: Данные из таблицы на странице.
Raises:
AssertionError: Если данные не соответствуют.
"""
+
expected_sessions_list = []
# Отправка запроса к бэкенду для получения информации о сессиях
diff --git a/pages/users_tab.py b/pages/users_tab.py
index 7d688da..2fc0dae 100644
--- a/pages/users_tab.py
+++ b/pages/users_tab.py
@@ -1,3 +1,9 @@
+"""Модуль вкладки 'Пользователи'.
+
+Содержит класс UsersTab для работы с таблицей пользователей.
+Позволяет управлять пользователями через модальные окна и проверять их состояние.
+"""
+
import re
from playwright.sync_api import Page
from modal_windows.modal_edit_user import EditUserModalWindow
@@ -13,14 +19,15 @@ class UsersTab(BasePage):
"""Класс для работы с вкладкой 'Пользователи'.
Предоставляет методы для взаимодействия с таблицей пользователей,
- модальными окнами добавления/редактирования и проверки состояния элементов.
+ модальными окнами и проверки состояния элементов.
Args:
- page (Page): Экземпляр страницы Playwright.
+ page: Экземпляр страницы Playwright.
"""
def __init__(self, page: Page) -> None:
- """Инициализация компонентов вкладки 'Пользователи'."""
+ """Инициализирует компоненты вкладки 'Пользователи'."""
+
super().__init__(page)
locator_button_1 = self.page.get_by_role("navigation").filter(
@@ -40,15 +47,16 @@ class UsersTab(BasePage):
self.success_alert = AlertComponent(page, "success")
def add_modal_window(self, window_type: str, title: str) -> None:
- """Добавляет модальное окно в коллекцию окон.
+ """Добавляет модальное окно в коллекцию.
Args:
- window_type (str): Тип окна ('add_user' или 'edit_user')
- title (str): Заголовок окна (имя пользователя для редактирования)
+ window_type: Тип окна ('add_user' или 'edit_user').
+ title: Заголовок окна.
Raises:
- AssertionError: Если указан неподдерживаемый тип окна.
+ AssertionError: Если тип окна не поддерживается.
"""
+
if window_type == "add_user":
self.modal_windows["add_user"] = AddUserModalWindow(self.page)
elif window_type == "edit_user":
@@ -60,14 +68,15 @@ class UsersTab(BasePage):
"""Возвращает модальное окно по заголовку.
Args:
- title (str): Заголовок окна
+ title: Заголовок окна.
Returns:
- ModalWindowComponent: Экземпляр модального окна
+ ModalWindowComponent: Экземпляр модального окна.
Raises:
AssertionError: Если окно не найдено.
"""
+
modal_window = self.modal_windows.get(title)
if modal_window is None:
assert False, f"Modal window with title '{title}' not found"
@@ -77,11 +86,12 @@ class UsersTab(BasePage):
"""Удаляет модальное окно из коллекции.
Args:
- title (str): Заголовок окна
+ title: Заголовок окна.
Raises:
AssertionError: Если окно не найдено.
"""
+
if self.modal_windows.get(title) is None:
assert False, f"Modal window with title '{title}' not found"
self.modal_windows[title] = None
@@ -90,8 +100,9 @@ class UsersTab(BasePage):
"""Закрывает модальное окно через кнопку в тулбаре.
Args:
- title (str): Заголовок окна
+ title: Заголовок окна.
"""
+
modal_window = self.get_modal_window(title)
modal_window.close_window_by_toolbar_button()
self.delete_modal_window(title)
@@ -100,45 +111,51 @@ class UsersTab(BasePage):
"""Закрывает модальное окно через кнопку закрытия.
Args:
- title (str): Заголовок окна
+ title: Заголовок окна.
"""
+
modal_window = self.get_modal_window(title)
modal_window.close_window()
self.delete_modal_window(title)
def close_add_user_window_by_toolbar_button(self) -> None:
- """Закрывает окно добавления пользователя через кнопку в тулбаре."""
+ """Закрывает окно добавления пользователя через тулбар."""
+
self.close_modal_window_by_toolbar_button("add_user")
def close_add_user_window(self) -> None:
"""Закрывает окно добавления пользователя."""
+
self.close_modal_window("add_user")
def close_edit_user_window_by_toolbar_button(self, title: str) -> None:
- """Закрывает окно редактирования пользователя через кнопку в тулбаре.
+ """Закрывает окно редактирования через кнопку в тулбаре.
Args:
- title (str): Имя пользователя (заголовок окна)
+ title: Имя пользователя (заголовок окна).
"""
+
self.close_modal_window_by_toolbar_button(title)
def close_edit_user_window(self, title: str) -> None:
"""Закрывает окно редактирования пользователя.
Args:
- title (str): Имя пользователя (заголовок окна)
+ title: Имя пользователя (заголовок окна).
"""
+
self.close_modal_window(title)
def add_new_user(self, user_data: dict) -> None:
"""Добавляет нового пользователя.
Args:
- user_data (dict): Данные пользователя
+ user_data: Данные пользователя.
Raises:
- AssertionError: Если не отображается сообщение об успешном добавлении.
+ AssertionError: Если нет сообщения об успешном добавлении.
"""
+
self.get_modal_window("add_user").new_user(user_data)
self.success_alert.check_alert_presence(' Новый пользователь \n успешно добавлен! ')
self.success_alert.check_alert_absence(' Новый пользователь \n успешно добавлен! ')
@@ -147,11 +164,12 @@ class UsersTab(BasePage):
"""Удаляет пользователя.
Args:
- user_name (str): Имя пользователя
+ user_name: Имя пользователя.
Raises:
- AssertionError: Если не отображается сообщение об успешном удалении.
+ AssertionError: Если нет сообщения об успешном удалении.
"""
+
self.get_modal_window(user_name).delete_user()
self.success_alert.check_alert_presence('\nПользователь удалён\n')
self.success_alert.check_alert_absence('\nПользователь удалён\n')
@@ -160,12 +178,13 @@ class UsersTab(BasePage):
"""Редактирует данные пользователя.
Args:
- user_name (str): Имя пользователя
- user_data (dict): Новые данные пользователя
+ user_name: Имя пользователя.
+ user_data: Новые данные пользователя.
Raises:
- AssertionError: Если не отображается сообщение об успешном обновлении.
+ AssertionError: Если нет сообщения об успешном обновлении.
"""
+
self.get_modal_window(user_name).edit_user(user_data)
self.success_alert.check_alert_presence('\nОбновление успешно\n')
self.success_alert.check_alert_absence('\nОбновление успешно\n')
@@ -174,11 +193,12 @@ class UsersTab(BasePage):
"""Сбрасывает пароль пользователя.
Args:
- user_name (str): Имя пользователя
+ user_name: Имя пользователя.
Returns:
- str: Новый пароль (если получен)
+ str: Новый пароль (если получен).
"""
+
new_password = ""
self.get_modal_window(user_name).reset_password()
@@ -193,15 +213,16 @@ class UsersTab(BasePage):
"""Ищет пользователя в таблице.
Args:
- name (str): Имя пользователя
- role (str): Роль пользователя
+ name: Имя пользователя.
+ role: Роль пользователя.
Returns:
- int: Индекс строки или -1 если не найден
+ int: Индекс строки или -1 если не найден.
Raises:
AssertionError: Если таблица пуста.
"""
+
table_content = self.users_table.read(TableLocators.TABLE_WORK_AREA)
if len(table_content) == 0:
assert False, "The contents of the table are missing"
@@ -219,6 +240,7 @@ class UsersTab(BasePage):
Raises:
AssertionError: Если кнопки недоступны или окно не открылось.
"""
+
if self.toolbar.is_button_not_present("close"):
self.toolbar.check_button_presence("edit")
self.toolbar.click_button("edit")
@@ -232,14 +254,15 @@ class UsersTab(BasePage):
"""Открывает окно редактирования по индексу строки.
Args:
- row_index (int): Индекс строки в таблице
+ row_index: Индекс строки в таблице.
Returns:
- tuple: (имя пользователя, роль)
+ tuple: (имя пользователя, роль).
Raises:
AssertionError: Если таблица пуста или индекс вне диапазона.
"""
+
tmp_dict = {"admin": "Администратор", "manager": "Контактное лицо", "operator": "Оператор"}
table_content = self.users_table.read(TableLocators.TABLE_WORK_AREA)
@@ -265,15 +288,16 @@ class UsersTab(BasePage):
return user_name, role
def open_edit_user_page_by_user(self, user_name: str, role: str) -> None:
- """Открывает окно редактирования по имени пользователя и роли.
+ """Открывает окно редактирования по имени и роли.
Args:
- user_name (str): Имя пользователя
- role (str): Роль пользователя
+ user_name: Имя пользователя.
+ role: Роль пользователя.
Raises:
AssertionError: Если пользователь не найден.
"""
+
row_index = self.find_user_in_table(user_name, role)
if row_index == -1:
assert False, f"User with name {user_name} and role {role} has not been found"
@@ -286,11 +310,12 @@ class UsersTab(BasePage):
"""Проверяет содержимое таблицы пользователей.
Args:
- verify (bool, optional): Проверять соответствие данных из БД. По умолчанию False.
+ verify: Проверять соответствие данных из БД. По умолчанию False.
Raises:
- AssertionError: Если таблица пуста или заголовки не соответствуют.
+ AssertionError: Если таблица пуста или заголовки неверны.
"""
+
expected_headers = ['Имя пользователя', 'Тип авторизации', 'Роль', 'E-mail', 'Номер для СМС']
table_content = self.users_table.read(TableLocators.TABLE_WORK_AREA)
@@ -312,15 +337,17 @@ class UsersTab(BasePage):
def check_add_user_window_content(self) -> None:
"""Проверяет содержимое окна добавления пользователя."""
+
self.get_modal_window("add_user").check_content()
def check_edit_user_window_content(self, user_name: str, role: str) -> None:
- """Проверяет содержимое окна редактирования пользователя.
+ """Проверяет содержимое окна редактирования.
Args:
- user_name (str): Имя пользователя
- role (str): Роль пользователя
+ user_name: Имя пользователя.
+ role: Роль пользователя.
"""
+
edit_user_window = self.get_modal_window(user_name)
edit_user_window.check_content(user_name, role)
@@ -330,6 +357,7 @@ class UsersTab(BasePage):
Raises:
AssertionError: Если тулбар или кнопка редактирования отсутствуют.
"""
+
self.toolbar.check_toolbar_presence("Toolbar is missing")
self.toolbar.check_button_presence("edit")
@@ -337,8 +365,9 @@ class UsersTab(BasePage):
"""Проверяет наличие и функциональность кнопок тулбара.
Raises:
- AssertionError: Если кнопки недоступны или имеют некорректные подсказки.
+ AssertionError: Если кнопки недоступны или подсказки неверны.
"""
+
self.toolbar.check_button_presence("edit")
self.toolbar.check_button_tooltip("edit", "Редактировать")
@@ -357,6 +386,7 @@ class UsersTab(BasePage):
Raises:
AssertionError: Если таблица отсутствует.
"""
+
self.users_table.check_presence(
TableLocators.TABLE_WORK_AREA,
"Users table is missing"
@@ -366,12 +396,13 @@ class UsersTab(BasePage):
"""Проверяет наличие пользователя в таблице.
Args:
- name (str): Имя пользователя
- role (str): Роль пользователя
+ name: Имя пользователя.
+ role: Роль пользователя.
Raises:
AssertionError: Если пользователь не найден.
"""
+
found = self.find_user_in_table(name, role)
if found == -1:
assert False, f"User with name {name} and role {role} has not been found"
@@ -380,12 +411,13 @@ class UsersTab(BasePage):
"""Проверяет отсутствие пользователя в таблице.
Args:
- name (str): Имя пользователя
- role (str): Роль пользователя
+ name: Имя пользователя.
+ role: Роль пользователя.
Raises:
AssertionError: Если пользователь найден.
"""
+
found = self.find_user_in_table(name, role)
if found != -1:
assert False, f"User with name {name} and role {role} has been found"
@@ -394,11 +426,12 @@ class UsersTab(BasePage):
"""Сверяет данные таблицы с данными из БД.
Args:
- users_table (list): Данные из таблицы на странице
+ users_table: Данные из таблицы на странице.
Raises:
AssertionError: Если данные не соответствуют.
"""
+
expected_users_list = []
tmp_dict = {"admin": "Администратор", "manager": "Контактное лицо", "operator": "Оператор"}
diff --git a/site/components/alert_component/index.html b/site/components/alert_component/index.html
index ca63575..a2dcc42 100644
--- a/site/components/alert_component/index.html
+++ b/site/components/alert_component/index.html
@@ -492,18 +492,18 @@
-
+
- check_absence
+ check_alert_absence
-
+
- check_presence
+ check_alert_presence
@@ -1739,18 +1739,18 @@
-
+
- check_absence
+ check_alert_absence
-
+
- check_presence
+ check_alert_presence
@@ -1804,6 +1804,10 @@
+
Модуль для работы с компонентом alert-окна в Playwright.
+
Содержит класс AlertComponent для взаимодействия с различными типами
+alert-окон (error, success, info, warning) и проверки их состояния.
+
@@ -1837,17 +1841,11 @@
Bases:
BaseComponent
-
Компонент для работы с alert-окнами.
-
Поддерживает различные типы alert-окон: error, success, info, warning.
+
Компонент для работы с alert-окнами Playwright.
+
Поддерживает типы: error, success, info, warning.
+Позволяет проверять наличие, отсутствие и текст сообщений.
-
- Атрибуты
- page: экземпляр страницы Playwright
-alert_type: тип alert-окна (error/success/info/warning)
-text: текстовый элемент сообщения alert-окна
-
-
@@ -1855,11 +1853,7 @@ text: текстовый элемент сообщения alert-окна
Source code in components\alert_component.py
- 11
-12
-13
-14
-15
+ 15
16
17
18
@@ -1933,27 +1927,29 @@ text: текстовый элемент сообщения alert-окна
86
87
88
-89 | class AlertComponent(BaseComponent):
- """Компонент для работы с alert-окнами.
+89
+90
+91
+92
+93
+94
| class AlertComponent(BaseComponent):
+ """Компонент для работы с alert-окнами Playwright.
- Поддерживает различные типы alert-окон: error, success, info, warning.
-
- Атрибуты:
- page: экземпляр страницы Playwright
- alert_type: тип alert-окна (error/success/info/warning)
- text: текстовый элемент сообщения alert-окна
+ Поддерживает типы: error, success, info, warning.
+ Позволяет проверять наличие, отсутствие и текст сообщений.
"""
def __init__(self, page: Page, alert_type: str):
- """Инициализация компонента alert-окна.
+ """Инициализирует компонент alert-окна.
Args:
- page: экземпляр страницы Playwright
- alert_type: тип alert-окна (error/success/info/warning)
+ page: Экземпляр страницы Playwright.
+ alert_type: Тип alert-окна (error/success/info/warning).
Raises:
- ValueError: если передан неподдерживаемый тип alert-окна
+ ValueError: Если передан неподдерживаемый тип alert-окна.
"""
+
super().__init__(page)
alert_types = ["error", "success", "info", "warning"]
@@ -1961,57 +1957,61 @@ text: текстовый элемент сообщения alert-окна
raise ValueError("Unsupported type of alert window")
self.alert_type = alert_type
- self.text = Text(page, f"//div[@class='v-alert {self.alert_type}']/div", "Alert message")
+ self.text = Text(page, f"//div[@class='v-alert {self.alert_type}']/div", "Alert message")
- # Действия:
- def get_text(self):
- """Получение текста сообщения из alert-окна.
+ def get_text(self) -> str:
+ """Возвращает текст сообщения из alert-окна.
Returns:
- str: текст сообщения alert-окна
+ str: Текст сообщения.
"""
+
return self.text.get_text(0)
- # Проверки:
- def check_presence(self, text):
- """Проверка наличия alert-окна с заданным текстом.
+ def check_alert_presence(self, text: str):
+ """Проверяет наличие alert-окна с заданным текстом.
Args:
- text: текст для проверки (если пустая строка - проверяется только наличие окна)
+ text: Текст для проверки. Если пустая строка - проверяет только
+ наличие окна.
Raises:
- AssertionError: если alert-окно не найдено
+ AssertionError: Если alert-окно не найдено.
"""
+
msg = f"No {self.alert_type} alert window on page"
if text == "":
expect(self.page.get_by_role("alert")).to_be_visible(), msg
else:
expect(self.page.get_by_role("alert").filter(has_text=text)).to_be_visible(), msg
- def check_absence(self, text, timeout=30000):
- """Проверка отсутствия alert-окна с заданным текстом.
+ def check_alert_absence(self, text: str, timeout: int = 30000):
+ """Проверяет отсутствие alert-окна с заданным текстом.
Args:
- text: текст для проверки
- timeout: время ожидания исчезновения (в миллисекундах)
+ text: Текст для проверки.
+ timeout: Время ожидания исчезновения (мс).
Raises:
- AssertionError: если alert-окно не исчезает в течение заданного времени
+ AssertionError: Если окно не исчезает в течение заданного времени.
"""
+
seconds = int(timeout/1000)
- msg = f"Alert {self.alert_type} window should disappear after {seconds} seconds"
+ msg = f"Alert {self.alert_type} window should disappear after {seconds} seconds"
expect(self.page.get_by_role("alert").filter(has_text=text)).to_be_hidden(timeout=timeout), msg
- def check_text(self, alert_text):
- """Проверка точного соответствия текста в alert-окне.
+ def check_text(self, alert_text: str):
+ """Проверяет точное соответствие текста в alert-окне.
Args:
- alert_text: ожидаемый текст сообщения
+ alert_text: Ожидаемый текст сообщения.
Raises:
- AssertionError: если текст не соответствует ожидаемому
+ AssertionError: Если текст не соответствует ожидаемому.
"""
- self.text.check_have_text(alert_text, f"Unexpected message in alert {self.alert_type} window")
+
+ self.text.check_have_text(alert_text,
+ f"Unexpected message in alert {self.alert_type} window")
|
@@ -2038,7 +2038,7 @@ text: текстовый элемент сообщения alert-окна
- Инициализация компонента alert-окна.
+ Инициализирует компонент alert-окна.
Parameters:
@@ -2061,7 +2061,7 @@ text: текстовый элемент сообщения alert-окна
|
- экземпляр страницы Playwright
+ Экземпляр страницы Playwright.
|
@@ -2077,7 +2077,7 @@ text: текстовый элемент сообщения alert-окна
|
- тип alert-окна (error/success/info/warning)
+ Тип alert-окна (error/success/info/warning).
|
@@ -2103,7 +2103,7 @@ text: текстовый элемент сообщения alert-окна
|
- если передан неподдерживаемый тип alert-окна
+ Если передан неподдерживаемый тип alert-окна.
|
@@ -2130,16 +2130,18 @@ text: текстовый элемент сообщения alert-окна
36
37
38
-39def __init__(self, page: Page, alert_type: str):
- """Инициализация компонента alert-окна.
+39
+40
| def __init__(self, page: Page, alert_type: str):
+ """Инициализирует компонент alert-окна.
Args:
- page: экземпляр страницы Playwright
- alert_type: тип alert-окна (error/success/info/warning)
+ page: Экземпляр страницы Playwright.
+ alert_type: Тип alert-окна (error/success/info/warning).
Raises:
- ValueError: если передан неподдерживаемый тип alert-окна
+ ValueError: Если передан неподдерживаемый тип alert-окна.
"""
+
super().__init__(page)
alert_types = ["error", "success", "info", "warning"]
@@ -2147,7 +2149,7 @@ text: текстовый элемент сообщения alert-окна
raise ValueError("Unsupported type of alert window")
self.alert_type = alert_type
- self.text = Text(page, f"//div[@class='v-alert {self.alert_type}']/div", "Alert message")
+ self.text = Text(page, f"//div[@class='v-alert {self.alert_type}']/div", "Alert message")
|
@@ -2157,15 +2159,15 @@ text: текстовый элемент сообщения alert-окна