Compare commits

..

No commits in common. "5f21e197f62fd3d63c21da8ae835adf91aae3bcd" and "e3fd08999c19c865ba6665c9eaccc341f0fc6918" have entirely different histories.

7 changed files with 98 additions and 84 deletions

View File

@ -30,53 +30,61 @@ class BaseComponent:
# Действия:
def get_input_fields_locators(self, container_locator: Locator) -> dict:
"""Находит пары "метка-поле ввода" в контейнере с layout структурой.
Метод ищет элементы в структуре div.layout > div.flex, где:
- Первый div.flex содержит метку (текст в input элементе)
- Второй div.flex содержит соответствующее поле ввода
Поддерживает различные структуры:
- xs4 (метка) -> xs8 (поле ввода)
- xs4 (метка) -> xs1 (поле ввода)
- Любые другие парные flex контейнеры
def get_input_fields_locators_(self, container_locator: Locator, search_class: str = "layout") -> dict:
"""Получение объекта словаря имя поля ввода : Locator.
Args:
container_locator: Контейнер, в котором искать поля ввода.
container_locator: объект Locator.
search_class: css класс для поиска (по умолчанию layout)
Returns:
Словарь, где ключ - текст метки, значение - Locator контейнера с полем ввода.
dict: словарь имя поля ввода : Locator xs8 контейнера
"""
fields_locators = {}
layouts = container_locator.locator("div.layout")
if search_class == "layout":
# Поиск по структуре layout -> xs4 (label) + xs8 (input контейнер)
layout_containers = container_locator.locator("div.layout")
for i in range(layouts.count()):
layout = layouts.nth(i)
flex_containers = layout.locator("div.flex")
for i in range(layout_containers.count()):
layout_container = layout_containers.nth(i)
# Обрабатываем пары контейнеров
for j in range(0, flex_containers.count() - 1):
label_container = flex_containers.nth(j)
input_container = flex_containers.nth(j + 1)
xs4_div = layout_container.locator("div.flex.xs4").first
xs8_div = layout_container.locator("div.flex.xs8").first
# Извлекаем текст метки
inputs = label_container.locator("input")
if inputs.count() > 0:
label_text = inputs.first.input_value().strip()
if label_text:
# Проверяем поле ввода
has_input = input_container.locator(
"input, textarea, select"
).count() > 0
if xs4_div.count() > 0 and xs8_div.count() > 0:
# Ищем input в label_container
label_input = xs4_div.locator("div.v-text-field__slot > input").first
if label_input.count() > 0:
label_text = label_input.input_value().strip()
if has_input:
fields_locators[label_text] = input_container
if label_text:
# Возвращаем xs8 контейнер
fields_locators[label_text] = xs8_div
return fields_locators
def get_input_fields_locators(self, container_locator: Locator, css_class: str) -> dict:
"""Получение объекта словаря имя поля ввода : Locator.
Args:
locator: объект Locator.
css_class: css класс для уточнения положения искомого объекта в DOM.
Returns:
dict: словарь имя поля ввода : Locator.
"""
fields_locators = {}
elements = container_locator.locator(f"div.flex.{css_class} div.v-text-field__slot > input").all()
for el in elements:
val = el.input_value().strip()
if val:
fields_locators[val] = el.locator("../ancestor::div[6]")
return fields_locators
def get_locator(self, locator: str | Locator) -> Locator:
"""Получение объекта Locator из строки или существующего Locator.

View File

@ -57,13 +57,10 @@ class RackObjectMaker(BaseComponent):
logger.debug("Rack data filled successfully")
def _get_form_fields(self) -> dict:
"""
Получает все поля формы стойки.
def _fill_text_fields(self, rack_data: RackData) -> None:
"""Заполняет текстовые поля."""
Returns:
dict: Словарь {название поля: Locator контейнера поля}
"""
logger.debug("Filling text fields...")
# Получаем контейнер формы (второй элемент)
container_locator = self.page.locator(RackLocators.FORM_INPUT_CONTAINER).nth(1)
@ -72,15 +69,8 @@ class RackObjectMaker(BaseComponent):
logger.error("Form container not found")
raise ValueError("Form container not found")
return self.get_input_fields_locators(container_locator)
def _fill_text_fields(self, rack_data: RackData) -> None:
"""Заполняет текстовые поля."""
logger.debug("Filling text fields...")
# Получаем все поля формы
fields_locators = self._get_form_fields()
# Используем метод из базового класса для получения всех полей
fields_locators = self.get_input_fields_locators_(container_locator, "layout")
logger.debug(f"Available text fields: {list(fields_locators.keys())}")
@ -91,7 +81,7 @@ class RackObjectMaker(BaseComponent):
logger.debug(f"Skipping empty value for field '{field_name}'")
return
# Получаем контейнер поля
# Получаем xs8 контейнер поля
field_container = fields_locators.get(field_name)
if not field_container:
@ -147,49 +137,51 @@ class RackObjectMaker(BaseComponent):
def _fill_combobox_fields(self, rack_data: RackData) -> None:
"""Заполняет combobox поля."""
# Получаем все поля формы
fields_locators = self._get_form_fields()
# Обязательные поля.
if rack_data.height:
self._fill_combobox_field("Высота в юнитах", rack_data.height, fields_locators)
self._fill_combobox_field("Высота в юнитах", rack_data.height)
logger.debug(f"Selected height: {rack_data.height} units")
if rack_data.depth:
self._fill_combobox_field("Глубина (мм)", rack_data.depth, fields_locators)
self._fill_combobox_field("Глубина (мм)", rack_data.depth)
logger.debug(f"Selected depth: {rack_data.depth} mm")
# Опциональные поля.
if rack_data.cable_entry:
self._fill_combobox_field("Ввод кабеля", rack_data.cable_entry, fields_locators)
self._fill_combobox_field("Ввод кабеля", rack_data.cable_entry)
logger.debug(f"Selected cable entry: {rack_data.cable_entry}")
if rack_data.state:
self._fill_combobox_field("Состояние", rack_data.state, fields_locators)
self._fill_combobox_field("Состояние", rack_data.state)
logger.debug(f"Selected state: {rack_data.state}")
if rack_data.owner:
self._fill_combobox_field("Владелец", rack_data.owner, fields_locators)
self._fill_combobox_field("Владелец", rack_data.owner)
logger.debug(f"Selected owner: {rack_data.owner}")
if rack_data.service_org:
self._fill_combobox_field("Обслуживающая организация", rack_data.service_org, fields_locators)
self._fill_combobox_field("Обслуживающая организация", rack_data.service_org)
logger.debug(f"Selected service organization: {rack_data.service_org}")
if rack_data.project:
self._fill_combobox_field("Проект/Титул", rack_data.project, fields_locators)
self._fill_combobox_field("Проект/Титул", rack_data.project)
logger.debug(f"Selected project/title: {rack_data.project}")
def _fill_combobox_field(self, field_name: str, value: str, fields_locators: dict) -> None:
def _fill_combobox_field(self, field_name: str, value: str) -> None:
"""
Заполняет combobox поле.
Args:
field_name: Название поля
value: Значение для установки
fields_locators: Словарь с найденными полями формы
"""
# Получаем контейнер формы (второй элемент)
container_locator = self.page.locator(RackLocators.FORM_INPUT_CONTAINER).nth(1)
# Используем метод из базового класса BaseComponent
fields_locators = self.get_input_fields_locators_(container_locator, "layout")
# Получаем контейнер поля по его названию
field_container = fields_locators.get(field_name)
@ -278,8 +270,14 @@ class RackObjectMaker(BaseComponent):
logger.debug("Checking rack fields presence...")
# Получаем все поля формы
fields_locators = self._get_form_fields()
# Получаем контейнер формы (второй элемент)
container_locator = self.page.locator(RackLocators.FORM_INPUT_CONTAINER).nth(1)
# Проверяем наличие контейнера
assert container_locator.count() > 0, "Form container not found"
# Используем метод из базового класса BaseComponent для получения всех полей
fields_locators = self.get_input_fields_locators_(container_locator, "layout")
logger.debug(f"Found fields in form: {list(fields_locators.keys())}")

View File

@ -61,13 +61,15 @@ class CreateChildElementFrame(BaseComponent):
# Получаем контейнер формы
container_locator = self.page.locator(RackLocators.FORM_INPUT_CONTAINER).nth(1)
fields_locators = self.get_input_fields_locators(container_locator)
# Используем метод get_input_fields_locators для получения всех полей
fields_locators = self.get_input_fields_locators_(container_locator, "layout")
if field_name not in fields_locators:
logger.warning(f"Field '{field_name}' not found in form")
return
# Получаем контейнер поля
# Получаем xs8 контейнер поля
field_container = fields_locators[field_name]
# Прокручиваем до поля
@ -119,7 +121,9 @@ class CreateChildElementFrame(BaseComponent):
"""Открывает выпадающий список combobox."""
container_locator = self.page.locator(RackLocators.FORM_INPUT_CONTAINER)
fields_locators = self.get_input_fields_locators(container_locator)
# Используем метод из базового класса BaseComponent
fields_locators = self.get_input_fields_locators_(container_locator, "layout")
combobox_container = fields_locators.get("Класс объекта учета")
if not combobox_container:
@ -145,7 +149,7 @@ class CreateChildElementFrame(BaseComponent):
# Открываем combobox
self.open_object_class_combobox()
# Выбирает значение из списка
# Выбираем значение из списка
self.selection_bar.select_value(class_name)
# Даем время на применение выбора
@ -167,7 +171,7 @@ class CreateChildElementFrame(BaseComponent):
# Получаем контейнеры всех полей
container_locator = self.page.locator(RackLocators.FORM_INPUT_CONTAINER)
fields_locators = self.get_input_fields_locators(container_locator)
fields_locators = self.get_input_fields_locators_(container_locator, "layout")
# Получаем контейнер конкретного поля
field_container = fields_locators.get(field_name)
@ -200,7 +204,7 @@ class CreateChildElementFrame(BaseComponent):
# Получаем контейнеры всех полей
container_locator = self.page.locator(RackLocators.FORM_INPUT_CONTAINER)
fields_locators = self.get_input_fields_locators(container_locator)
fields_locators = self.get_input_fields_locators_(container_locator, "layout")
# Получаем контейнер конкретного поля
field_container = fields_locators.get(field_name)

View File

@ -19,9 +19,8 @@ class SettingsFormLocators:
SETTTINGS_FORM_TITLE = f"{SETTTINGS_FORM_SCROLL_CONTAINER}//div[contains(@class, 'v-toolbar__title')]"
SETTINGS_FORM_INPUT_FORM_CONTAINER = "//nav[contains(@class, 'active v-toolbar')]/following-sibling::div"
SETTINGS_FORM_INPUT_FIELD = "div.v-text-field__slot > input"
SETTINGS_FORM_INPUT_VALUE_SUFFIX = ".v-text-field__suffix"
SETTINGS_FORM_INPUT_FIELD = "div:nth-child(2) div.v-text-field__slot > input"
SETTINGS_FORM_INPUT_VALUE_SUFFIX = "div:nth-child(2) div.v-text-field__slot div.v-text-field__suffix"
DROPDOWN_LIST = "//div[contains(@class, 'menuable__content__active')]"
SELECTED_VALUES = "//div[@class='v-select__selections']"

View File

@ -36,8 +36,9 @@ class PushNotificationsSettingsTab(BasePage):
self.settings_form = SettingsFormComponent(page)
self.settings_form.add_toolbar_title("Общие")
css_class = "xs6"
container_locator = self.page.locator(SettingsFormLocators.SETTINGS_FORM_INPUT_FORM_CONTAINER)
self.input_fields_locators = self.settings_form.get_input_fields_locators(container_locator)
self.input_fields_locators = self.settings_form.get_input_fields_locators(container_locator, css_class)
loc = self.input_fields_locators.get("Сообщение")
loc_message_input = loc.locator(SettingsFormLocators.SETTINGS_FORM_INPUT_FIELD).first

View File

