e-nms_qa_automation/components/dynamic_form_component.py

152 lines
6.1 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# components/dynamic_form_component.py
"""Универсальный компонент для работы с динамическими формами."""
from typing import Optional, Dict, List, Any
from playwright.sync_api import Page, Locator
from tools.logger import get_logger
logger = get_logger("DYNAMIC_FORM_COMPONENT")
class DynamicFormComponent:
"""Компонент для работы с формами, находит поля по меткам."""
def __init__(self, page: Page, form_selector: str = "form, .v-form"):
self.page = page
self.form_selector = form_selector
self._form_container = None
self._field_labels_cache = {}
def _get_form_container(self) -> Locator:
"""Получает контейнер формы."""
if self._form_container is None:
container = self.page.locator(self.form_selector)
try:
container.wait_for(state="visible", timeout=5000)
self._form_container = container
except:
raise ValueError(f"Form container not found: {self.form_selector}")
return self._form_container
def get_all_field_labels(self) -> List[str]:
"""Получает все метки полей в форме."""
self._load_field_labels()
return list(self._field_labels_cache.keys())
def _load_field_labels(self) -> None:
"""Загружает метки полей формы."""
if self._field_labels_cache:
return
form = self._get_form_container()
labels = {}
# Ищем все элементы с текстом, которые могут быть метками
# Адаптируйте селекторы под вашу структуру DOM
label_elements = form.locator(
".v-label, label, .field-label, [class*='label']"
)
for i in range(label_elements.count()):
elem = label_elements.nth(i)
label_text = elem.text_content().strip()
if label_text and len(label_text) < 100: # Исключаем большие тексты
labels[label_text] = elem
self._field_labels_cache = labels
def get_field_by_label(self, label_text: str) -> Optional[Locator]:
"""Находит поле по метке."""
self._load_field_labels()
# Прямое совпадение
if label_text in self._field_labels_cache:
return self._get_field_input(self._field_labels_cache[label_text])
# Частичное совпадение
for label, element in self._field_labels_cache.items():
if label_text in label or label in label_text:
return self._get_field_input(element)
logger.warning(f"Поле с меткой '{label_text}' не найдено")
return None
def _get_field_input(self, label_element: Locator) -> Optional[Locator]:
"""Получает элемент ввода рядом с меткой."""
# Разные стратегии поиска input элемента
strategies = [
lambda: label_element.locator("+ input, + textarea").first,
lambda: label_element.locator("../..").locator("input, textarea").first,
lambda: self.page.locator(f"input[aria-label*='{label_element.text_content()}']"),
lambda: self.page.locator(f"input[placeholder*='{label_element.text_content()}']"),
]
for strategy in strategies:
try:
input_elem = strategy()
if input_elem.count() > 0:
return input_elem
except:
continue
return None
def get_field_type_by_label(self, label_text: str) -> str:
"""Определяет тип поля по метке."""
field_element = self.get_field_by_label(label_text)
if not field_element:
return "unknown"
# Определяем тип по атрибутам
input_type = field_element.get_attribute("type")
role = field_element.get_attribute("role")
if input_type == "checkbox" or role == "checkbox":
return "checkbox"
elif role == "combobox" or field_element.get_attribute("aria-haspopup") == "listbox":
return "combobox"
else:
return "text"
def fill_field_by_label(self, label_text: str, value: Any) -> bool:
"""Заполняет поле по метке."""
field_type = self.get_field_type_by_label(label_text)
if field_type == "text":
return self._fill_text_field_by_label(label_text, str(value))
elif field_type == "combobox":
return self._fill_combobox_by_label(label_text, str(value))
elif field_type == "checkbox":
return self._set_checkbox_by_label(label_text, bool(value))
else:
logger.warning(f"Неизвестный тип поля для '{label_text}'")
return False
def _fill_text_field_by_label(self, label_text: str, value: str) -> bool:
"""Заполняет текстовое поле по метке."""
field = self.get_field_by_label(label_text)
if not field:
return False
try:
field.click()
field.fill("")
field.fill(value)
# Проверяем результат
actual_value = field.input_value()
if actual_value == value:
logger.debug(f"✓ Заполнено поле '{label_text}': '{value}'")
return True
else:
logger.warning(f"Несоответствие значения для '{label_text}'")
return False
except Exception as e:
logger.error(f"Ошибка при заполнении поля '{label_text}': {e}")
return False
def _fill_combobox_by_label(self, label_text: str, value: str) -> bool:
"""Заполняет combobox по метке."""
# Реализация аналогичная modal_rack_edit.py
# ...