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 -
    @@ -2130,16 +2130,18 @@ text: текстовый элемент сообщения alert-окна

    363738 -39
    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-окна.

    def __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-окна

    -

    - check_absence(text, timeout=30000) +

    + check_alert_absence(text, timeout=30000)

    -

    Проверка отсутствия alert-окна с заданным текстом.

    +

    Проверяет отсутствие alert-окна с заданным текстом.

    Parameters:

    @@ -2184,10 +2186,11 @@ text: текстовый элемент сообщения alert-окна

    text + str
    -

    текст для проверки

    +

    Текст для проверки.

    @@ -2199,10 +2202,11 @@ text: текстовый элемент сообщения alert-окна

    timeout + int
    -

    время ожидания исчезновения (в миллисекундах)

    +

    Время ожидания исчезновения (мс).

    @@ -2228,7 +2232,7 @@ text: текстовый элемент сообщения alert-окна

    -

    если alert-окно не исчезает в течение заданного времени

    +

    Если окно не исчезает в течение заданного времени.

    @@ -2238,9 +2242,7 @@ text: текстовый элемент сообщения alert-окна

    Source code in components\alert_component.py -
    @@ -2351,15 +2359,19 @@ text: текстовый элемент сообщения alert-окна

    616263 -64 @@ -2440,25 +2453,29 @@ text: текстовый элемент сообщения alert-окна

    Source code in components\alert_component.py -
    66
    -67
    -68
    +              
    68
     69
     70
     71
    @@ -2250,18 +2252,22 @@ text: текстовый элемент сообщения alert-окна

    75 76 77 -78
    def check_absence(self, text, timeout=30000):
    -    """Проверка отсутствия alert-окна с заданным текстом.
    +78
    +79
    +80
    +81
    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
     
    @@ -2272,15 +2278,15 @@ text: текстовый элемент сообщения alert-окна

    -

    - check_presence(text) +

    + check_alert_presence(text)

    -

    Проверка наличия alert-окна с заданным текстом.

    +

    Проверяет наличие alert-окна с заданным текстом.

    Parameters:

    @@ -2299,10 +2305,12 @@ text: текстовый элемент сообщения alert-окна

    text
    + str
    -

    текст для проверки (если пустая строка - проверяется только наличие окна)

    +

    Текст для проверки. Если пустая строка - проверяет только + наличие окна.

    @@ -2328,7 +2336,7 @@ text: текстовый элемент сообщения alert-окна

    -

    если alert-окно не найдено

    +

    Если alert-окно не найдено.

    def check_presence(self, text):
    -    """Проверка наличия alert-окна с заданным текстом.
    +64
    +65
    +66
    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
    @@ -2382,7 +2394,7 @@ text: текстовый элемент сообщения alert-окна

    -

    Проверка точного соответствия текста в alert-окне.

    +

    Проверяет точное соответствие текста в alert-окне.

    Parameters:

    @@ -2401,10 +2413,11 @@ text: текстовый элемент сообщения alert-окна

    alert_text
    + str
    -

    ожидаемый текст сообщения

    +

    Ожидаемый текст сообщения.

    @@ -2430,7 +2443,7 @@ text: текстовый элемент сообщения alert-окна

    -

    если текст не соответствует ожидаемому

    +

    Если текст не соответствует ожидаемому.

    @@ -2509,12 +2527,14 @@ text: текстовый элемент сообщения alert-окна

    454647 -48
    80
    -81
    -82
    -83
    +              
    83
     84
     85
     86
     87
     88
    -89
    def check_text(self, alert_text):
    -    """Проверка точного соответствия текста в alert-окне.
    +89
    +90
    +91
    +92
    +93
    +94
    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")
     
    @@ -2476,7 +2493,7 @@ text: текстовый элемент сообщения alert-окна

    -

    Получение текста сообщения из alert-окна.

    +

    Возвращает текст сообщения из alert-окна.

    Returns:

    @@ -2490,10 +2507,11 @@ text: текстовый элемент сообщения alert-окна

    str + str
    -

    текст сообщения alert-окна

    +

    Текст сообщения.

    def get_text(self):
    -    """Получение текста сообщения из alert-окна.
    +48
    +49
    def get_text(self) -> str:
    +    """Возвращает текст сообщения из alert-окна.
     
         Returns:
    -        str: текст сообщения alert-окна
    +        str: Текст сообщения.
         """
    +
         return self.text.get_text(0)
     
    diff --git a/site/components/base_component/index.html b/site/components/base_component/index.html index d49ab82..794d770 100644 --- a/site/components/base_component/index.html +++ b/site/components/base_component/index.html @@ -1876,6 +1876,9 @@
    +

    Базовый модуль для работы с компонентами страницы.

    +

    Содержит базовый класс для взаимодействия с элементами страницы через Playwright.

    + @@ -1914,11 +1917,6 @@ - работа с прокруткой

    -
    - Атрибуты -

    page: экземпляр страницы Playwright

    -
    - @@ -1926,11 +1924,7 @@
    Source code in components\base_component.py -
      8
    -  9
    - 10
    - 11
    - 12
    +                
     12
      13
      14
      15
    @@ -2090,24 +2084,32 @@
     169
     170
     171
    -172
    class BaseComponent:
    +172
    +173
    +174
    +175
    +176
    +177
    +178
    +179
    +180
    +181
    +182
    class BaseComponent:
         """Базовый компонент для работы с элементами страницы.
     
         Предоставляет общие методы для взаимодействия с элементами:
         - получение локаторов
         - проверка видимости элементов
         - работа с прокруткой
    -
    -    Атрибуты:
    -        page: экземпляр страницы Playwright
         """
     
         def __init__(self, page: Page):
             """Инициализация базового компонента.
     
             Args:
    -            page: экземпляр страницы Playwright
    +            page: экземпляр страницы Playwright.
             """
    +
             self.page = page
     
         # Действия:
    @@ -2115,14 +2117,15 @@
             """Получение объекта 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):
    @@ -2141,53 +2144,57 @@
         #     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)
    @@ -2196,15 +2203,16 @@
             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)
    @@ -2213,15 +2221,16 @@
             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")
    @@ -2234,15 +2243,16 @@
             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")
    @@ -2304,7 +2314,7 @@
                 
    -

    экземпляр страницы Playwright

    +

    экземпляр страницы Playwright.

    @@ -2317,18 +2327,20 @@
    Source code in components\base_component.py -
    @@ -2420,10 +2434,7 @@
    Source code in components\base_component.py -
    20
    -21
    +              
    21
     22
     23
     24
     25
    -26
    def __init__(self, page: Page):
    +26
    +27
    +28
    def __init__(self, page: Page):
         """Инициализация базового компонента.
     
         Args:
    -        page: экземпляр страницы Playwright
    +        page: экземпляр страницы Playwright.
         """
    +
         self.page = page
     
    @@ -2366,10 +2378,11 @@ locator
    + str | Locator
    -

    локатор элемента (строка или объект Locator)

    +

    локатор элемента (строка или объект Locator).

    @@ -2381,10 +2394,11 @@ msg + str
    -

    сообщение об ошибке при неудачной проверке

    +

    сообщение об ошибке при неудачной проверке.

    @@ -2410,7 +2424,7 @@
    -

    если элемент не виден на странице

    +

    если элемент не виден на странице.

    @@ -2532,7 +2548,7 @@ @@ -2542,9 +2558,7 @@
    Source code in components\base_component.py -
    59
    -60
    -61
    -62
    +              
    62
     63
     64
     65
    @@ -2431,16 +2442,21 @@
     67
     68
     69
    -70
    def check_presence(self, locator, msg):
    +70
    +71
    +72
    +73
    +74
    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
     
    @@ -2483,7 +2499,7 @@
    -

    строка с CSS/XPath селектором или объект Locator

    +

    строка с CSS/XPath селектором или объект Locator.

    @@ -2509,7 +2525,7 @@
    -

    объект для работы с элементом

    +

    объект для работы с элементом.

    -

    если передан некорректный тип локатора

    +

    если передан некорректный тип локатора.

    29
    -30
    -31
    +              
    @@ -2652,25 +2671,27 @@
    Source code in components\base_component.py -
    31
     32
     33
     34
    @@ -2559,18 +2573,22 @@
     43
     44
     45
    -46
    def get_locator(self, locator: str | Locator) -> Locator:
    +46
    +47
    +48
    +49
    def get_locator(self, locator: str | Locator) -> Locator:
         """Получение объекта 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):
    @@ -2613,10 +2631,11 @@
                     locator
                 
    + str | Locator
    -

    локатор элемента

    +

    локатор элемента.

    @@ -2642,7 +2661,7 @@
    -

    True если элемент можно прокрутить горизонтально

    +

    True если элемент можно прокрутить горизонтально.

    @@ -2748,25 +2770,27 @@
    Source code in components\base_component.py -
    84
    -85
    -86
    -87
    -88
    -89
    -90
    -91
    -92
    -93
    -94
    def is_scrollable_horizontally(self, locator) -> bool:
    +              
     89
    + 90
    + 91
    + 92
    + 93
    + 94
    + 95
    + 96
    + 97
    + 98
    + 99
    +100
    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")
     
    @@ -2709,10 +2730,11 @@ locator
    + str | Locator
    -

    локатор элемента

    +

    локатор элемента.

    @@ -2738,7 +2760,7 @@
    -

    True если элемент можно прокрутить вертикально

    +

    True если элемент можно прокрутить вертикально.

    @@ -2844,14 +2869,7 @@
    Source code in components\base_component.py -
    72
    -73
    -74
    -75
    -76
    +              
    76
     77
     78
     79
     80
     81
    -82
    def is_scrollable_vertically(self, locator) -> bool:
    +82
    +83
    +84
    +85
    +86
    +87
    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")
     
    @@ -2805,10 +2829,11 @@ locator
    + str | Locator
    -

    локатор элемента

    +

    локатор элемента.

    @@ -2834,7 +2859,7 @@
    -

    если прокрутка не выполнена до конца

    +

    если прокрутка не выполнена до конца.

    114
    -115
    -116
    -117
    -118
    -119
    -120
    -121
    +              
    @@ -2950,15 +2978,7 @@
    Source code in components\base_component.py -
    121
     122
     123
     124
    @@ -2859,15 +2877,24 @@
     126
     127
     128
    -129
    def scroll_down(self, locator):
    +129
    +130
    +131
    +132
    +133
    +134
    +135
    +136
    +137
    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)
    @@ -2911,10 +2938,11 @@
                     locator
                 
    + str | Locator
    -

    локатор элемента

    +

    локатор элемента.

    @@ -2940,7 +2968,7 @@
    -

    если прокрутка не выполнена до конца

    +

    если прокрутка не выполнена до конца.

    131
    -132
    -133
    -134
    -135
    -136
    -137
    -138
    -139
    +              
    @@ -3064,16 +3095,7 @@
    Source code in components\base_component.py -
    139
     140
     141
     142
    @@ -2969,15 +2989,25 @@
     147
     148
     149
    -150
    def scroll_left(self, locator):
    +150
    +151
    +152
    +153
    +154
    +155
    +156
    +157
    +158
    +159
    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")
    @@ -3025,10 +3055,11 @@
                     locator
                 
    + str | Locator
    -

    локатор элемента

    +

    локатор элемента.

    @@ -3054,7 +3085,7 @@
    -

    если прокрутка не выполнена до конца

    +

    если прокрутка не выполнена до конца.

    152
    -153
    -154
    -155
    -156
    -157
    -158
    -159
    -160
    -161
    +              
    @@ -3180,13 +3214,7 @@
    Source code in components\base_component.py -
    161
     162
     163
     164
    @@ -3084,15 +3106,26 @@
     169
     170
     171
    -172
    def scroll_right(self, locator):
    +172
    +173
    +174
    +175
    +176
    +177
    +178
    +179
    +180
    +181
    +182
    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")
    @@ -3141,10 +3174,11 @@
                     locator
                 
    + str | Locator
    -

    локатор элемента

    +

    локатор элемента.

    @@ -3170,7 +3204,7 @@
    -

    если прокрутка не выполнена до конца

    +

    если прокрутка не выполнена до конца.

     97
    - 98
    - 99
    -100
    -101
    -102
    -103
    +              
    103
     104
     105
     106
    @@ -3195,15 +3223,23 @@
     109
     110
     111
    -112
    def scroll_up(self, locator):
    +112
    +113
    +114
    +115
    +116
    +117
    +118
    +119
    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)
    diff --git a/site/components/card_component/index.html b/site/components/card_component/index.html
    index 5a8a79a..49d240b 100644
    --- a/site/components/card_component/index.html
    +++ b/site/components/card_component/index.html
    @@ -1750,6 +1750,9 @@
     
         
    +

    Модуль компонента карточки пользователя.

    +

    Содержит класс для работы с карточкой пользователя через Playwright.

    + @@ -1784,15 +1787,9 @@

    Компонент карточки пользователя.

    -

    Предоставляет методы для взаимодействия с элементами карточки пользователя.

    +

    Предоставляет методы для взаимодействия с элементами карточки.

    -
    - Атрибуты -

    page: экземпляр страницы Playwright -logout_button: кнопка выхода из системы

    -
    - @@ -1800,10 +1797,7 @@ logout_button: кнопка выхода из системы

    Source code in components\card_component.py -
    11
    -12
    -13
    -14
    +                
    14
     15
     16
     17
    @@ -1830,36 +1824,35 @@ logout_button: кнопка выхода из системы

    38 39 40 -41
    class CardComponent(BaseComponent):
    +41
    +42
    class CardComponent(BaseComponent):
         """Компонент карточки пользователя.
     
    -    Предоставляет методы для взаимодействия с элементами карточки пользователя.
    -
    -    Атрибуты:
    -        page: экземпляр страницы Playwright
    -        logout_button: кнопка выхода из системы
    +    Предоставляет методы для взаимодействия с элементами карточки.
         """
     
         def __init__(self, page: Page):
    -        """Инициализация компонента карточки пользователя.
    +        """Инициализирует компонент карточки пользователя.
     
             Args:
    -            page: экземпляр страницы Playwright
    +            page: Экземпляр страницы Playwright.
             """
    +
             super().__init__(page)
     
             self.logout_button = Button(
    -            page, 
    -            page.get_by_role("button", name="Выйти"), 
    +            page,
    +            page.get_by_role("button", name="Выйти"),
                 "logout button"
             )
     
         # Действия:
         def click_logout_button(self):
    -        """Нажатие кнопки выхода из системы.
    +        """Нажимает кнопку выхода из системы.
     
             Выполняет клик по кнопке 'Выйти' в карточке пользователя.
             """
    +
             self.logout_button.click()
     
    @@ -1887,7 +1880,7 @@ logout_button: кнопка выхода из системы

    -

    Инициализация компонента карточки пользователя.

    +

    Инициализирует компонент карточки пользователя.

    Parameters:

    @@ -1910,7 +1903,7 @@ logout_button: кнопка выхода из системы

    -

    экземпляр страницы Playwright

    +

    Экземпляр страницы Playwright.

    @@ -1923,7 +1916,8 @@ logout_button: кнопка выхода из системы

    Source code in components\card_component.py -
    21
    +              
    20
    +21
     22
     23
     24
    @@ -1936,16 +1930,17 @@ logout_button: кнопка выхода из системы

    31 32 33
    def __init__(self, page: Page):
    -    """Инициализация компонента карточки пользователя.
    +    """Инициализирует компонент карточки пользователя.
     
         Args:
    -        page: экземпляр страницы Playwright
    +        page: Экземпляр страницы Playwright.
         """
    +
         super().__init__(page)
     
         self.logout_button = Button(
    -        page, 
    -        page.get_by_role("button", name="Выйти"), 
    +        page,
    +        page.get_by_role("button", name="Выйти"),
             "logout button"
         )
     
    @@ -1965,7 +1960,7 @@ logout_button: кнопка выхода из системы

    -

    Нажатие кнопки выхода из системы.

    +

    Нажимает кнопку выхода из системы.

    Выполняет клик по кнопке 'Выйти' в карточке пользователя.

    @@ -1976,11 +1971,13 @@ logout_button: кнопка выхода из системы

    38 39 40 -41
    def click_logout_button(self):
    -    """Нажатие кнопки выхода из системы.
    +41
    +42
    def click_logout_button(self):
    +    """Нажимает кнопку выхода из системы.
     
         Выполняет клик по кнопке 'Выйти' в карточке пользователя.
         """
    +
         self.logout_button.click()
     
    diff --git a/site/components/confirm_component/index.html b/site/components/confirm_component/index.html index 9ded5bf..41226a6 100644 --- a/site/components/confirm_component/index.html +++ b/site/components/confirm_component/index.html @@ -1822,6 +1822,10 @@
    +

    Модуль компонента окна подтверждения действий.

    +

    Содержит класс ConfirmComponent для взаимодействия с окном подтверждения, +включая кнопки подтверждения, отмены и закрытия, а также проверки текста.

    + @@ -1856,20 +1860,8 @@

    Компонент окна подтверждения действий.

    -

    Предоставляет методы для взаимодействия с диалоговыми окнами подтверждения, -содержащими кнопки отмены и подтверждения действия.

    -
    - Атрибуты -

    page: экземпляр страницы Playwright -title: текстовый элемент заголовка окна -text: текстовый элемент основного сообщения -close_button: кнопка закрытия окна -cancel_button: кнопка отмены действия -allow_button: кнопка подтверждения действия

    -
    - @@ -1877,11 +1869,7 @@ allow_button: кнопка подтверждения действия

    Source code in components\confirm_component.py -
    13
    -14
    -15
    -16
    -17
    +                
    17
     18
     19
     20
    @@ -1945,43 +1933,18 @@ allow_button: кнопка подтверждения действия

    78 79 80 -81 -82 -83 -84 -85 -86 -87 -88 -89 -90 -91 -92 -93 -94 -95
    class ConfirmComponent(BaseComponent):
    -    """Компонент окна подтверждения действий.
    -
    -    Предоставляет методы для взаимодействия с диалоговыми окнами подтверждения,
    -    содержащими кнопки отмены и подтверждения действия.
    -
    -    Атрибуты:
    -        page: экземпляр страницы Playwright
    -        title: текстовый элемент заголовка окна
    -        text: текстовый элемент основного сообщения
    -        close_button: кнопка закрытия окна
    -        cancel_button: кнопка отмены действия
    -        allow_button: кнопка подтверждения действия
    -    """
    +81
    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: текст на кнопке подтверждения
    +            page: Экземпляр страницы Playwright.
    +            cancel_button_text: Текст кнопки отмены.
    +            allow_button_text: Текст кнопки подтверждения.
             """
    +
             super().__init__(page)
     
             self.title = Text(page, ConfirmLocators.TITLE, "confirm title")
    @@ -1989,58 +1952,51 @@ allow_button: кнопка подтверждения действия

    self.close_button = Button(page, ConfirmLocators.BUTTON_CLOSE, "confirm close button") self.cancel_button = Button( - page, - page.get_by_role("button", name=cancel_button_text).first, + page, + page.get_by_role("button", name=cancel_button_text).first, "confirm cancel button" ) self.allow_button = Button( - page, - page.get_by_role("button", name=allow_button_text).first, + page, + page.get_by_role("button", name=allow_button_text).first, "confirm allow button" ) # Действия: - def click_allow_button(self): - """Нажатие кнопки подтверждения действия. + def click_allow_button(self) -> None: + """Нажимает кнопку подтверждения действия.""" - Выполняет клик по кнопке с текстом, переданным в allow_button_text. - """ self.allow_button.click() - def click_cancel_button(self): - """Нажатие кнопки отмены действия. + def click_cancel_button(self) -> None: + """Нажимает кнопку отмены действия.""" - Выполняет клик по кнопке с текстом, переданным в cancel_button_text. - """ self.cancel_button.click() - def click_close_button(self): - """Нажатие кнопки закрытия окна подтверждения.""" + def click_close_button(self) -> None: + """Нажимает кнопку закрытия окна подтверждения.""" + self.close_button.click() # Проверки: - def check_title(self, title, msg): - """Проверка текста заголовка окна подтверждения. + def check_title(self, title: str, msg: str) -> None: + """Проверяет текст заголовка окна подтверждения. Args: - title: ожидаемый текст заголовка - msg: сообщение об ошибке при несоответствии - - Raises: - AssertionError: если текст заголовка не соответствует ожидаемому + title: Ожидаемый текст заголовка. + msg: Сообщение при ошибке. """ + self.title.check_have_text(title, msg) - def check_text(self, text, msg): - """Проверка текста сообщения в окне подтверждения. + def check_text(self, text: str, msg: str) -> None: + """Проверяет текст сообщения в окне подтверждения. Args: - text: ожидаемый текст сообщения - msg: сообщение об ошибке при несоответствии - - Raises: - AssertionError: если текст сообщения не соответствует ожидаемому + text: Ожидаемый текст сообщения. + msg: Сообщение при ошибке. """ + self.text.check_have_text(text, msg)
    @@ -2068,7 +2024,7 @@ allow_button: кнопка подтверждения действия

    -

    Инициализация компонента окна подтверждения.

    +

    Инициализация компонента.

    Parameters:

    @@ -2091,7 +2047,7 @@ allow_button: кнопка подтверждения действия

    -

    экземпляр страницы Playwright

    +

    Экземпляр страницы Playwright.

    @@ -2107,7 +2063,7 @@ allow_button: кнопка подтверждения действия

    -

    текст на кнопке отмены

    +

    Текст кнопки отмены.

    @@ -2123,7 +2079,7 @@ allow_button: кнопка подтверждения действия

    -

    текст на кнопке подтверждения

    +

    Текст кнопки подтверждения.

    @@ -2136,7 +2092,15 @@ allow_button: кнопка подтверждения действия

    Source code in components\confirm_component.py -
    28
    +              
    20
    +21
    +22
    +23
    +24
    +25
    +26
    +27
    +28
     29
     30
     31
    @@ -2152,21 +2116,15 @@ allow_button: кнопка подтверждения действия

    41 42 43 -44 -45 -46 -47 -48 -49 -50 -51
    def __init__(self, page: Page, cancel_button_text: str, allow_button_text: str):
    -    """Инициализация компонента окна подтверждения.
    +44
    def __init__(self, page: Page, cancel_button_text: str, allow_button_text: str):
    +    """Инициализация компонента.
     
         Args:
    -        page: экземпляр страницы Playwright
    -        cancel_button_text: текст на кнопке отмены
    -        allow_button_text: текст на кнопке подтверждения
    +        page: Экземпляр страницы Playwright.
    +        cancel_button_text: Текст кнопки отмены.
    +        allow_button_text: Текст кнопки подтверждения.
         """
    +
         super().__init__(page)
     
         self.title = Text(page, ConfirmLocators.TITLE, "confirm title")
    @@ -2174,13 +2132,13 @@ allow_button: кнопка подтверждения действия

    self.close_button = Button(page, ConfirmLocators.BUTTON_CLOSE, "confirm close button") self.cancel_button = Button( - page, - page.get_by_role("button", name=cancel_button_text).first, + page, + page.get_by_role("button", name=cancel_button_text).first, "confirm cancel button" ) self.allow_button = Button( - page, - page.get_by_role("button", name=allow_button_text).first, + page, + page.get_by_role("button", name=allow_button_text).first, "confirm allow button" )
    @@ -2200,7 +2158,7 @@ allow_button: кнопка подтверждения действия

    -

    Проверка текста сообщения в окне подтверждения.

    +

    Проверяет текст сообщения в окне подтверждения.

    Parameters:

    @@ -2219,10 +2177,11 @@ allow_button: кнопка подтверждения действия

    text
    + str
    -

    ожидаемый текст сообщения

    +

    Ожидаемый текст сообщения.

    @@ -2234,10 +2193,11 @@ allow_button: кнопка подтверждения действия

    msg
    + str
    -

    сообщение об ошибке при несоответствии

    +

    Сообщение при ошибке.

    @@ -2248,51 +2208,24 @@ allow_button: кнопка подтверждения действия

    -

    Raises:

    - - - - - - - - - - - - - -
    TypeDescription
    - AssertionError - -
    -

    если текст сообщения не соответствует ожидаемому

    -
    -
    - -
    Source code in components\confirm_component.py -
    85
    -86
    -87
    -88
    -89
    -90
    -91
    -92
    -93
    -94
    -95
    def check_text(self, text, msg):
    -    """Проверка текста сообщения в окне подтверждения.
    +              
    73
    +74
    +75
    +76
    +77
    +78
    +79
    +80
    +81
    def check_text(self, text: str, msg: str) -> None:
    +    """Проверяет текст сообщения в окне подтверждения.
     
         Args:
    -        text: ожидаемый текст сообщения
    -        msg: сообщение об ошибке при несоответствии
    -
    -    Raises:
    -        AssertionError: если текст сообщения не соответствует ожидаемому
    +        text: Ожидаемый текст сообщения.
    +        msg: Сообщение при ошибке.
         """
    +
         self.text.check_have_text(text, msg)
     
    @@ -2311,7 +2244,7 @@ allow_button: кнопка подтверждения действия

    -

    Проверка текста заголовка окна подтверждения.

    +

    Проверяет текст заголовка окна подтверждения.

    Parameters:

    @@ -2330,10 +2263,11 @@ allow_button: кнопка подтверждения действия

    title
    + str
    -

    ожидаемый текст заголовка

    +

    Ожидаемый текст заголовка.

    @@ -2345,10 +2279,11 @@ allow_button: кнопка подтверждения действия

    msg
    + str
    -

    сообщение об ошибке при несоответствии

    +

    Сообщение при ошибке.

    @@ -2359,51 +2294,24 @@ allow_button: кнопка подтверждения действия

    -

    Raises:

    - - - - - - - - - - - - - -
    TypeDescription
    - AssertionError - -
    -

    если текст заголовка не соответствует ожидаемому

    -
    -
    - -
    Source code in components\confirm_component.py -
    73
    -74
    -75
    -76
    -77
    -78
    -79
    -80
    -81
    -82
    -83
    def check_title(self, title, msg):
    -    """Проверка текста заголовка окна подтверждения.
    +              
    63
    +64
    +65
    +66
    +67
    +68
    +69
    +70
    +71
    def check_title(self, title: str, msg: str) -> None:
    +    """Проверяет текст заголовка окна подтверждения.
     
         Args:
    -        title: ожидаемый текст заголовка
    -        msg: сообщение об ошибке при несоответствии
    -
    -    Raises:
    -        AssertionError: если текст заголовка не соответствует ожидаемому
    +        title: Ожидаемый текст заголовка.
    +        msg: Сообщение при ошибке.
         """
    +
         self.title.check_have_text(title, msg)
     
    @@ -2422,22 +2330,17 @@ allow_button: кнопка подтверждения действия

    -

    Нажатие кнопки подтверждения действия.

    -

    Выполняет клик по кнопке с текстом, переданным в allow_button_text.

    +

    Нажимает кнопку подтверждения действия.

    Source code in components\confirm_component.py -
    54
    -55
    -56
    -57
    -58
    -59
    def click_allow_button(self):
    -    """Нажатие кнопки подтверждения действия.
    +              
    47
    +48
    +49
    +50
    def click_allow_button(self) -> None:
    +    """Нажимает кнопку подтверждения действия."""
     
    -    Выполняет клик по кнопке с текстом, переданным в allow_button_text.
    -    """
         self.allow_button.click()
     
    @@ -2456,22 +2359,17 @@ allow_button: кнопка подтверждения действия

    -

    Нажатие кнопки отмены действия.

    -

    Выполняет клик по кнопке с текстом, переданным в cancel_button_text.

    +

    Нажимает кнопку отмены действия.

    Source code in components\confirm_component.py -
    61
    -62
    -63
    -64
    -65
    -66
    def click_cancel_button(self):
    -    """Нажатие кнопки отмены действия.
    +              
    52
    +53
    +54
    +55
    def click_cancel_button(self) -> None:
    +    """Нажимает кнопку отмены действия."""
     
    -    Выполняет клик по кнопке с текстом, переданным в cancel_button_text.
    -    """
         self.cancel_button.click()
     
    @@ -2490,15 +2388,17 @@ allow_button: кнопка подтверждения действия

    -

    Нажатие кнопки закрытия окна подтверждения.

    +

    Нажимает кнопку закрытия окна подтверждения.

    Source code in components\confirm_component.py -
    68
    -69
    -70
    def click_close_button(self):
    -    """Нажатие кнопки закрытия окна подтверждения."""
    +              
    57
    +58
    +59
    +60
    def click_close_button(self) -> None:
    +    """Нажимает кнопку закрытия окна подтверждения."""
    +
         self.close_button.click()
     
    diff --git a/site/components/modal_window_component/index.html b/site/components/modal_window_component/index.html index 1a20f00..98786c1 100644 --- a/site/components/modal_window_component/index.html +++ b/site/components/modal_window_component/index.html @@ -566,15 +566,6 @@