@ -44,32 +44,32 @@ class SessionSettingsTab(BasePage):
self.settings_form.add_toolbar_title("Время жизни сеанса")
css_class = "xs4"
container_locator = self.page.locator(SettingsFormLocators.SETTINGS_FORM_INPUT_FORM_CONTAINER)
self.input_fields_locators = self.settings_form.get_input_fields_locators(container_locator)
self.input_fields_locators = self.settings_form.get_input_fields_locators(container_locator, css_class)
# Используем локаторы для числовых полей
loc = self.input_fields_locators.get("Администратор")
loc_admin = loc.locator(SettingsFormLocators.SETTINGS_FORM_INPUT_FIELD).first
loc_admin = loc.locator(SettingsFormLocators.SETTINGS_FORM_INPUT_FIELD)
admin_setting = TextInput(page, loc_admin, "admin_setting")
self.settings_form.add_content_item("admin_setting", admin_setting)
loc = self.input_fields_locators.get("Оператор")
loc_oper = loc.locator(SettingsFormLocators.SETTINGS_FORM_INPUT_FIELD).first
loc_oper = loc.locator(SettingsFormLocators.SETTINGS_FORM_INPUT_FIELD)
operator_setting = TextInput(page, loc_oper, "operator_setting")
self.settings_form.add_content_item("operator_setting", operator_setting)
loc = self.input_fields_locators.get("Контактное лицо")
loc_manager = loc.locator(SettingsFormLocators.SETTINGS_FORM_INPUT_FIELD).first
loc_manager = loc.locator(SettingsFormLocators.SETTINGS_FORM_INPUT_FIELD)
manager_setting = TextInput(page, loc_manager, "manager_setting")
self.settings_form.add_content_item("manager_setting", manager_setting)
loc = self.input_fields_locators.get("Специалист информационной безопасности")
loc_inform_secur_user = loc.locator(SettingsFormLocators.SETTINGS_FORM_INPUT_FIELD).first
loc_inform_secur_user = loc.locator(SettingsFormLocators.SETTINGS_FORM_INPUT_FIELD)
inform_secur_user_setting = TextInput(page, loc_inform_secur_user, "inform_secur_user_setting")
self.settings_form.add_content_item("inform_secur_user_setting", inform_secur_user_setting)
loc = self.input_fields_locators.get('$collector')
loc_collector = loc.locator(SettingsFormLocators.SETTINGS_FORM_INPUT_FIELD).first
loc_collector = loc.locator(SettingsFormLocators.SETTINGS_FORM_INPUT_FIELD)
collector_setting = TextInput(page, loc_collector, "collector_setting")
self.settings_form.add_content_item("collector_setting", collector_setting)
@ -220,8 +220,8 @@ class SessionSettingsTab(BasePage):
)
for name in actual_input_field_names:
# Для суффикса "минут"
value_suffix_loc = self.input_fields_locators.get(name).locator(SettingsFormLocators.SETTINGS_FORM_INPUT_VALUE_SUFFIX)
value_suffix_loc = self.input_fields_locators.get(name).\
locator(SettingsFormLocators.SETTINGS_FORM_INPUT_VALUE_SUFFIX)
value_suffix = value_suffix_loc.text_content().strip()
assert value_suffix == "минут", f"Incorrect value suffix for field {name}"

View File

@ -213,7 +213,9 @@ class TestCreateRackElement:
# Получаем контейнер формы
container_locator = create_child_frame.page.locator(RackLocators.FORM_INPUT_CONTAINER).nth(1)
fields_locators = create_child_frame.get_input_fields_locators(container_locator)
# Используем метод get_input_fields_locators для получения всех полей
fields_locators = create_child_frame.get_input_fields_locators_(container_locator, "layout")
logger.debug(f"Available fields: {list(fields_locators.keys())}")
@ -225,7 +227,7 @@ class TestCreateRackElement:
logger.debug(f"Field '{field_name}' not found in fields_locators")
return False
# Получаем контейнер поля
# Получаем xs8 контейнер поля
field_container = fields_locators[field_name]
if not field_container.is_visible():
@ -407,7 +409,9 @@ class TestCreateRackElement:
# Получаем контейнер формы
container_locator = create_child_frame.page.locator(RackLocators.FORM_INPUT_CONTAINER).nth(1)
fields_locators = create_child_frame.get_input_fields_locators(container_locator)
# Используем метод get_input_fields_locators для получения всех полей
fields_locators = create_child_frame.get_input_fields_locators_(container_locator, "layout")
# Очищаем поле "Высота в юнитах" если оно заполнено
if "Высота в юнитах" in fields_locators: