Добавлен новый компонент components_derived/modal_view_ztp_template

Radislav 2025-10-14 12:49:20 +03:00
parent c747802c86
commit 3417feb4be
4 changed files with 204 additions and 127 deletions

View File

@ -7,7 +7,6 @@
import re import re
from playwright.sync_api import Page from playwright.sync_api import Page
from tools.logger import get_logger from tools.logger import get_logger
from locators.modal_window_locators import ModalWindowLocators
from components.modal_window_component import ModalWindowComponent from components.modal_window_component import ModalWindowComponent
@ -19,16 +18,15 @@ class ViewTemplateModalWindow(ModalWindowComponent):
Наследует ModalWindowComponent и добавляет функционал для: Наследует ModalWindowComponent и добавляет функционал для:
1. Инициализации модального окна с конкретным шаблоном 1. Инициализации модального окна с конкретным шаблоном
2. Закрытия модального окна 2. Закрытия модального окна через тулбар
3. Получения конфигурационных данных шаблона 3. Проверки содержимого модального окна
4. Проверки содержимого модального окна
""" """
def __init__(self, page: Page, title: str): def __init__(self, page: Page, title: str):
"""Инициализирует элементы формы модального окна шаблона.""" """Инициализирует элементы формы модального окна шаблона."""
super().__init__(page) super().__init__(page)
# Настройка заголовка и кнопок закрытия # Настройка заголовка и кнопки закрытия
self.window_title = title self.window_title = title
locator_button_toolbar_close = self.page.get_by_role("navigation").filter( locator_button_toolbar_close = self.page.get_by_role("navigation").filter(
has_text=re.compile(self.window_title) has_text=re.compile(self.window_title)
@ -37,14 +35,6 @@ class ViewTemplateModalWindow(ModalWindowComponent):
self.add_toolbar_title(self.window_title) self.add_toolbar_title(self.window_title)
self.add_toolbar_button(locator_button_toolbar_close, "close") self.add_toolbar_button(locator_button_toolbar_close, "close")
locator_button_close = self.page.get_by_role("button", name="Закрыть")
self.add_button(locator_button_close, "close")
def close_window(self) -> None:
"""Закрывает окно через кнопку 'Закрыть'."""
close_button = self.get_button_by_name("close")
close_button.click()
def close_window_by_toolbar_button(self): def close_window_by_toolbar_button(self):
"""Закрывает окно через кнопку в тулбаре.""" """Закрывает окно через кнопку в тулбаре."""
self.click_toolbar_close_button() self.click_toolbar_close_button()
@ -60,108 +50,3 @@ class ViewTemplateModalWindow(ModalWindowComponent):
self.check_by_window_title() self.check_by_window_title()
self.check_toolbar_button_visibility("close") self.check_toolbar_button_visibility("close")
self.check_toolbar_button_tooltip("close", "Закрыть") self.check_toolbar_button_tooltip("close", "Закрыть")
def get_modal_window_data(self) -> dict:
"""Извлекает данные из модального окна шаблона и структурирует по кодам и значениям.
Returns:
dict: Данные в формате {'код': 'значение'} как в API
"""
modal_data = {}
# Получаем все значения из input полей
input_locator = self.get_locator(ModalWindowLocators.MODAL_WINDOW_TEXT_FIELD_INPUT)
# Проверка наличия элементов
input_count = input_locator.count()
if input_count == 0:
logger.warning("Поля ввода не найдены в модальном окне")
return modal_data
all_values = []
# Обрабатываем каждое поле с обработкой возможных ошибок
for i in range(input_count):
input_field = input_locator.nth(i)
# Проверяем, что элемент видим и доступен
if not input_field.is_visible():
logger.debug("Поле %s не видимо, пропускаем", i)
continue
# Получаем значение с обработкой возможных ошибок состояния элемента
if input_field.is_visible():
value = input_field.input_value().strip()
if value: # Игнорируем пустые значения
all_values.append(value)
else:
logger.debug("Поле %s стало невидимым после проверки, пропускаем", i)
logger.info("Все значения из полей: %s", all_values)
# Анализируем пары код-значение
i = 0
while i < len(all_values) - 1:
current_value = all_values[i]
next_value = all_values[i + 1]
# Определяем, является ли текущее значение кодом (число)
if current_value.isdigit():
# Текущее значение - код, следующее - значение
modal_data[current_value] = next_value
i += 2 # Перескакиваем через пару
else:
# Если текущее значение не число, ищем следующую пару
i += 1
# Добавляем имя шаблона с ключом 'Шаблон' вместо 'template'
if all_values:
modal_data['Шаблон'] = all_values[-1]
logger.info("Структурированные данные из модального окна: %s", modal_data)
return modal_data
def compare_modal_with_api_data(self, modal_data: dict, api_data: dict,
title: str) -> None:
"""Сравнивает данные из модального окна с данными из API."""
errors = []
# Создаем копию API данных с заменой 'template' на 'Шаблон'
api_data_adapted = api_data.copy()
if 'template' in api_data_adapted:
api_data_adapted['Шаблон'] = api_data_adapted.pop('template')
# Сравниваем все поля
for code, expected_value in api_data_adapted.items():
if code in modal_data:
actual_value = modal_data[code]
if actual_value != expected_value:
error_msg = (
f"Расхождение для кода {code}: "
f"модальное окно='{actual_value}', API='{expected_value}'"
)
logger.error(error_msg)
errors.append(error_msg)
else:
error_msg = f"Код {code} не найден в модальном окне"
logger.error(error_msg)
errors.append(error_msg)
# Дополнительная проверка имени шаблона
modal_template = modal_data.get('Шаблон', '')
if modal_template != title:
error_msg = (
f"Расхождение в имени шаблона: "
f"модальное окно='{modal_template}', ожидается='{title}'"
)
logger.error(error_msg)
errors.append(error_msg)
# Если есть расхождения, выбрасываем ошибку
if errors:
error_details = "\n".join(errors)
assert False, (
f"Обнаружены расхождения для шаблона '{title}':\n{error_details}"
)
logger.info("Данные модального окна соответствуют API для шаблона '%s'", title)

View File

@ -0,0 +1,192 @@
"""Модуль modal_view_ztp_template содержит класс для работы с модальным окном шаблона ZTP.
Класс ViewZTPTemplateModalWindow наследует базовый функционал ModalWindowComponent
и реализует методы просмотра модального окна шаблона Zero Touch Provisioning.
"""
import re
from playwright.sync_api import Page
from tools.logger import get_logger
from locators.modal_window_locators import ModalWindowLocators
from components.modal_window_component import ModalWindowComponent
logger = get_logger("VIEW_ZTP_TEMPLATE_MODAL_WINDOW")
class ViewZTPTemplateModalWindow(ModalWindowComponent):
"""Модальное окно шаблона Zero Touch Provisioning.
Наследует ModalWindowComponent и добавляет функционал для:
1. Инициализации модального окна с конкретным шаблоном ZTP
2. Закрытия модального окна
3. Получения конфигурационных данных шаблона ZTP
4. Проверки содержимого модального окна
5. Сравнения данных с API специфичными для ZTP
"""
def __init__(self, page: Page, title: str):
"""Инициализирует элементы формы модального окна шаблона ZTP."""
super().__init__(page)
# Настройка заголовка и кнопок закрытия
self.window_title = title
locator_button_toolbar_close = self.page.get_by_role("navigation").filter(
has_text=re.compile(self.window_title)
).get_by_role("button")
self.add_toolbar_title(self.window_title)
self.add_toolbar_button(locator_button_toolbar_close, "close")
locator_button_close = self.page.get_by_role("button", name="Закрыть")
self.add_button(locator_button_close, "close")
def close_window(self) -> None:
"""Закрывает окно через кнопку 'Закрыть'."""
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) -> None:
"""Проверяет наличие и корректность элементов окна ZTP шаблона.
Проверяет:
1. Наличие заголовка окна с именем шаблона
2. Видимость кнопки закрытия
3. Подсказку кнопки закрытия
4. Наличие специфичных полей для ZTP
"""
self.check_by_window_title()
self.check_toolbar_button_visibility("close")
self.check_toolbar_button_tooltip("close", "Закрыть")
def get_modal_window_data(self) -> dict:
"""Извлекает данные из модального окна шаблона ZTP и структурирует по кодам и значениям.
Returns:
dict: Данные в формате {'код': 'значение'} как в API ZTP
"""
modal_data = {}
# Получаем все значения из input полей
input_locator = self.get_locator(ModalWindowLocators.MODAL_WINDOW_TEXT_FIELD_INPUT)
# Проверка наличия элементов
input_count = input_locator.count()
if input_count == 0:
logger.warning("Поля ввода не найдены в модальном окне ZTP")
return modal_data
all_values = []
# Обрабатываем каждое поле с обработкой возможных ошибок
for i in range(input_count):
input_field = input_locator.nth(i)
# Проверяем, что элемент видим и доступен
if not input_field.is_visible():
logger.debug("Поле %s не видимо, пропускаем", i)
continue
# Получаем значение с обработкой возможных ошибок состояния элемента
if input_field.is_visible():
value = input_field.input_value().strip()
if value: # Игнорируем пустые значения
all_values.append(value)
else:
logger.debug("Поле %s стало невидимым после проверки, пропускаем", i)
logger.info("Все значения из полей ZTP шаблона: %s", all_values)
# Анализируем пары код-значение для ZTP формата
i = 0
while i < len(all_values) - 1:
current_value = all_values[i]
next_value = all_values[i + 1]
# Для ZTP шаблонов могут быть как числовые коды, так и строковые идентификаторы
if current_value.isdigit() or self._is_ztp_field_code(current_value):
# Текущее значение - код, следующее - значение
modal_data[current_value] = next_value
i += 2 # Перескакиваем через пару
else:
# Если текущее значение не подходит как код, ищем следующую пару
i += 1
# Добавляем имя шаблона с ключом 'template'
if all_values:
modal_data['template'] = all_values[-1]
logger.info("Структурированные данные из модального окна ZTP: %s", modal_data)
return modal_data
def _is_ztp_field_code(self, value: str) -> bool:
"""Проверяет, является ли значение кодом поля ZTP.
Args:
value: Проверяемое значение
Returns:
bool: True если значение похоже на код поля ZTP
"""
ztp_field_patterns = [
'vendorCode',
'authentication',
'deviceType',
'authenticationOption',
'manufacturer'
]
return any(pattern.lower() in value.lower() for pattern in ztp_field_patterns)
def compare_modal_with_api_data(self, modal_data: dict, api_data: dict,
title: str) -> None:
"""Сравнивает данные из модального окна ZTP с данными из API.
Args:
modal_data: Данные из модального окна
api_data: Данные из API ответа
title: Имя шаблона для проверки
"""
errors = []
# Для ZTP API данные уже содержат нужные ключи
api_data_adapted = api_data.copy()
# Сравниваем все поля
for code, expected_value in api_data_adapted.items():
if code in modal_data:
actual_value = modal_data[code]
if str(actual_value) != str(expected_value):
error_msg = (
f"Расхождение для поля {code}: "
f"модальное окно='{actual_value}', API='{expected_value}'"
)
logger.error(error_msg)
errors.append(error_msg)
else:
error_msg = f"Поле {code} не найдено в модальном окне ZTP"
logger.error(error_msg)
errors.append(error_msg)
# Дополнительная проверка имени шаблона
modal_template = modal_data.get('template', '')
if modal_template != title:
error_msg = (
f"Расхождение в имени шаблона ZTP: "
f"модальное окно='{modal_template}', ожидается='{title}'"
)
logger.error(error_msg)
errors.append(error_msg)
# Если есть расхождения, выбрасываем ошибку
if errors:
error_details = "\n".join(errors)
assert False, (
f"Обнаружены расхождения для ZTP шаблона '{title}':\n{error_details}"
)
logger.info("Данные модального окна ZTP соответствуют API для шаблона '%s'", title)

View File

@ -8,7 +8,7 @@ from playwright.sync_api import Page
from tools.logger import get_logger from tools.logger import get_logger
from locators.table_locators import TableLocators from locators.table_locators import TableLocators
from locators.modal_window_locators import ModalWindowLocators from locators.modal_window_locators import ModalWindowLocators
from components_derived.modal_view_template import ViewTemplateModalWindow from components_derived.modal_view_ztp_template import ViewZTPTemplateModalWindow
from components.modal_window_component import ModalWindowComponent from components.modal_window_component import ModalWindowComponent
from components.toolbar_component import ToolbarComponent from components.toolbar_component import ToolbarComponent
from components.table_component import TableComponent from components.table_component import TableComponent
@ -44,16 +44,16 @@ class ZTPTemplatesTab(BasePage):
Args: Args:
title: Заголовок окна. title: Заголовок окна.
""" """
self.modal_windows[title] = ViewTemplateModalWindow(self.page, title) self.modal_windows[title] = ViewZTPTemplateModalWindow(self.page, title)
def get_modal_window(self, title: str) -> ViewTemplateModalWindow: def get_modal_window(self, title: str) -> ViewZTPTemplateModalWindow:
"""Возвращает модальное окно по заголовку. """Возвращает модальное окно по заголовку.
Args: Args:
title: Заголовок окна. title: Заголовок окна.
Returns: Returns:
ViewTemplateModalWindow: Экземпляр модального окна шаблона. ViewZTPTemplateModalWindow: Экземпляр модального окна шаблона.
Raises: Raises:
AssertionError: Если окно не найдено. AssertionError: Если окно не найдено.
@ -92,7 +92,7 @@ class ZTPTemplatesTab(BasePage):
row_locator.click() row_locator.click()
# Создаем временный экземпляр модального окна для получения заголовка # Создаем временный экземпляр модального окна для получения заголовка
temp_modal = ViewTemplateModalWindow(self.page, "") temp_modal = ViewZTPTemplateModalWindow(self.page, "")
title = temp_modal.toolbar.get_toolbar_title_text( title = temp_modal.toolbar.get_toolbar_title_text(
ModalWindowLocators.MODAL_WINDOW_TITLE ModalWindowLocators.MODAL_WINDOW_TITLE
) )
@ -150,7 +150,7 @@ class ZTPTemplatesTab(BasePage):
temp_modal = ModalWindowComponent(self.page) temp_modal = ModalWindowComponent(self.page)
temp_modal.scroll_window_down() temp_modal.scroll_window_down()
def check_templates_modal_content(self, title: str) -> None: def check_ztp_templates_modal_content(self, title: str) -> None:
"""Проверяет наличие и корректность элементов модального окна шаблона. """Проверяет наличие и корректность элементов модального окна шаблона.
Args: Args:
@ -162,7 +162,7 @@ class ZTPTemplatesTab(BasePage):
modal_window = self.get_modal_window(title) modal_window = self.get_modal_window(title)
modal_window.check_content() modal_window.check_content()
def check_templates_table_content(self) -> None: def check_ztp_templates_table_content(self) -> None:
"""Проверяет содержимое таблицы шаблонов. """Проверяет содержимое таблицы шаблонов.
Проверяет заголовки и наличие данных в таблице. Проверяет заголовки и наличие данных в таблице.

View File

@ -75,7 +75,7 @@ class TestZTPTemplatesTab:
browser.wait_for_timeout(5000) browser.wait_for_timeout(5000)
# Проверка содержимого таблицы шаблонов # Проверка содержимого таблицы шаблонов
ztp_templates_tab.check_templates_table_content() ztp_templates_tab.check_ztp_templates_table_content()
#@pytest.mark.skip(reason=" Временно исключено из тестирования") #@pytest.mark.skip(reason=" Временно исключено из тестирования")
def test_templates_table_row_highlighting(self, browser: Page) -> None: def test_templates_table_row_highlighting(self, browser: Page) -> None:
@ -226,7 +226,7 @@ class TestZTPTemplatesTab:
ztp_templates_tab.should_be_modal_window() ztp_templates_tab.should_be_modal_window()
# Проверка содержимого модального окна # Проверка содержимого модального окна
ztp_templates_tab.check_templates_modal_content(title) ztp_templates_tab.check_ztp_templates_modal_content(title)
# Закрытие модального окна через кнопку 'Закрыть' # Закрытие модального окна через кнопку 'Закрыть'
ztp_templates_tab.close_modal_window(title) ztp_templates_tab.close_modal_window(title)