diff --git a/components/base_component.py b/components/base_component.py index e239622..83f92a9 100644 --- a/components/base_component.py +++ b/components/base_component.py @@ -30,61 +30,53 @@ class BaseComponent: # Действия: - def get_input_fields_locators_(self, container_locator: Locator, search_class: str = "layout") -> dict: - """Получение объекта словаря имя поля ввода : Locator. + 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 контейнеры Args: - container_locator: объект Locator. - search_class: css класс для поиска (по умолчанию layout) + container_locator: Контейнер, в котором искать поля ввода. Returns: - dict: словарь имя поля ввода : Locator xs8 контейнера + Словарь, где ключ - текст метки, значение - Locator контейнера с полем ввода. """ fields_locators = {} - if search_class == "layout": - # Поиск по структуре layout -> xs4 (label) + xs8 (input контейнер) - layout_containers = container_locator.locator("div.layout") + layouts = container_locator.locator("div.layout") - for i in range(layout_containers.count()): - layout_container = layout_containers.nth(i) + for i in range(layouts.count()): + layout = layouts.nth(i) + flex_containers = layout.locator("div.flex") - xs4_div = layout_container.locator("div.flex.xs4").first - xs8_div = layout_container.locator("div.flex.xs8").first + # Обрабатываем пары контейнеров + for j in range(0, flex_containers.count() - 1): + label_container = flex_containers.nth(j) + input_container = flex_containers.nth(j + 1) - 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() + # Извлекаем текст метки + 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 label_text: - # Возвращаем xs8 контейнер - fields_locators[label_text] = xs8_div + if has_input: + fields_locators[label_text] = input_container 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. diff --git a/components_derived/accounting_objects/rack_maker.py b/components_derived/accounting_objects/rack_maker.py index 30428fa..64b9c17 100644 --- a/components_derived/accounting_objects/rack_maker.py +++ b/components_derived/accounting_objects/rack_maker.py @@ -57,10 +57,13 @@ class RackObjectMaker(BaseComponent): logger.debug("Rack data filled successfully") - def _fill_text_fields(self, rack_data: RackData) -> None: - """Заполняет текстовые поля.""" + def _get_form_fields(self) -> dict: + """ + Получает все поля формы стойки. - logger.debug("Filling text fields...") + Returns: + dict: Словарь {название поля: Locator контейнера поля} + """ # Получаем контейнер формы (второй элемент) container_locator = self.page.locator(RackLocators.FORM_INPUT_CONTAINER).nth(1) @@ -69,8 +72,15 @@ class RackObjectMaker(BaseComponent): logger.error("Form container not found") raise ValueError("Form container not found") - # Используем метод из базового класса для получения всех полей - fields_locators = self.get_input_fields_locators_(container_locator, "layout") + 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() logger.debug(f"Available text fields: {list(fields_locators.keys())}") @@ -81,7 +91,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: @@ -137,51 +147,49 @@ 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) + self._fill_combobox_field("Высота в юнитах", rack_data.height, fields_locators) logger.debug(f"Selected height: {rack_data.height} units") if rack_data.depth: - self._fill_combobox_field("Глубина (мм)", rack_data.depth) + self._fill_combobox_field("Глубина (мм)", rack_data.depth, fields_locators) logger.debug(f"Selected depth: {rack_data.depth} mm") # Опциональные поля. if rack_data.cable_entry: - self._fill_combobox_field("Ввод кабеля", rack_data.cable_entry) + self._fill_combobox_field("Ввод кабеля", rack_data.cable_entry, fields_locators) logger.debug(f"Selected cable entry: {rack_data.cable_entry}") if rack_data.state: - self._fill_combobox_field("Состояние", rack_data.state) + self._fill_combobox_field("Состояние", rack_data.state, fields_locators) logger.debug(f"Selected state: {rack_data.state}") if rack_data.owner: - self._fill_combobox_field("Владелец", rack_data.owner) + self._fill_combobox_field("Владелец", rack_data.owner, fields_locators) logger.debug(f"Selected owner: {rack_data.owner}") if rack_data.service_org: - self._fill_combobox_field("Обслуживающая организация", rack_data.service_org) + self._fill_combobox_field("Обслуживающая организация", rack_data.service_org, fields_locators) logger.debug(f"Selected service organization: {rack_data.service_org}") if rack_data.project: - self._fill_combobox_field("Проект/Титул", rack_data.project) + self._fill_combobox_field("Проект/Титул", rack_data.project, fields_locators) logger.debug(f"Selected project/title: {rack_data.project}") - def _fill_combobox_field(self, field_name: str, value: str) -> None: + def _fill_combobox_field(self, field_name: str, value: str, fields_locators: dict) -> 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) @@ -270,14 +278,8 @@ class RackObjectMaker(BaseComponent): logger.debug("Checking rack fields presence...") - # Получаем контейнер формы (второй элемент) - 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") + # Получаем все поля формы + fields_locators = self._get_form_fields() logger.debug(f"Found fields in form: {list(fields_locators.keys())}") diff --git a/components_derived/frames/create_child_element_frame.py b/components_derived/frames/create_child_element_frame.py index b5b81ae..c5bd55e 100644 --- a/components_derived/frames/create_child_element_frame.py +++ b/components_derived/frames/create_child_element_frame.py @@ -61,15 +61,13 @@ class CreateChildElementFrame(BaseComponent): # Получаем контейнер формы container_locator = self.page.locator(RackLocators.FORM_INPUT_CONTAINER).nth(1) - - # Используем метод get_input_fields_locators для получения всех полей - fields_locators = self.get_input_fields_locators_(container_locator, "layout") + fields_locators = self.get_input_fields_locators(container_locator) 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] # Прокручиваем до поля @@ -121,9 +119,7 @@ class CreateChildElementFrame(BaseComponent): """Открывает выпадающий список combobox.""" container_locator = self.page.locator(RackLocators.FORM_INPUT_CONTAINER) - - # Используем метод из базового класса BaseComponent - fields_locators = self.get_input_fields_locators_(container_locator, "layout") + fields_locators = self.get_input_fields_locators(container_locator) combobox_container = fields_locators.get("Класс объекта учета") if not combobox_container: @@ -149,7 +145,7 @@ class CreateChildElementFrame(BaseComponent): # Открываем combobox self.open_object_class_combobox() - # Выбираем значение из списка + # Выбирает значение из списка self.selection_bar.select_value(class_name) # Даем время на применение выбора @@ -171,7 +167,7 @@ class CreateChildElementFrame(BaseComponent): # Получаем контейнеры всех полей container_locator = self.page.locator(RackLocators.FORM_INPUT_CONTAINER) - fields_locators = self.get_input_fields_locators_(container_locator, "layout") + fields_locators = self.get_input_fields_locators(container_locator) # Получаем контейнер конкретного поля field_container = fields_locators.get(field_name) @@ -204,7 +200,7 @@ class CreateChildElementFrame(BaseComponent): # Получаем контейнеры всех полей container_locator = self.page.locator(RackLocators.FORM_INPUT_CONTAINER) - fields_locators = self.get_input_fields_locators_(container_locator, "layout") + fields_locators = self.get_input_fields_locators(container_locator) # Получаем контейнер конкретного поля field_container = fields_locators.get(field_name) diff --git a/locators/settings_form_locators.py b/locators/settings_form_locators.py index f7562db..fc57f85 100644 --- a/locators/settings_form_locators.py +++ b/locators/settings_form_locators.py @@ -19,8 +19,9 @@ 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: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" + + SETTINGS_FORM_INPUT_FIELD = "div.v-text-field__slot > input" + SETTINGS_FORM_INPUT_VALUE_SUFFIX = ".v-text-field__suffix" DROPDOWN_LIST = "//div[contains(@class, 'menuable__content__active')]" SELECTED_VALUES = "//div[@class='v-select__selections']" diff --git a/pages/push_notifications_settings_tab.py b/pages/push_notifications_settings_tab.py index 7948e71..b62afda 100644 --- a/pages/push_notifications_settings_tab.py +++ b/pages/push_notifications_settings_tab.py @@ -36,9 +36,8 @@ 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, css_class) + self.input_fields_locators = self.settings_form.get_input_fields_locators(container_locator) loc = self.input_fields_locators.get("Сообщение") loc_message_input = loc.locator(SettingsFormLocators.SETTINGS_FORM_INPUT_FIELD).first diff --git a/pages/session_settings_tab.py b/pages/session_settings_tab.py index bf0c731..fbecd7c 100644 --- a/pages/session_settings_tab.py +++ b/pages/session_settings_tab.py @@ -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, css_class) + self.input_fields_locators = self.settings_form.get_input_fields_locators(container_locator) + # Используем локаторы для числовых полей loc = self.input_fields_locators.get("Администратор") - loc_admin = loc.locator(SettingsFormLocators.SETTINGS_FORM_INPUT_FIELD) + loc_admin = loc.locator(SettingsFormLocators.SETTINGS_FORM_INPUT_FIELD).first 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) + loc_oper = loc.locator(SettingsFormLocators.SETTINGS_FORM_INPUT_FIELD).first 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) + loc_manager = loc.locator(SettingsFormLocators.SETTINGS_FORM_INPUT_FIELD).first 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) + loc_inform_secur_user = loc.locator(SettingsFormLocators.SETTINGS_FORM_INPUT_FIELD).first 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) + loc_collector = loc.locator(SettingsFormLocators.SETTINGS_FORM_INPUT_FIELD).first 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}" diff --git a/tests/e2e/create_elements/test_create_rack_element.py b/tests/e2e/create_elements/test_create_rack_element.py index 297b1ec..318da95 100644 --- a/tests/e2e/create_elements/test_create_rack_element.py +++ b/tests/e2e/create_elements/test_create_rack_element.py @@ -213,9 +213,7 @@ class TestCreateRackElement: # Получаем контейнер формы container_locator = create_child_frame.page.locator(RackLocators.FORM_INPUT_CONTAINER).nth(1) - - # Используем метод get_input_fields_locators для получения всех полей - fields_locators = create_child_frame.get_input_fields_locators_(container_locator, "layout") + fields_locators = create_child_frame.get_input_fields_locators(container_locator) logger.debug(f"Available fields: {list(fields_locators.keys())}") @@ -227,7 +225,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(): @@ -409,9 +407,7 @@ class TestCreateRackElement: # Получаем контейнер формы container_locator = create_child_frame.page.locator(RackLocators.FORM_INPUT_CONTAINER).nth(1) - - # Используем метод get_input_fields_locators для получения всех полей - fields_locators = create_child_frame.get_input_fields_locators_(container_locator, "layout") + fields_locators = create_child_frame.get_input_fields_locators(container_locator) # Очищаем поле "Высота в юнитах" если оно заполнено if "Высота в юнитах" in fields_locators: