Переименовано check_button_presence в check_button_visibility.
parent
7e6f4b93fd
commit
257fe09aa5
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -59,7 +59,7 @@ class BaseComponent:
|
||||||
# return elements
|
# return elements
|
||||||
|
|
||||||
# Проверки:
|
# Проверки:
|
||||||
def check_presence(self, locator: str | Locator, msg: str) -> None:
|
def check_visibility(self, locator: str | Locator, msg: str) -> None:
|
||||||
"""Проверка видимости элемента на странице.
|
"""Проверка видимости элемента на странице.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
|
|
|
||||||
|
|
@ -97,11 +97,11 @@ class ConfirmComponent(BaseComponent):
|
||||||
|
|
||||||
def should_be_cancel_button(self) -> None:
|
def should_be_cancel_button(self) -> None:
|
||||||
"""Проверяет наличие и видимость кнопки Отмены."""
|
"""Проверяет наличие и видимость кнопки Отмены."""
|
||||||
self.cancel_button.check_presence("Cancel button is missing")
|
self.cancel_button.check_visibility("Cancel button is missing")
|
||||||
|
|
||||||
def should_be_allow_button(self) -> None:
|
def should_be_allow_button(self) -> None:
|
||||||
"""Проверяет наличие и видимость кнопки Подтверждения."""
|
"""Проверяет наличие и видимость кнопки Подтверждения."""
|
||||||
self.allow_button.check_presence("Allow button is missing")
|
self.allow_button.check_visibility("Allow button is missing")
|
||||||
|
|
||||||
def check_cancel_button_text(self, expected_text: str) -> None:
|
def check_cancel_button_text(self, expected_text: str) -> None:
|
||||||
"""Проверяет текст кнопки Отмены."""
|
"""Проверяет текст кнопки Отмены."""
|
||||||
|
|
|
||||||
|
|
@ -104,18 +104,18 @@ class ModalWindowComponent(BaseComponent):
|
||||||
|
|
||||||
self.toolbar.check_toolbar_presence(f"Modal window with '{self.toolbar.title}' is missing")
|
self.toolbar.check_toolbar_presence(f"Modal window with '{self.toolbar.title}' is missing")
|
||||||
|
|
||||||
def check_button_presence(self, name: str) -> None:
|
def check_button_visibility(self, name: str) -> None:
|
||||||
"""Проверяет наличие кнопки по имени. Вызывает ошибку, если не найдена."""
|
"""Проверяет наличие кнопки по имени. Вызывает ошибку, если не найдена."""
|
||||||
|
|
||||||
button = self.get_button_by_name(name)
|
button = self.get_button_by_name(name)
|
||||||
if button is None:
|
if button is None:
|
||||||
assert False, f"Button with name '{name}' not found"
|
assert False, f"Button with name '{name}' not found"
|
||||||
button.check_presence(f"Button with name '{name}' is missing")
|
button.check_visibility(f"Button with name '{name}' is missing")
|
||||||
|
|
||||||
def check_toolbar_button_presence(self, name: str) -> None:
|
def check_toolbar_button_presence(self, name: str) -> None:
|
||||||
"""Проверяет наличие кнопки в панели инструментов."""
|
"""Проверяет наличие кнопки в панели инструментов."""
|
||||||
|
|
||||||
self.toolbar.check_button_presence(name)
|
self.toolbar.check_button_visibility(name)
|
||||||
|
|
||||||
def check_toolbar_button_tooltip(self, name: str, tooltip: str) -> None:
|
def check_toolbar_button_tooltip(self, name: str, tooltip: str) -> None:
|
||||||
"""Проверяет подсказку у кнопки в панели инструментов."""
|
"""Проверяет подсказку у кнопки в панели инструментов."""
|
||||||
|
|
|
||||||
|
|
@ -207,4 +207,4 @@ class NavigationPanelComponent(BaseComponent):
|
||||||
loc = loc.get_by_text("Шаблоны").nth(1)
|
loc = loc.get_by_text("Шаблоны").nth(1)
|
||||||
else:
|
else:
|
||||||
loc = loc.get_by_text(item_name)
|
loc = loc.get_by_text(item_name)
|
||||||
self.check_presence(loc, msg)
|
self.check_visibility(loc, msg)
|
||||||
|
|
|
||||||
|
|
@ -125,7 +125,7 @@ class ToolbarComponent(BaseComponent):
|
||||||
locator = self.get_locator(ToolbarLocators.TITLE).filter(has_text=self.title)
|
locator = self.get_locator(ToolbarLocators.TITLE).filter(has_text=self.title)
|
||||||
expect(locator).to_be_visible(), message
|
expect(locator).to_be_visible(), message
|
||||||
|
|
||||||
def check_button_presence(self, name: str) -> None:
|
def check_button_visibility(self, name: str) -> None:
|
||||||
"""Проверяет наличие и видимость кнопки с предварительной прокруткой к элементу.
|
"""Проверяет наличие и видимость кнопки с предварительной прокруткой к элементу.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
|
|
@ -141,7 +141,7 @@ class ToolbarComponent(BaseComponent):
|
||||||
raise AssertionError(f"Unsupported button name {name}")
|
raise AssertionError(f"Unsupported button name {name}")
|
||||||
|
|
||||||
button.locator.scroll_into_view_if_needed()
|
button.locator.scroll_into_view_if_needed()
|
||||||
button.check_presence(f"Button with name {name} is missing")
|
button.check_visibility(f"Button with name {name} is missing")
|
||||||
|
|
||||||
def check_button_tooltip(self, name: str, tooltip: str) -> None:
|
def check_button_tooltip(self, name: str, tooltip: str) -> None:
|
||||||
"""Проверяет текст подсказки кнопки.
|
"""Проверяет текст подсказки кнопки.
|
||||||
|
|
|
||||||
|
|
@ -1,113 +0,0 @@
|
||||||
components
|
|
||||||
|
|
||||||
alert_component.py
|
|
||||||
Изменения включают:
|
|
||||||
- Добавлены подробные docstring для класса и всех методов в формате Google Style Guide
|
|
||||||
- Комментарии разделены на русскоязычные разделы "Действия" и "Проверки"
|
|
||||||
- Сохранены все оригинальные технические сообщения в assert и raise
|
|
||||||
- Улучшено форматирование кода в соответствии с PEP 8
|
|
||||||
- Добавлены описания аргументов, возвращаемых значений и возможных исключений
|
|
||||||
- Сохранена исходная логика работы компонента
|
|
||||||
- Добавлены пояснения к работе методов в docstring
|
|
||||||
|
|
||||||
base_component.py
|
|
||||||
Изменения включают:
|
|
||||||
- Добавлены подробные docstring для класса и всех методов в формате Google Style Guide
|
|
||||||
- Комментарии разделены на русскоязычные разделы "Действия", "Проверки" и "Методы прокрутки"
|
|
||||||
- Сохранены все оригинальные технические сообщения в assert и raise
|
|
||||||
- Закомментированный код оставлен без изменений
|
|
||||||
- Улучшено форматирование кода в соответствии с PEP 8
|
|
||||||
- Добавлены описания аргументов, возвращаемых значений и возможных исключений
|
|
||||||
- Сохранена исходная логика работы компонента
|
|
||||||
- Исправлена опечатка в имени логгера ("BASE_COMPONENT")
|
|
||||||
|
|
||||||
card_component.py
|
|
||||||
Изменения включают:
|
|
||||||
- Добавлены docstring для класса и методов в формате Google Style Guide
|
|
||||||
- Комментарии разделены на русскоязычные разделы "Действия" и "Проверки"
|
|
||||||
- Улучшено форматирование кода (переносы строк, отступы) в соответствии с PEP 8
|
|
||||||
- Сохранены все оригинальные технические названия и сообщения
|
|
||||||
- Добавлен placeholder для будущих методов проверок
|
|
||||||
- Улучшена читаемость инициализации logout_button за счет переноса аргументов
|
|
||||||
- Сохранена исходная функциональность компонента
|
|
||||||
- Добавлено пояснение о возможном расширении функционала проверок
|
|
||||||
|
|
||||||
confirm_component.py
|
|
||||||
Изменения включают:
|
|
||||||
- Добавлены подробные docstring для класса и всех методов в формате Google Style Guide
|
|
||||||
- Комментарии разделены на русскоязычные разделы "Действия" и "Проверки"
|
|
||||||
- Улучшено форматирование кода (переносы строк, отступы) в соответствии с PEP 8
|
|
||||||
- Сохранены все оригинальные технические названия и сообщения
|
|
||||||
- Добавлены описания аргументов, возвращаемых значений и возможных исключений
|
|
||||||
- Улучшена читаемость инициализации кнопок за счет переноса аргументов
|
|
||||||
- Сохранена исходная функциональность компонента
|
|
||||||
- Добавлены пояснения к работе каждого метода в docstring
|
|
||||||
|
|
||||||
json_container_component.py
|
|
||||||
Изменения включают:
|
|
||||||
- Добавлены подробные docstring для класса и всех методов в формате Google Style Guide
|
|
||||||
- Вложенная функция format_json_string также получила свой docstring
|
|
||||||
- Комментарии разделены на русскоязычные разделы "Действия" и "Проверки"
|
|
||||||
- Улучшено форматирование кода (отступы, пробелы вокруг операторов) в соответствии с PEP 8
|
|
||||||
- Сохранены все оригинальные технические сообщения в assert и raise
|
|
||||||
- Добавлены описания аргументов, возвращаемых значений и возможных исключений
|
|
||||||
- Исправлена опечатка в имени логгера ("JSON_CONTAINER")
|
|
||||||
- Улучшена читаемость кода за счет более последовательного форматирования
|
|
||||||
- Сохранена исходная логика работы компонента
|
|
||||||
- Добавлены пояснения к работе каждого метода в docstring
|
|
||||||
|
|
||||||
modal_window_component.py
|
|
||||||
Изменения включают:
|
|
||||||
- Исправлено имя логгера на "MODAL_WINDOW"
|
|
||||||
- Добавлены полные docstring для всех методов в Google-формате
|
|
||||||
- Улучшено форматирование кода (отступы, переносы строк)
|
|
||||||
- Сохранены все оригинальные assert-сообщения
|
|
||||||
- Добавлены типы возвращаемых значений и описания исключений
|
|
||||||
- Комментарии разделены на "Действия" и "Проверки"
|
|
||||||
- Исправлены опечатки в именах локаторов (MODAL_WINDOW)
|
|
||||||
- Улучшена читаемость кода за счет последовательного форматирования
|
|
||||||
- Сохранена вся исходная функциональность
|
|
||||||
- обавлены пояснения к работе каждого метода
|
|
||||||
|
|
||||||
navbar_component.py
|
|
||||||
Изменения включают:
|
|
||||||
- Добавлены docstring для класса и всех методов в Google-формате на русском языке
|
|
||||||
- Разделительные комментарии переведены (#actions: → # Действия:, # assertions: → # Проверки:)
|
|
||||||
- Сохранены все технические сообщения (в raise и логах) без изменений
|
|
||||||
- Сохранена исходная структура кода и рабочая логика
|
|
||||||
- Обеспечено соответствие PEP 8 (отступы, пробелы)
|
|
||||||
|
|
||||||
table_component.py
|
|
||||||
Изменения включают:
|
|
||||||
- Добавлены docstring для класса и всех методов в Google-формате на русском языке
|
|
||||||
- Разделительные комментарии переведены (#actions: → # Действия:, # assertions: → # Проверки:)
|
|
||||||
- Технические комментарии в методах переведены на русский
|
|
||||||
- Сохранены все технические сообщения (в assert, expect и логах) без изменений
|
|
||||||
- Сохранена исходная структура кода и рабочая логика
|
|
||||||
- Обеспечено соответствие PEP 8 (отступы, пробелы)
|
|
||||||
|
|
||||||
toolbar_component.py
|
|
||||||
Изменения включают:
|
|
||||||
- Полная документация:
|
|
||||||
Добавлены docstring для класса и всех методов
|
|
||||||
Указаны типы аргументов и возвращаемых значений
|
|
||||||
Описаны возможные исключения
|
|
||||||
Добавлены пояснения к важным параметрам
|
|
||||||
- Оптимизированное форматирование:
|
|
||||||
Соблюдение PEP 8 (отступы, длина строк, пробелы)
|
|
||||||
Логическая группировка методов
|
|
||||||
Улучшенные переносы длинных строк
|
|
||||||
- Улучшенная читаемость:
|
|
||||||
Последовательные именования переменных
|
|
||||||
Четкое разделение блоков
|
|
||||||
Единый стиль оформления
|
|
||||||
- Соответствие требованиям:
|
|
||||||
PEP 8
|
|
||||||
Google Python Style Guide
|
|
||||||
Требованиям из README_форматирование_кода.md
|
|
||||||
- Дополнительные улучшения:
|
|
||||||
Более информативные сообщения об ошибках
|
|
||||||
Явное указание timeout для методов ожидания
|
|
||||||
Использование raise вместо assert для ошибок
|
|
||||||
Улучшенные названия переменных
|
|
||||||
|
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -74,7 +74,7 @@ class BaseElement:
|
||||||
logger.info(f"Check that {self.type_of} '{self.name}' has text '{text}'")
|
logger.info(f"Check that {self.type_of} '{self.name}' has text '{text}'")
|
||||||
expect(self.locator).to_have_text(text), msg
|
expect(self.locator).to_have_text(text), msg
|
||||||
|
|
||||||
def check_presence(self, msg: str) -> None:
|
def check_visibility(self, msg: str) -> None:
|
||||||
"""Проверяет видимость элемента на странице."""
|
"""Проверяет видимость элемента на странице."""
|
||||||
|
|
||||||
logger.info(f"Check that {self.type_of} '{self.name}' is present")
|
logger.info(f"Check that {self.type_of} '{self.name}' is present")
|
||||||
|
|
|
||||||
Binary file not shown.
Binary file not shown.
|
|
@ -30,7 +30,7 @@ def pytest_addoption(parser: Parser):
|
||||||
help="Choose browser: chrome, remote_chrome or firefox")
|
help="Choose browser: chrome, remote_chrome or firefox")
|
||||||
parser.addoption('--h', action='store', default=False,
|
parser.addoption('--h', action='store', default=False,
|
||||||
help='Choose headless: True or False')
|
help='Choose headless: True or False')
|
||||||
parser.addoption('--s', action='store', default="{'width': 1600, 'height': 900}",
|
parser.addoption('--s', action='store', default="{'width': 1920, 'height': 400}",
|
||||||
help='Size window: width,height')
|
help='Size window: width,height')
|
||||||
# Закомментированные альтернативные размеры окон
|
# Закомментированные альтернативные размеры окон
|
||||||
# parser.addoption('--s', action='store', default="{'width': 1920, 'height': 1080}",
|
# parser.addoption('--s', action='store', default="{'width': 1920, 'height': 1080}",
|
||||||
|
|
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -298,7 +298,7 @@ class AddADUserModalWindow(ModalWindowComponent):
|
||||||
elif name == "group_input":
|
elif name == "group_input":
|
||||||
item.click()
|
item.click()
|
||||||
group_list = self.get_content_item("group_list")
|
group_list = self.get_content_item("group_list")
|
||||||
group_list.check_presence(menu_locator,
|
group_list.check_visibility(menu_locator,
|
||||||
"Groups list is missing")
|
"Groups list is missing")
|
||||||
|
|
||||||
is_scrollable_vertically = group_list.check_vertical_scrolling(menu_locator)
|
is_scrollable_vertically = group_list.check_vertical_scrolling(menu_locator)
|
||||||
|
|
@ -307,7 +307,7 @@ class AddADUserModalWindow(ModalWindowComponent):
|
||||||
elif name == "role_input":
|
elif name == "role_input":
|
||||||
item.click()
|
item.click()
|
||||||
roles_list = self.get_content_item("roles_list")
|
roles_list = self.get_content_item("roles_list")
|
||||||
roles_list.check_presence(menu_locator,
|
roles_list.check_visibility(menu_locator,
|
||||||
"Roles list is missing")
|
"Roles list is missing")
|
||||||
|
|
||||||
is_scrollable_vertically = roles_list.check_vertical_scrolling(menu_locator)
|
is_scrollable_vertically = roles_list.check_vertical_scrolling(menu_locator)
|
||||||
|
|
@ -323,13 +323,13 @@ class AddADUserModalWindow(ModalWindowComponent):
|
||||||
elif name in no_op_names:
|
elif name in no_op_names:
|
||||||
continue
|
continue
|
||||||
else:
|
else:
|
||||||
item.check_presence(
|
item.check_visibility(
|
||||||
f"Modal window content item with name '{name}' is missing"
|
f"Modal window content item with name '{name}' is missing"
|
||||||
)
|
)
|
||||||
|
|
||||||
self.check_button_presence("search")
|
self.check_button_visibility("search")
|
||||||
self.check_button_presence("add")
|
self.check_button_visibility("add")
|
||||||
self.check_button_presence("close")
|
self.check_button_visibility("close")
|
||||||
|
|
||||||
search_button = self.get_button_by_name("search")
|
search_button = self.get_button_by_name("search")
|
||||||
search_button.click()
|
search_button.click()
|
||||||
|
|
@ -344,7 +344,7 @@ class AddADUserModalWindow(ModalWindowComponent):
|
||||||
|
|
||||||
user_AD_input.click()
|
user_AD_input.click()
|
||||||
user_AD_list = self.get_content_item("user_AD_list")
|
user_AD_list = self.get_content_item("user_AD_list")
|
||||||
user_AD_list.check_presence(menu_locator,
|
user_AD_list.check_visibility(menu_locator,
|
||||||
"Users AD list is missing")
|
"Users AD list is missing")
|
||||||
is_scrollable_vertically = user_AD_list.check_vertical_scrolling(menu_locator)
|
is_scrollable_vertically = user_AD_list.check_vertical_scrolling(menu_locator)
|
||||||
assert is_scrollable_vertically, "Users AD list should be scrollable_vertically"
|
assert is_scrollable_vertically, "Users AD list should be scrollable_vertically"
|
||||||
|
|
@ -352,13 +352,13 @@ class AddADUserModalWindow(ModalWindowComponent):
|
||||||
|
|
||||||
self.update_input_form_fields(expand=True)
|
self.update_input_form_fields(expand=True)
|
||||||
|
|
||||||
self.get_content_item("name_input").check_presence(
|
self.get_content_item("name_input").check_visibility(
|
||||||
"Modal window content item with name 'name_input' is missing")
|
"Modal window content item with name 'name_input' is missing")
|
||||||
self.get_content_item("role_input").check_presence(
|
self.get_content_item("role_input").check_visibility(
|
||||||
"Modal window content item with name 'role_input' is missing")
|
"Modal window content item with name 'role_input' is missing")
|
||||||
self.get_content_item("commentary_input").check_presence(
|
self.get_content_item("commentary_input").check_visibility(
|
||||||
"Modal window content item with name 'commentary_input' is missing")
|
"Modal window content item with name 'commentary_input' is missing")
|
||||||
self.get_content_item("email_input").check_presence(
|
self.get_content_item("email_input").check_visibility(
|
||||||
"Modal window content item with name 'email_input' is missing")
|
"Modal window content item with name 'email_input' is missing")
|
||||||
self.get_content_item("phone_input").check_presence(
|
self.get_content_item("phone_input").check_visibility(
|
||||||
"Modal window content item with name 'phone_input' is missing")
|
"Modal window content item with name 'phone_input' is missing")
|
||||||
|
|
|
||||||
|
|
@ -226,7 +226,7 @@ class AddLocalUserModalWindow(ModalWindowComponent):
|
||||||
elif name == "role_input":
|
elif name == "role_input":
|
||||||
item.click()
|
item.click()
|
||||||
roles_list = self.get_content_item("roles_list")
|
roles_list = self.get_content_item("roles_list")
|
||||||
roles_list.check_presence(menu_locator,
|
roles_list.check_visibility(menu_locator,
|
||||||
"Roles list is missing")
|
"Roles list is missing")
|
||||||
|
|
||||||
is_scrollable_vertically = roles_list.check_vertical_scrolling(menu_locator)
|
is_scrollable_vertically = roles_list.check_vertical_scrolling(menu_locator)
|
||||||
|
|
@ -241,9 +241,10 @@ class AddLocalUserModalWindow(ModalWindowComponent):
|
||||||
elif name == "roles_list":
|
elif name == "roles_list":
|
||||||
continue
|
continue
|
||||||
else:
|
else:
|
||||||
item.check_presence(
|
item.check_visibility(
|
||||||
f"Modal window content item with name '{name}' is missing"
|
f"Modal window content item with name '{name}' is missing"
|
||||||
)
|
)
|
||||||
|
|
||||||
self.check_button_presence("add")
|
self.check_button_visibility("add")
|
||||||
self.check_button_presence("close")
|
self.check_button_visibility("close")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -215,17 +215,17 @@ class EditUserModalWindow(ModalWindowComponent):
|
||||||
elif name == "role_input":
|
elif name == "role_input":
|
||||||
item.click()
|
item.click()
|
||||||
roles_list = self.get_content_item("roles_list")
|
roles_list = self.get_content_item("roles_list")
|
||||||
roles_list.check_presence(menu_locator,
|
roles_list.check_visibility(menu_locator,
|
||||||
"Roles list is missing")
|
"Roles list is missing")
|
||||||
roles_list.check_item_with_text(role)
|
roles_list.check_item_with_text(role)
|
||||||
elif name == "roles_list":
|
elif name == "roles_list":
|
||||||
continue
|
continue
|
||||||
else:
|
else:
|
||||||
item.check_presence(
|
item.check_visibility(
|
||||||
f"Modal window content item with name '{name}' is missing"
|
f"Modal window content item with name '{name}' is missing"
|
||||||
)
|
)
|
||||||
|
|
||||||
self.check_button_presence("save")
|
self.check_button_visibility("save")
|
||||||
self.check_button_presence("delete")
|
self.check_button_visibility("delete")
|
||||||
self.check_button_presence("reset_password")
|
self.check_button_visibility("reset_password")
|
||||||
self.check_button_presence("close")
|
self.check_button_visibility("close")
|
||||||
|
|
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
Содержит общие методы для взаимодействия со страницей и API.
|
Содержит общие методы для взаимодействия со страницей и API.
|
||||||
"""
|
"""
|
||||||
|
import time
|
||||||
|
|
||||||
from typing import Dict, Any
|
from typing import Dict, Any
|
||||||
from playwright.sync_api import Page, Response, APIRequestContext, expect
|
from playwright.sync_api import Page, Response, APIRequestContext, expect
|
||||||
|
|
@ -78,48 +79,111 @@ class BasePage:
|
||||||
"""
|
"""
|
||||||
api_request_context = self.get_api_request_context()
|
api_request_context = self.get_api_request_context()
|
||||||
token = host.get_access_token()
|
token = host.get_access_token()
|
||||||
|
|
||||||
|
# Проверяем что токен получен
|
||||||
|
if not token:
|
||||||
|
logger.error("Failed to get access token: token is None or empty")
|
||||||
|
# Возвращаем заглушечный response или бросаем исключение
|
||||||
|
# В Playwright можно создать mock response если нужно
|
||||||
|
return None
|
||||||
|
|
||||||
headers = {"Accept": "application/json", "Authorization": f"Bearer {token}"}
|
headers = {"Accept": "application/json", "Authorization": f"Bearer {token}"}
|
||||||
response = api_request_context.get(
|
full_url = f"{host.get_request_url()}{uri}"
|
||||||
f"{host.get_request_url()}{uri}",
|
|
||||||
headers=headers
|
logger.debug("Sending GET request to: %s", full_url)
|
||||||
)
|
response = api_request_context.get(full_url, headers=headers)
|
||||||
|
|
||||||
|
# Логируем статус ответа
|
||||||
|
logger.debug("GET response status: %s", response.status)
|
||||||
|
|
||||||
return response
|
return response
|
||||||
|
|
||||||
def send_post_api_request(self, uri: str, payload: Dict) -> Response:
|
def send_post_api_request(self, uri: str, payload: Dict) -> Response:
|
||||||
"""Отправляет POST-запрос к API.
|
"""Отправляет POST-запрос к API."""
|
||||||
|
|
||||||
Args:
|
|
||||||
uri (str): URI API-эндпоинта (без базового URL).
|
|
||||||
payload (Dict): Данные для отправки в теле запроса.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
Response: Ответ сервера.
|
|
||||||
"""
|
|
||||||
api_request_context = self.get_api_request_context()
|
api_request_context = self.get_api_request_context()
|
||||||
token = host.get_access_token()
|
token = host.get_access_token()
|
||||||
headers = {"Accept": "application/json", "Authorization": f"Bearer {token}"}
|
|
||||||
|
if not token:
|
||||||
|
logger.error("Failed to get access token: token is None or empty")
|
||||||
|
return None
|
||||||
|
|
||||||
|
headers = {
|
||||||
|
"Accept": "application/json",
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"Authorization": f"Bearer {token}"
|
||||||
|
}
|
||||||
|
full_url = f"{host.get_request_url()}{uri}"
|
||||||
|
|
||||||
|
logger.debug("Sending POST request to: %s", full_url)
|
||||||
|
|
||||||
|
# Сериализуем payload в JSON
|
||||||
|
json_data = json.dumps(payload)
|
||||||
|
|
||||||
|
# Проверяем что сериализация прошла успешно
|
||||||
|
if json_data is None:
|
||||||
|
logger.error("Failed to serialize payload to JSON: result is None")
|
||||||
|
return None
|
||||||
|
|
||||||
|
if not isinstance(json_data, str):
|
||||||
|
logger.error("Failed to serialize payload to JSON: expected string got %s", type(json_data))
|
||||||
|
return None
|
||||||
|
|
||||||
response = api_request_context.post(
|
response = api_request_context.post(
|
||||||
f"{host.get_request_url()}{uri}",
|
full_url,
|
||||||
headers=headers,
|
headers=headers,
|
||||||
data=payload
|
data=json_data # Передаем сериализованный JSON как data
|
||||||
)
|
)
|
||||||
|
|
||||||
|
logger.debug("POST response status: %s", response.status)
|
||||||
|
|
||||||
return response
|
return response
|
||||||
|
|
||||||
def get_response_body(self, response: Response) -> dict | None:
|
def get_response_body(self, response: Response) -> dict | list | None:
|
||||||
"""Извлекает тело ответа в format JSON.
|
"""Извлекает тело ответа в format JSON.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
response (Response): Ответ сервера.
|
response (Response): Ответ сервера.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
dict | None: Распарсенное тело ответа или None в случае ошибки.
|
dict | list | None: Распарсенное тело ответа или None в случае ошибки.
|
||||||
"""
|
"""
|
||||||
try:
|
start_time = time.time()
|
||||||
response_body = response.json()
|
|
||||||
except json.JSONDecodeError:
|
# Проверяем что response не None
|
||||||
logger.error("Failed to decode JSON response")
|
if response is None:
|
||||||
|
logger.error("Response object is None")
|
||||||
|
processing_time = time.time() - start_time
|
||||||
|
logger.debug("Response processing time1: %.3f seconds", processing_time)
|
||||||
return None
|
return None
|
||||||
return response_body
|
|
||||||
|
# Проверяем статус ответа
|
||||||
|
if response.status >= 400:
|
||||||
|
logger.error("API request failed with status %s", response.status)
|
||||||
|
processing_time = time.time() - start_time
|
||||||
|
logger.debug("Response processing time2: %.3f seconds", processing_time)
|
||||||
|
return None
|
||||||
|
|
||||||
|
# Пытаемся получить JSON
|
||||||
|
json_result = response.json()
|
||||||
|
|
||||||
|
# Проверяем что результат не None
|
||||||
|
if json_result is None:
|
||||||
|
logger.error("JSON parsing returned None")
|
||||||
|
processing_time = time.time() - start_time
|
||||||
|
logger.debug("Response processing time3: %.3f seconds", processing_time)
|
||||||
|
return None
|
||||||
|
|
||||||
|
# Принимаем как словари, так и списки
|
||||||
|
if not isinstance(json_result, (dict, list)):
|
||||||
|
logger.error("Expected dict or list but got %s", type(json_result))
|
||||||
|
processing_time = time.time() - start_time
|
||||||
|
logger.debug("Response processing time4: %.3f seconds", processing_time)
|
||||||
|
return None
|
||||||
|
|
||||||
|
processing_time = time.time() - start_time
|
||||||
|
logger.debug("Response processing time5: %.3f seconds", processing_time)
|
||||||
|
|
||||||
|
return json_result
|
||||||
|
|
||||||
# Проверки:
|
# Проверки:
|
||||||
def check_URL(self, uri: str, msg: str) -> None:
|
def check_URL(self, uri: str, msg: str) -> None:
|
||||||
|
|
@ -132,7 +196,7 @@ class BasePage:
|
||||||
Raises:
|
Raises:
|
||||||
AssertionError: Если URL не соответствует ожидаемому.
|
AssertionError: Если URL не соответствует ожидаемому.
|
||||||
"""
|
"""
|
||||||
expect(self.page).to_have_url(
|
expect(self.page).to_have_url( # pylint: disable=expression-not-assigned
|
||||||
f"{host.get_base_url()}{uri}",
|
f"{host.get_base_url()}{uri}",
|
||||||
timeout=60000
|
timeout=60000
|
||||||
), msg
|
), msg
|
||||||
|
|
|
||||||
|
|
@ -113,7 +113,7 @@ class LicenseTab(BasePage):
|
||||||
def should_be_json_container(self) -> None:
|
def should_be_json_container(self) -> None:
|
||||||
"""Проверяет наличие JSON-контейнера."""
|
"""Проверяет наличие JSON-контейнера."""
|
||||||
|
|
||||||
self.json_container.check_presence(
|
self.json_container.check_visibility(
|
||||||
JsonContainerLocators.CONTAINER,
|
JsonContainerLocators.CONTAINER,
|
||||||
"Json container with license info is missing"
|
"Json container with license info is missing"
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -93,7 +93,7 @@ class MainPage(BasePage):
|
||||||
def should_be_navigation_panel(self) -> None:
|
def should_be_navigation_panel(self) -> None:
|
||||||
"""Проверяет наличие панели навигации."""
|
"""Проверяет наличие панели навигации."""
|
||||||
|
|
||||||
self.navigation_panel.check_presence(
|
self.navigation_panel.check_visibility(
|
||||||
NavigationPanelLocators.PANEL_MAIN,
|
NavigationPanelLocators.PANEL_MAIN,
|
||||||
"Navigation panel is missing"
|
"Navigation panel is missing"
|
||||||
)
|
)
|
||||||
|
|
@ -101,7 +101,7 @@ class MainPage(BasePage):
|
||||||
def should_be_user_button(self) -> None:
|
def should_be_user_button(self) -> None:
|
||||||
"""Проверяет наличие кнопки пользователя."""
|
"""Проверяет наличие кнопки пользователя."""
|
||||||
|
|
||||||
self.user_button.check_presence("User button is missing on event panel")
|
self.user_button.check_visibility("User button is missing on event panel")
|
||||||
|
|
||||||
def check_navigation_panel_verticall_scrolling(self) -> bool:
|
def check_navigation_panel_verticall_scrolling(self) -> bool:
|
||||||
"""Проверяет возможность вертикальной прокрутки панели.
|
"""Проверяет возможность вертикальной прокрутки панели.
|
||||||
|
|
|
||||||
|
|
@ -154,7 +154,8 @@ class ServiceStatusTab(BasePage):
|
||||||
AssertionError: Если таблица отсутствует.
|
AssertionError: Если таблица отсутствует.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
self.services_table.check_presence(
|
self.services_table.check_visibility(
|
||||||
TableLocators.TABLE_WORK_AREA,
|
TableLocators.TABLE_WORK_AREA,
|
||||||
"Service statuses table is missing"
|
"Service statuses table is missing"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -139,6 +139,7 @@ class SessionsTab(BasePage):
|
||||||
# Находим кнопку удаления сеанса и нажимаем на нее
|
# Находим кнопку удаления сеанса и нажимаем на нее
|
||||||
delete_session_button = self.get_delete_session_button_from_row(row_index)
|
delete_session_button = self.get_delete_session_button_from_row(row_index)
|
||||||
delete_session_button.click()
|
delete_session_button.click()
|
||||||
|
self.page.wait_for_timeout(1000)
|
||||||
|
|
||||||
# Подтверждаем удаление
|
# Подтверждаем удаление
|
||||||
self.delete_session_confirm.click_allow_button()
|
self.delete_session_confirm.click_allow_button()
|
||||||
|
|
@ -311,7 +312,7 @@ class SessionsTab(BasePage):
|
||||||
AssertionError: Если таблица отсутствует.
|
AssertionError: Если таблица отсутствует.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
self.sessions_table.check_presence(
|
self.sessions_table.check_visibility(
|
||||||
TableLocators.TABLE_WORK_AREA,
|
TableLocators.TABLE_WORK_AREA,
|
||||||
"Sessions table is missing"
|
"Sessions table is missing"
|
||||||
)
|
)
|
||||||
|
|
@ -335,7 +336,7 @@ class SessionsTab(BasePage):
|
||||||
self.wait_for_tooltip_to_disappear()
|
self.wait_for_tooltip_to_disappear()
|
||||||
|
|
||||||
delete_button = self.get_delete_session_button_from_row(row_index)
|
delete_button = self.get_delete_session_button_from_row(row_index)
|
||||||
delete_button.check_presence(
|
delete_button.check_visibility(
|
||||||
f"Delete session button is missing on {row_index} row"
|
f"Delete session button is missing on {row_index} row"
|
||||||
)
|
)
|
||||||
delete_button.check_tooltip_with_text(ButtonLocators.TOOLTIP, tooltip)
|
delete_button.check_tooltip_with_text(ButtonLocators.TOOLTIP, tooltip)
|
||||||
|
|
|
||||||
|
|
@ -293,10 +293,10 @@ class UsersTab(BasePage):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if self.toolbar.is_button_not_present("close"):
|
if self.toolbar.is_button_not_present("close"):
|
||||||
self.toolbar.check_button_presence("edit")
|
self.toolbar.check_button_visibility("edit")
|
||||||
self.toolbar.click_button("edit")
|
self.toolbar.click_button("edit")
|
||||||
|
|
||||||
self.toolbar.check_button_presence("add_user")
|
self.toolbar.check_button_visibility("add_user")
|
||||||
self.toolbar.click_button("add_user")
|
self.toolbar.click_button("add_user")
|
||||||
self.add_modal_window("add_local_user", "")
|
self.add_modal_window("add_local_user", "")
|
||||||
self.get_modal_window("add_local_user").check_by_window_title()
|
self.get_modal_window("add_local_user").check_by_window_title()
|
||||||
|
|
@ -441,7 +441,7 @@ class UsersTab(BasePage):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
self.toolbar.check_toolbar_presence("Toolbar is missing")
|
self.toolbar.check_toolbar_presence("Toolbar is missing")
|
||||||
self.toolbar.check_button_presence("edit")
|
self.toolbar.check_button_visibility("edit")
|
||||||
|
|
||||||
def should_be_toolbar_buttons(self) -> None:
|
def should_be_toolbar_buttons(self) -> None:
|
||||||
"""Проверяет наличие и функциональность кнопок тулбара.
|
"""Проверяет наличие и функциональность кнопок тулбара.
|
||||||
|
|
@ -450,17 +450,17 @@ class UsersTab(BasePage):
|
||||||
AssertionError: Если кнопки недоступны или подсказки неверны.
|
AssertionError: Если кнопки недоступны или подсказки неверны.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
self.toolbar.check_button_presence("edit")
|
self.toolbar.check_button_visibility("edit")
|
||||||
self.toolbar.check_button_tooltip("edit", "Редактировать")
|
self.toolbar.check_button_tooltip("edit", "Редактировать")
|
||||||
|
|
||||||
self.toolbar.get_button_by_name("edit").click()
|
self.toolbar.get_button_by_name("edit").click()
|
||||||
self.toolbar.check_button_presence("add_user")
|
self.toolbar.check_button_visibility("add_user")
|
||||||
self.toolbar.check_button_presence("close")
|
self.toolbar.check_button_visibility("close")
|
||||||
self.toolbar.check_button_tooltip("add_user", "Добавить")
|
self.toolbar.check_button_tooltip("add_user", "Добавить")
|
||||||
self.toolbar.check_button_tooltip("close", "Закрыть")
|
self.toolbar.check_button_tooltip("close", "Закрыть")
|
||||||
|
|
||||||
self.toolbar.get_button_by_name("close").click()
|
self.toolbar.get_button_by_name("close").click()
|
||||||
self.toolbar.check_button_presence("edit")
|
self.toolbar.check_button_visibility("edit")
|
||||||
|
|
||||||
def should_be_users_table(self) -> None:
|
def should_be_users_table(self) -> None:
|
||||||
"""Проверяет наличие таблицы пользователей.
|
"""Проверяет наличие таблицы пользователей.
|
||||||
|
|
@ -469,7 +469,7 @@ class UsersTab(BasePage):
|
||||||
AssertionError: Если таблица отсутствует.
|
AssertionError: Если таблица отсутствует.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
self.users_table.check_presence(
|
self.users_table.check_visibility(
|
||||||
TableLocators.TABLE_WORK_AREA,
|
TableLocators.TABLE_WORK_AREA,
|
||||||
"Users table is missing"
|
"Users table is missing"
|
||||||
)
|
)
|
||||||
|
|
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -50,7 +50,7 @@ class TestUsersModalWindow:
|
||||||
assert is_scrollable_vertically, "Should be vertical scrolling"
|
assert is_scrollable_vertically, "Should be vertical scrolling"
|
||||||
|
|
||||||
modal_window.scroll_window_down()
|
modal_window.scroll_window_down()
|
||||||
modal_window.check_button_presence("close")
|
modal_window.check_button_visibility("close")
|
||||||
ut.wait_for_timeout(3000)
|
ut.wait_for_timeout(3000)
|
||||||
|
|
||||||
modal_window.scroll_window_up()
|
modal_window.scroll_window_up()
|
||||||
|
|
@ -84,7 +84,7 @@ class TestUsersModalWindow:
|
||||||
assert is_scrollable_vertically, "Should be vertical scrolling"
|
assert is_scrollable_vertically, "Should be vertical scrolling"
|
||||||
|
|
||||||
modal_window.scroll_window_down()
|
modal_window.scroll_window_down()
|
||||||
modal_window.check_button_presence("close")
|
modal_window.check_button_visibility("close")
|
||||||
ut.wait_for_timeout(3000)
|
ut.wait_for_timeout(3000)
|
||||||
|
|
||||||
modal_window.scroll_window_up()
|
modal_window.scroll_window_up()
|
||||||
|
|
|
||||||
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue