650 lines
27 KiB
Python
650 lines
27 KiB
Python
"""Модуль для работы с формой редактирования стойки в модальном окне."""
|
||
|
||
import time
|
||
from dataclasses import dataclass
|
||
from typing import Optional, List, Dict, Any
|
||
from playwright.sync_api import Page
|
||
from tools.logger import get_logger
|
||
from locators.rack_locators import RackLocators
|
||
from elements.text_input_element import TextInput
|
||
from components.base_component import BaseComponent
|
||
from components.dropdown_list_component import DropdownList
|
||
|
||
|
||
logger = get_logger("EDIT_RACK_FORM")
|
||
logger.setLevel("INFO")
|
||
|
||
|
||
@dataclass
|
||
class EditRackFormData:
|
||
"""Класс для хранения данных редактируемой стойки."""
|
||
|
||
# Основные поля
|
||
name: str = ""
|
||
serial: str = ""
|
||
inventory: str = ""
|
||
comment: str = ""
|
||
allocated_power: str = ""
|
||
|
||
# Combobox поля
|
||
cable_entry: str = ""
|
||
state: str = ""
|
||
depth: str = ""
|
||
usize: str = ""
|
||
|
||
# Combobox поля (не заполняемые)
|
||
owner: str = ""
|
||
service_org: str = ""
|
||
project: str = ""
|
||
|
||
# Checkbox поле
|
||
ventilation_panel: Optional[bool] = None
|
||
|
||
|
||
class EditRackForm(BaseComponent):
|
||
"""Компонент для работы с формой редактирования стойки в модальном окне."""
|
||
|
||
# Маппинг текстовых полей
|
||
TEXT_FIELDS_MAPPING = {
|
||
"Имя": ("name", "name_input"),
|
||
"Комментарий": ("comment", "comment_input"),
|
||
"Серийный номер": ("serial", "serial_input"),
|
||
"Инвентарный номер": ("inventory", "inventory_input"),
|
||
"Выделенная мощность (Вт/ВА)": ("allocated_power", "power_input"),
|
||
}
|
||
|
||
# Маппинг полей для заполнения combobox полей
|
||
COMBOBOX_FIELDS_MAPPING = {
|
||
"Ввод кабеля": ("cable_entry", "cable_entry_input", "cable_entry_list"),
|
||
"Состояние": ("state", "state_input", "state_list"),
|
||
"Глубина (мм)": ("depth", "depth_input", "depth_list"),
|
||
"Высота в юнитах": ("usize", "usize_input", "usize_list"),
|
||
"Владелец": ("owner", "owner_input", "owner_list"),
|
||
"Обслуживающая организация": ("service_org", "service_input", "service_list"),
|
||
"Проект/Титул": ("project", "project_input", "project_list")
|
||
}
|
||
|
||
# Локаторы для текстовых полей (из RackLocators)
|
||
TEXT_FIELDS_LOCATORS = {
|
||
"Имя": RackLocators.EDIT_RACK_FORM_FIELD_NAME,
|
||
"Комментарий": RackLocators.EDIT_RACK_FORM_FIELD_COMMENT,
|
||
"Серийный номер": RackLocators.EDIT_RACK_FORM_FIELD_SERIAL,
|
||
"Инвентарный номер": RackLocators.EDIT_RACK_FORM_FIELD_INVENTORY,
|
||
"Выделенная мощность (Вт/ВА)": RackLocators.EDIT_RACK_FORM_FIELD_POWER,
|
||
}
|
||
|
||
# Локаторы для combobox полей (из RackLocators)
|
||
COMBOBOX_FIELDS_LOCATORS = {
|
||
"Ввод кабеля": RackLocators.EDIT_RACK_FORM_SELECT_CABLE_INPUT,
|
||
"Состояние": RackLocators.EDIT_RACK_FORM_SELECT_CONDITION_TYPE,
|
||
"Глубина (мм)": RackLocators.EDIT_RACK_FORM_SELECT_DEPTH,
|
||
"Высота в юнитах": RackLocators.EDIT_RACK_FORM_SELECT_USIZE,
|
||
"Владелец": RackLocators.EDIT_RACK_FORM_SELECT_OWNER,
|
||
"Обслуживающая организация": RackLocators.EDIT_RACK_FORM_SELECT_SERVICE_PROVIDER,
|
||
"Проект/Титул": RackLocators.EDIT_RACK_FORM_SELECT_PROJECT,
|
||
}
|
||
|
||
# Локатор для чекбокса вентиляционной панели
|
||
CHECKBOX_VENTILATION = RackLocators.EDIT_RACK_FORM_CHECKBOX_VENTILATION
|
||
|
||
def __init__(self, page: Page) -> None:
|
||
"""Инициализирует компонент формы редактирования стойки.
|
||
|
||
Args:
|
||
page: Экземпляр страницы Playwright
|
||
"""
|
||
|
||
super().__init__(page)
|
||
self.page = page
|
||
self.content_items = {}
|
||
self.available_fields = None
|
||
|
||
# Инициализация полей формы
|
||
self._init_form_fields()
|
||
|
||
def _init_form_fields(self) -> None:
|
||
"""Инициализирует все поля формы редактирования."""
|
||
|
||
# Получаем доступные поля формы
|
||
container_locator = self.page.locator(RackLocators.EDIT_RACK_FORM)
|
||
self.available_fields = self.get_input_fields_locators(container_locator)
|
||
|
||
self._init_text_fields()
|
||
self._init_combobox_fields()
|
||
self._init_checkbox_fields()
|
||
|
||
def _init_text_fields(self) -> None:
|
||
"""Инициализирует текстовые поля формы."""
|
||
|
||
for field_label, (attr_name, widget_name) in self.TEXT_FIELDS_MAPPING.items():
|
||
locator = self.TEXT_FIELDS_LOCATORS.get(field_label)
|
||
if not locator:
|
||
continue
|
||
|
||
self._init_single_text_field(field_label, locator, widget_name)
|
||
|
||
def _init_single_text_field(self, field_label: str, locator: str, widget_name: str) -> None:
|
||
"""Инициализирует одно текстовое поле.
|
||
|
||
Args:
|
||
field_label: Метка поля
|
||
locator: Локатор поля
|
||
widget_name: Имя виджета
|
||
"""
|
||
|
||
try:
|
||
element = self.page.locator(locator).first
|
||
if element.count() > 0 and element.is_visible():
|
||
# Создаем TextInput для поля
|
||
field_input = TextInput(self.page, element, widget_name)
|
||
self.content_items[widget_name] = field_input
|
||
logger.debug(f"Initialized text field: '{field_label}'")
|
||
except Exception as e:
|
||
logger.error(f"Error initializing text field '{field_label}': {e}")
|
||
|
||
def _init_combobox_fields(self) -> None:
|
||
"""Инициализирует combobox поля формы."""
|
||
|
||
for field_label, (attr_name, input_name, list_name) in self.COMBOBOX_FIELDS_MAPPING.items():
|
||
locator = self.COMBOBOX_FIELDS_LOCATORS.get(field_label)
|
||
if not locator:
|
||
continue
|
||
|
||
self._init_single_combobox_field(field_label, locator, input_name, list_name)
|
||
|
||
def _init_single_combobox_field(
|
||
self, field_label: str, locator: str, input_name: str, list_name: str
|
||
) -> None:
|
||
"""Инициализирует одно combobox поле.
|
||
|
||
Args:
|
||
field_label: Метка поля
|
||
locator: Локатор поля
|
||
input_name: Имя поля ввода
|
||
list_name: Имя списка
|
||
"""
|
||
|
||
try:
|
||
element = self.page.locator(locator).first
|
||
if element.count() > 0 and element.is_visible():
|
||
# Для combobox создаем TextInput для клика
|
||
field_input = TextInput(self.page, element, input_name)
|
||
self.content_items[input_name] = field_input
|
||
# Добавляем DropdownList для выбора значений
|
||
self.content_items[list_name] = DropdownList(self.page)
|
||
logger.debug(f"Initialized combobox field: '{field_label}'")
|
||
except Exception as e:
|
||
logger.error(f"Error initializing combobox field '{field_label}': {e}")
|
||
|
||
def _init_checkbox_fields(self) -> None:
|
||
"""Инициализирует checkbox поля формы."""
|
||
|
||
try:
|
||
self._init_ventilation_checkbox()
|
||
except Exception as e:
|
||
logger.error(f"Error initializing checkbox: {e}")
|
||
|
||
def _init_ventilation_checkbox(self) -> None:
|
||
"""Инициализирует чекбокс вентиляционной панели."""
|
||
|
||
checkbox_input = self.page.locator(self.CHECKBOX_VENTILATION).first
|
||
|
||
if checkbox_input.count() == 0:
|
||
logger.debug("Ventilation panel checkbox not found")
|
||
return
|
||
|
||
# Импортируем Checkbox только здесь чтобы избежать циклических импортов
|
||
from elements.checkbox_element import Checkbox
|
||
|
||
checkbox = Checkbox(self.page, checkbox_input, "ventilation_panel")
|
||
self.content_items["ventilation_checkbox"] = checkbox
|
||
|
||
logger.debug("Initialized ventilation panel checkbox")
|
||
|
||
def clear_field(self, field_name: str) -> None:
|
||
"""Очищает указанное поле.
|
||
|
||
Args:
|
||
field_name: Название поля для очистки
|
||
"""
|
||
|
||
logger.debug(f"Clearing field: '{field_name}'")
|
||
|
||
# Проверяем, не является ли поле чекбоксом
|
||
if field_name == "Вентиляционная панель":
|
||
logger.debug(f"Field '{field_name}' is a checkbox, skipping clear operation")
|
||
return
|
||
|
||
# Получаем локатор поля
|
||
locator = None
|
||
if field_name in self.COMBOBOX_FIELDS_LOCATORS:
|
||
locator = self.COMBOBOX_FIELDS_LOCATORS[field_name]
|
||
elif field_name in self.TEXT_FIELDS_LOCATORS:
|
||
locator = self.TEXT_FIELDS_LOCATORS[field_name]
|
||
else:
|
||
logger.warning(f"Unknown field: {field_name}")
|
||
return
|
||
|
||
field_element = self.page.locator(locator).first
|
||
|
||
if field_element.count() == 0:
|
||
logger.debug(f"Field '{field_name}' not found")
|
||
return
|
||
|
||
# Для текстовых полей
|
||
if field_name in self.TEXT_FIELDS_LOCATORS:
|
||
try:
|
||
field_element.click()
|
||
field_element.page.keyboard.press("Control+A")
|
||
field_element.page.keyboard.press("Backspace")
|
||
self.wait_for_timeout(200)
|
||
logger.debug(f"Text field '{field_name}' cleared")
|
||
except Exception as e:
|
||
logger.debug(f"Could not clear text field '{field_name}': {e}")
|
||
return
|
||
|
||
# Для combobox полей
|
||
if field_name in self.COMBOBOX_FIELDS_LOCATORS:
|
||
# Поднимаемся до родительского контейнера
|
||
parent_container = field_element.locator(
|
||
"xpath=ancestor::div[contains(@class, 'v-input')]"
|
||
).first
|
||
|
||
if parent_container.count() == 0:
|
||
logger.debug(f"Parent container not found for field '{field_name}'")
|
||
return
|
||
|
||
# Ищем кнопку очистки (крестик)
|
||
clear_button = parent_container.locator(
|
||
".v-input__icon--clear button, .v-input__icon--append button, i.mdi-close-circle, i.mdi-close"
|
||
).first
|
||
|
||
if clear_button.count() > 0 and clear_button.is_visible():
|
||
clear_button.click()
|
||
self.wait_for_timeout(300)
|
||
logger.debug(f"Combobox field '{field_name}' cleared")
|
||
else:
|
||
logger.debug(f"Clear button not found for field '{field_name}'")
|
||
|
||
def get_content_item(self, item_name: str) -> Any:
|
||
"""Возвращает элемент контента по имени.
|
||
|
||
Args:
|
||
item_name: Имя элемента
|
||
|
||
Returns:
|
||
Элемент или None если не найден
|
||
"""
|
||
return self.content_items.get(item_name)
|
||
|
||
def _scroll_to_element_in_dropdown(self, value: str) -> bool:
|
||
"""Скроллит выпадающий список до элемента с нужным текстом используя playwright.
|
||
|
||
Args:
|
||
value: Текст для поиска
|
||
|
||
Returns:
|
||
bool: True если элемент найден, False в противном случае
|
||
"""
|
||
|
||
logger.debug(f"Scrolling to find element with text: '{value}'")
|
||
|
||
# Получаем активное выпадающее меню
|
||
dropdown_menu = self.page.locator("div.menuable__content__active").first
|
||
|
||
if dropdown_menu.count() == 0:
|
||
logger.error("Active dropdown menu not found")
|
||
return False
|
||
|
||
max_attempts = 10
|
||
attempts = 0
|
||
|
||
while attempts < max_attempts:
|
||
# Получаем все видимые элементы списка
|
||
visible_items = dropdown_menu.locator("a.v-list__tile, div[role='listitem']").all()
|
||
|
||
if visible_items:
|
||
# Проверяем каждый видимый элемент
|
||
for item in visible_items:
|
||
item_text = item.text_content() or ""
|
||
if value in item_text:
|
||
logger.debug(f"Found element with text '{value}'")
|
||
# Скроллим до элемента
|
||
item.scroll_into_view_if_needed()
|
||
self.wait_for_timeout(300)
|
||
return True
|
||
|
||
# Если элемент не найден, скроллим до последнего видимого элемента
|
||
last_item = visible_items[-1]
|
||
last_item_text = last_item.text_content() or ""
|
||
logger.debug(f"Scrolling to last visible item: '{last_item_text}'")
|
||
last_item.scroll_into_view_if_needed()
|
||
self.wait_for_timeout(500)
|
||
else:
|
||
# Если нет видимых элементов, скроллим вниз
|
||
dropdown_menu.evaluate("(el) => el.scrollTop += 200")
|
||
self.wait_for_timeout(300)
|
||
|
||
attempts += 1
|
||
logger.debug(f"Scroll attempt {attempts}/{max_attempts}")
|
||
|
||
logger.warning(f"Element with text '{value}' not found after {max_attempts} scroll attempts")
|
||
return False
|
||
|
||
def fill_rack_data(self, rack_data: EditRackFormData) -> Dict[str, int]:
|
||
"""Заполняет поля формы редактирования стойки.
|
||
|
||
Args:
|
||
rack_data: Данные для заполнения
|
||
|
||
Returns:
|
||
Словарь с результатами заполнения
|
||
"""
|
||
results = {
|
||
"text_fields_filled": 0,
|
||
"combobox_fields_filled": 0,
|
||
"checkboxes_set": 0
|
||
}
|
||
|
||
self._fill_text_fields(rack_data, results)
|
||
self._fill_combobox_fields(rack_data, results)
|
||
self._set_checkbox(rack_data, results)
|
||
|
||
logger.info(f"Filled {results['text_fields_filled']} text fields, "
|
||
f"{results['combobox_fields_filled']} combobox fields, "
|
||
f"{results['checkboxes_set']} checkboxes")
|
||
return results
|
||
|
||
def _fill_text_fields(self, rack_data: EditRackFormData, results: Dict[str, int]) -> None:
|
||
"""Заполняет текстовые поля.
|
||
|
||
Args:
|
||
rack_data: Данные для заполнения
|
||
results: Словарь с результатами
|
||
"""
|
||
|
||
for field_label, (attr_name, field_name) in self.TEXT_FIELDS_MAPPING.items():
|
||
value = getattr(rack_data, attr_name, "")
|
||
if not value or not str(value).strip():
|
||
continue
|
||
|
||
self._fill_single_text_field(field_label, field_name, value, results)
|
||
|
||
def _fill_single_text_field(
|
||
self, field_label: str, field_name: str, value: str, results: Dict[str, int]
|
||
) -> None:
|
||
"""Заполняет одно текстовое поле.
|
||
|
||
Args:
|
||
field_label: Метка поля
|
||
field_name: Имя поля
|
||
value: Значение для заполнения
|
||
results: Словарь с результатами
|
||
"""
|
||
|
||
try:
|
||
input_field = self.get_content_item(field_name)
|
||
if input_field:
|
||
input_field.input_value(value)
|
||
results["text_fields_filled"] += 1
|
||
logger.debug(f"Field '{field_label}' filled: '{value}'")
|
||
except Exception as e:
|
||
logger.error(f"Error filling field '{field_label}': {e}")
|
||
|
||
def _fill_combobox_fields(self, rack_data: EditRackFormData, results: Dict[str, int]) -> None:
|
||
"""Заполняет combobox поля.
|
||
|
||
Args:
|
||
rack_data: Данные для заполнения
|
||
results: Словарь с результатами
|
||
"""
|
||
|
||
for field_label, (attr_name, input_name, list_name) in self.COMBOBOX_FIELDS_MAPPING.items():
|
||
value = getattr(rack_data, attr_name, "")
|
||
if not value or not str(value).strip():
|
||
continue
|
||
|
||
self._fill_single_combobox_field(
|
||
field_label, input_name, list_name, value, results
|
||
)
|
||
|
||
def _fill_single_combobox_field(
|
||
self, field_label: str, input_name: str, list_name: str, value: str, results: Dict[str, int]
|
||
) -> None:
|
||
"""Заполняет одно combobox поле.
|
||
|
||
Args:
|
||
field_label: Метка поля
|
||
input_name: Имя поля ввода
|
||
list_name: Имя списка
|
||
value: Значение для выбора
|
||
results: Словарь с результатами
|
||
"""
|
||
|
||
try:
|
||
combobox_field = self.get_content_item(input_name)
|
||
if not combobox_field:
|
||
logger.warning(f"Field '{field_label}' input not found")
|
||
return
|
||
|
||
# Кликаем для открытия выпадающего списка
|
||
combobox_field.click(force=True)
|
||
self.wait_for_timeout(1000)
|
||
|
||
# Скроллим до нужного элемента
|
||
if not self._scroll_to_element_in_dropdown(value):
|
||
logger.error(f"Could not find element with text '{value}' after scrolling")
|
||
# Закрываем выпадающий список кликом вне
|
||
self.page.mouse.click(10, 10)
|
||
self.wait_for_timeout(300)
|
||
return
|
||
|
||
# Получаем активное выпадающее меню
|
||
dropdown_menu = self.page.locator("div.menuable__content__active").first
|
||
|
||
# Ищем элемент с нужным текстом
|
||
item_locator = dropdown_menu.locator(f"a.v-list__tile:has-text('{value}')").first
|
||
|
||
if item_locator.count() == 0:
|
||
item_locator = dropdown_menu.locator(f"span:has-text('{value}')").first
|
||
|
||
if item_locator.count() == 0:
|
||
item_locator = dropdown_menu.locator(f"div[role='listitem']:has-text('{value}')").first
|
||
|
||
if item_locator.count() > 0:
|
||
# Убеждаемся что элемент видим и кликаем
|
||
item_locator.scroll_into_view_if_needed()
|
||
self.wait_for_timeout(300)
|
||
item_locator.click()
|
||
results["combobox_fields_filled"] += 1
|
||
logger.debug(f"Field '{field_label}' set: '{value}'")
|
||
|
||
# Небольшая пауза после выбора
|
||
self.wait_for_timeout(500)
|
||
else:
|
||
logger.error(f"Item with text '{value}' not found in dropdown for field '{field_label}'")
|
||
# Закрываем выпадающий список кликом вне
|
||
self.page.mouse.click(10, 10)
|
||
self.wait_for_timeout(300)
|
||
|
||
except Exception as e:
|
||
logger.error(f"Error filling combobox '{field_label}': {e}")
|
||
self.page.mouse.click(10, 10)
|
||
|
||
def _set_checkbox(self, rack_data: EditRackFormData, results: Dict[str, int]) -> None:
|
||
"""Устанавливает чекбокс.
|
||
|
||
Args:
|
||
rack_data: Данные для заполнения
|
||
results: Словарь с результатами
|
||
"""
|
||
|
||
if rack_data.ventilation_panel is None:
|
||
return
|
||
|
||
try:
|
||
checkbox = self.get_content_item("ventilation_checkbox")
|
||
if not checkbox:
|
||
logger.warning("Ventilation panel checkbox not found")
|
||
return
|
||
|
||
if rack_data.ventilation_panel:
|
||
checkbox.check(force=True)
|
||
logger.debug("Ventilation panel checkbox checked")
|
||
else:
|
||
checkbox.uncheck(force=True)
|
||
logger.debug("Ventilation panel checkbox unchecked")
|
||
|
||
results["checkboxes_set"] += 1
|
||
|
||
except Exception as e:
|
||
logger.error(f"Error setting checkbox: {e}")
|
||
|
||
def is_field_highlighted_as_error(self, field_name: str) -> bool:
|
||
"""Проверяет, подсвечено ли поле как ошибочное.
|
||
|
||
Args:
|
||
field_name: Название поля для проверки
|
||
|
||
Returns:
|
||
bool: True если поле подсвечено ошибкой, False в противном случае
|
||
"""
|
||
|
||
# Для чекбокса проверка ошибок не применяется
|
||
if field_name == "Вентиляционная панель":
|
||
return False
|
||
|
||
# Проверяем в текстовых полях
|
||
if field_name in self.TEXT_FIELDS_LOCATORS:
|
||
locator = self.TEXT_FIELDS_LOCATORS[field_name]
|
||
field_element = self.page.locator(locator).first
|
||
|
||
if field_element.count() == 0:
|
||
logger.debug(f"Field '{field_name}' not found")
|
||
return False
|
||
|
||
# Поднимаемся до родительского контейнера с классом v-input
|
||
parent_input = field_element.locator("xpath=ancestor::div[contains(@class, 'v-input')]").first
|
||
|
||
if parent_input.count() > 0:
|
||
# Проверяем наличие класса ошибки
|
||
class_attr = parent_input.get_attribute("class") or ""
|
||
is_error = "v-input--error" in class_attr or "error--text" in class_attr
|
||
logger.debug(f"Field '{field_name}' error state: {is_error}, classes: {class_attr}")
|
||
return is_error
|
||
|
||
# Проверяем в combobox полях
|
||
elif field_name in self.COMBOBOX_FIELDS_LOCATORS:
|
||
locator = self.COMBOBOX_FIELDS_LOCATORS[field_name]
|
||
field_element = self.page.locator(locator).first
|
||
|
||
if field_element.count() == 0:
|
||
logger.debug(f"Field '{field_name}' not found")
|
||
return False
|
||
|
||
# Поднимаемся до родительского контейнера с классом v-input
|
||
parent_input = field_element.locator("xpath=ancestor::div[contains(@class, 'v-input')]").first
|
||
|
||
if parent_input.count() > 0:
|
||
# Проверяем наличие класса ошибки
|
||
class_attr = parent_input.get_attribute("class") or ""
|
||
is_error = "v-input--error" in class_attr or "error--text" in class_attr
|
||
logger.debug(f"Field '{field_name}' error state: {is_error}, classes: {class_attr}")
|
||
return is_error
|
||
|
||
return False
|
||
|
||
def verify_required_fields_highlighted(self, field_names: List[str]) -> Dict[str, bool]:
|
||
"""Проверяет, что указанные поля подсвечены как обязательные (с ошибкой).
|
||
|
||
Args:
|
||
field_names: Список названий полей для проверки
|
||
|
||
Returns:
|
||
Словарь с результатами проверки {field_name: is_highlighted}
|
||
"""
|
||
|
||
results = {}
|
||
|
||
for field_name in field_names:
|
||
results[field_name] = self.is_field_highlighted_as_error(field_name)
|
||
logger.debug(f"Field '{field_name}' highlighted: {results[field_name]}")
|
||
|
||
return results
|
||
|
||
def wait_for_field_error(self, field_name: str, timeout: int = 5000) -> bool:
|
||
"""Ожидает появления подсветки ошибки на поле.
|
||
|
||
Args:
|
||
field_name: Название поля
|
||
timeout: Таймаут в миллисекундах
|
||
|
||
Returns:
|
||
bool: True если ошибка появилась, False в противном случае
|
||
"""
|
||
|
||
# Для чекбокса не ждем ошибок
|
||
if field_name == "Вентиляционная панель":
|
||
return False
|
||
|
||
start_time = time.time()
|
||
|
||
while (time.time() - start_time) * 1000 < timeout:
|
||
if self.is_field_highlighted_as_error(field_name):
|
||
return True
|
||
self.wait_for_timeout(200)
|
||
|
||
return False
|
||
|
||
def get_field_value(self, field_name: str) -> Optional[str]:
|
||
"""Получает значение поля.
|
||
|
||
Args:
|
||
field_name: Название поля
|
||
|
||
Returns:
|
||
Значение поля или None если поле не найдено
|
||
"""
|
||
|
||
# Для чекбокса
|
||
if field_name == "Вентиляционная панель":
|
||
checkbox = self.get_content_item("ventilation_checkbox")
|
||
if checkbox:
|
||
return str(checkbox.is_checked())
|
||
return None
|
||
|
||
# Для текстовых полей
|
||
if field_name in self.TEXT_FIELDS_LOCATORS:
|
||
for field_label, (attr_name, widget_name) in self.TEXT_FIELDS_MAPPING.items():
|
||
if attr_name == field_name or field_label == field_name:
|
||
input_field = self.get_content_item(widget_name)
|
||
if input_field:
|
||
return input_field.get_input_value()
|
||
return None
|
||
|
||
# Для combobox полей
|
||
if field_name in self.COMBOBOX_FIELDS_LOCATORS:
|
||
locator = self.COMBOBOX_FIELDS_LOCATORS.get(field_name)
|
||
if not locator:
|
||
# Пробуем найти по атрибуту
|
||
for field_label, (attr_name, input_name, _) in self.COMBOBOX_FIELDS_MAPPING.items():
|
||
if attr_name == field_name or field_label == field_name:
|
||
input_field = self.get_content_item(input_name)
|
||
if input_field:
|
||
# Получаем текст из поля
|
||
element = input_field.element
|
||
selections = element.locator("xpath=ancestor::div[contains(@class, 'v-select__selections')]").first
|
||
if selections.count() > 0:
|
||
value_span = selections.locator("span").first
|
||
return value_span.text_content() or ""
|
||
return None
|
||
|
||
element = self.page.locator(locator).first
|
||
if element.count() > 0:
|
||
selections = element.locator("xpath=ancestor::div[contains(@class, 'v-select__selections')]").first
|
||
if selections.count() > 0:
|
||
value_span = selections.locator("span").first
|
||
return value_span.text_content() or ""
|
||
|
||
return None
|