diff --git a/components/navbar_component.py b/components/navbar_component.py index 6c9205a..b3254f1 100644 --- a/components/navbar_component.py +++ b/components/navbar_component.py @@ -247,8 +247,10 @@ class NavigationPanelComponent(BaseComponent): Returns: bool: True если элемент видим, False если нет. """ - try: - self.check_item_visibility(locator, item_name) - return True - except: + element_locator = self.page.locator(locator).filter(has_text=item_name) + + # Сначала проверяем что элемент вообще существует + if element_locator.count() == 0: return False + + return element_locator.is_visible() \ No newline at end of file diff --git a/components_derived/selection_bar_component.py b/components_derived/selection_bar_component.py new file mode 100644 index 0000000..3f24d69 --- /dev/null +++ b/components_derived/selection_bar_component.py @@ -0,0 +1,101 @@ +"""Модуль компонента панели выбора значения. + +Содержит класс для работы с компонентом панели выбора значения через Playwright. +""" + +from playwright.sync_api import Page, Locator, expect +from tools.logger import get_logger +from locators.selection_bar_locators import SelectionBarLocators +from locators.combobox_locators import ComboboxLocators +from components.dropdown_list_component import DropdownList +from components.base_component import BaseComponent + +logger = get_logger("FILTER_PARAMETER_BAR") + + +class SelectionBarComponent(BaseComponent): + """Компонент панели выбора значения. + + Предоставляет методы для взаимодействия с элементами компонента панели выбора значения. + """ + + def __init__(self, page: Page, locator: str | Locator): + """Инициализирует компонент панели выбора значения. + + Args: + page: Экземпляр страницы Playwright. + locator: Локатор панели выбора значения (строка или объект Locator) + """ + + super().__init__(page) + + # Локатор панели параметра фильтрации + self.selection_bar_locator = self.get_locator(locator) + + # При нажатии на панель появляется выпадающий список с параметрами фильтрации для выбора + self.selected_values_list = DropdownList(self.page) + + # Действия: + def clear_selections(self) -> None: + """ Удаление ранее выбранных значений """ + + selected_values = self.get_selected_values() + if len(selected_values) > 0: + clear_button_locator = self.selection_bar_locator.\ + locator(SelectionBarLocators.CLEAR_SELECTION_BUTTON) + clear_button_locator.click() + + + def get_selection_bar_title(self) -> str: + """ Возвращает название панели выбора значения """ + + title_locator = self.selection_bar_locator.locator("//label") + return title_locator.text_content() + + def get_selected_values(self) -> list[str]: + """ Возвращает список выбранных значений """ + + selected_values_locator = self.selection_bar_locator.\ + locator(SelectionBarLocators.PARAMETERS_SELECTED) + + selected_values = selected_values_locator.all_inner_texts() + return selected_values[0].splitlines() + + def open_values_list(self) -> None: + """ Открытие выпадающего списка путем нажатия на панель выбора значения """ + + expect(self.selection_bar_locator).to_be_visible() + self.selection_bar_locator.click() + + def get_available_options(self) -> list[str]: + """ + Возвращает список всех доступных опций из выпадающего списка. + + Returns: + list[str]: Список доступных опций + """ + logger.info("Получение списка доступных опций из выпадающего списка...") + + # Открываем выпадающий список + self.open_values_list() + + # Ждем появления списка + self.wait_for_timeout(1000) + + # Получаем все элементы списка + options = self.selected_values_list.get_item_names(SelectionBarLocators.LIST_ITEMS) + + # Закрываем список (кликаем вне его) + self.page.mouse.click(10, 10) + self.wait_for_timeout(500) + + logger.info(f"Найдено доступных опций: {len(options)} - {options}") + return options + + def select_value(self, name: str) -> None: + """ Выбор значения из списка """ + + self.selected_values_list.check_item_with_text(name) + self.selected_values_list.click_item_with_text(name) + + # Проверки: diff --git a/components_derived/sidebar_filter_component.py b/components_derived/sidebar_filter_component.py new file mode 100644 index 0000000..a047516 --- /dev/null +++ b/components_derived/sidebar_filter_component.py @@ -0,0 +1,119 @@ +"""Модуль компонента боковой панели формы ввода полей фильтрации отображения данных в панели событий. Содержит класс для работы +с формами ввода, их элементами и проверками.""" + +from playwright.sync_api import Page, Locator +from tools.logger import get_logger +from elements.button_element import Button +from components_derived.selection_bar_component import SelectionBarComponent +from components_derived.date_input_component import DateInput +from components.toolbar_component import ToolbarComponent +from components.base_component import BaseComponent + +logger = get_logger("SIDEBAR_FILTER") + + +class SidebarFilterComponent(BaseComponent): + """Компонент боковой панели формы ввода полей фильтрации отображения данных в панели событий. Предоставляет методы для + взаимодействия с формой, ее содержимым и проверок.""" + + def __init__(self, page: Page, locator: str | Locator): + """Инициализирует компонент боковой панели формы ввода параметров фильтрации. + + Args: + page: Экземпляр страницы Playwright + locator: Локатор контейнера (строка или объект Locator) для которого вызывается панель + """ + super().__init__(page) + + self.sidebar_locator = self.get_locator(locator) + + self.toolbar = ToolbarComponent(page, "Настройки и параметры") + + # Поля ввода даты начала и даты окончания события + self.start_time_filter = DateInput(page, + self.sidebar_locator.locator( + "//div[contains(@class, 'scrollarea__body')]/div").nth(0)) + self.finish_time_filter = DateInput(page, + self.sidebar_locator.locator( + "//div[contains(@class, 'scrollarea__body')]/div").nth(1)) + + # Поля задания параметров фильтрации (произвольное количество) + self.filtering_parameters = {} + + # Кнопки задания/сброса параметров фильтрации + self.apply_button = Button(page, + self.sidebar_locator.get_by_role("button").filter(has_text='Применить Фильтры'), + "apply_button") + self.reset_button = Button(page, + self.sidebar_locator.get_by_role("button").filter(has_text='Сбросить Фильтры'), + "reset_button") + + # Действия: + def add_filtering_parameter(self, name: str, title: str) -> None: + """Добавляет поле задания параметров фильтрации по заданному имени.""" + + loc = self.sidebar_locator.locator("//div[contains(@class, 'scrollarea__body')]").\ + get_by_role("combobox").filter(has_text=title) + self.filtering_parameters[name] = SelectionBarComponent(self.page, loc) + + def get_filtering_parameter(self, name: str) -> SelectionBarComponent | None: + """Возвращает поле задания параметров фильтрации по заданному или None, если не найдено.""" + + return self.filtering_parameters.get(name) + + def get_start_time_filter(self) -> DateInput: + """Возвращает поле задания параметров фильтрации даты начала.""" + + return self.start_time_filter + + def get_finish_time_filter(self) -> DateInput: + """Возвращает поле задания параметров фильтрации даты окончания.""" + + return self.finish_time_filter + + def click_apply_button(self) -> None: + """Клик по кнопке применения фильтра.""" + + self.apply_button.click() + + def click_reset_button(self) -> None: + """Клик по кнопке сброса фильтра.""" + + self.reset_button.click() + + # Проверки: + def check_content(self) -> None: + """Проверяет наличие постоянных полей панели параметров фильтрации.""" + + self.should_be_toolbar() + self.start_time_filter.check_content("Дата начала") + self.finish_time_filter.check_content("Дата окончания") + + self.check_apply_button_visibility() + self.check_reset_button_visibility() + + + def check_vertical_scrolling(self, locator: str| Locator) -> bool: + """Проверяет возможность вертикальной прокрутки формы.""" + + return self.is_scrollable_vertically(locator) + + def check_apply_button_visibility(self) -> None: + """Проверяет наличие кнопки применения фильтра.""" + + self.apply_button.check_visibility("Apply Filter Button is missing") + + def check_reset_button_visibility(self) -> None: + """Проверяет наличие кнопки сброса фильтра.""" + + self.reset_button.check_visibility("Reset Filter Button is missing") + + def should_be_toolbar(self) -> None: + """Проверяет наличие тулбара. + + Raises: + AssertionError: Если тулбар отсутствует. + """ + + self.toolbar.check_toolbar_presence_by_locator_and_title(self.sidebar_locator, + "Sidebar Filter form toolbar is missing") diff --git a/locators/combobox_locators.py b/locators/combobox_locators.py index 597de62..fbed277 100644 --- a/locators/combobox_locators.py +++ b/locators/combobox_locators.py @@ -27,7 +27,8 @@ class ComboboxLocators: # Выпадающие списки LISTBOX_SELECTOR: str = "//div[contains(@class, 'v-menu__content')]//div[@role='list']" + LIST_ITEMS_SELECTOR: str = "//div[contains(@class, 'v-menu__content')]//div[@role='listitem']" OPTIONS_SELECTOR: str = "//div[contains(@class, 'v-menu__content')]//div[@role='listitem']//span" # Получение выбранного значения - SELECTED_VALUE_SPAN: str = "span" + SELECTED_VALUE_SPAN: str = "span" \ No newline at end of file diff --git a/locators/selection_bar_locators.py b/locators/selection_bar_locators.py new file mode 100644 index 0000000..b0d2bfc --- /dev/null +++ b/locators/selection_bar_locators.py @@ -0,0 +1,22 @@ +"""Модуль selection_bar_locators содержит локаторы компонента панели выбора значения. + +Класс SelectionBarLocators предоставляет XPath/CSS локаторы для взаимодействия +с компонентом панели выбора значения. +""" + +class SelectionBarLocators: + """Локаторы для компонента панели выбора значения. + + Содержит XPath/CSS локаторы для: + - Кнопок открытия и очистки + - Выбранных значений + - Элементов выпадающего списка + """ + + OPEN_PARAMETERS_LIST_BUTTON = "div.v-input__icon--append" + CLEAR_SELECTION_BUTTON = "div.v-input__icon--clear" + PARAMETERS_SELECTED = "div.v-select__selections" + + # Локаторы для элементов выпадающего списка + LISTBOX = "//div[@role='listbox']" + LIST_ITEMS = "//div[@role='listbox']//div[@role='listitem']" \ No newline at end of file diff --git a/pages/create_elements_tab/__pycache__/create_child_element_tab.cpython-313.pyc b/pages/create_elements_tab/__pycache__/create_child_element_tab.cpython-313.pyc deleted file mode 100644 index be16468..0000000 Binary files a/pages/create_elements_tab/__pycache__/create_child_element_tab.cpython-313.pyc and /dev/null differ diff --git a/pages/create_elements_tab/__pycache__/create_rack_element_tab.cpython-313.pyc b/pages/create_elements_tab/__pycache__/create_rack_element_tab.cpython-313.pyc deleted file mode 100644 index a8b9842..0000000 Binary files a/pages/create_elements_tab/__pycache__/create_rack_element_tab.cpython-313.pyc and /dev/null differ diff --git a/pages/create_elements_tab/create_rack_element_tab.py b/pages/create_elements_tab/create_rack_element_tab.py index 682fa32..5965815 100644 --- a/pages/create_elements_tab/create_rack_element_tab.py +++ b/pages/create_elements_tab/create_rack_element_tab.py @@ -7,7 +7,7 @@ from playwright.sync_api import Page, expect from elements.tooltip_button_element import TooltipButton from components.toolbar_component import ToolbarComponent -from components.dropdown_list_component import DropdownList +from components_derived.selection_bar_component import SelectionBarComponent from pages.main_page import MainPage from pages.base_page import BasePage from components.base_component import BaseComponent @@ -82,8 +82,8 @@ class CreateRackElementTab(BasePage): self.toolbar.add_tooltip_button(create_button_locator, "add") self.toolbar.add_tooltip_button(cancel_button_locator, "cancel") - # Инициализация компонента выпадающего списка - self.dropdown = DropdownList(page) + # Инициализация компонента панели выбора значения для работы с combobox + self.selection_bar = SelectionBarComponent(page, ComboboxLocators.OBJECT_CLASS_COMBOBOX) # =============== МЕТОДЫ ДЕЙСТВИЙ ======================== @@ -104,11 +104,7 @@ class CreateRackElementTab(BasePage): Открывает выпадающий список combobox 'Класс объекта учета'. """ logger.info("Открытие combobox 'Класс объекта учета'...") - self.dropdown.open_combobox( - ComboboxLocators.OBJECT_CLASS_COMBOBOX, - ComboboxLocators.LISTBOX_SELECTOR, - ComboboxLocators.COMBOBOX_ICON - ) + self.selection_bar.open_values_list() def select_object_class(self, class_name: str) -> None: """ @@ -125,7 +121,8 @@ class CreateRackElementTab(BasePage): # Открываем combobox self.open_object_class_combobox() - self.dropdown.click_item_with_text(class_name) + # Выбираем значение из списка + self.selection_bar.select_value(class_name) # Проверяем что выбор произошел self.wait_for_timeout(1000) @@ -139,6 +136,30 @@ class CreateRackElementTab(BasePage): logger.info(f"Класс объекта '{class_name}' успешно выбран") + def get_object_class_options(self) -> list[str]: + """ + Получает список доступных опций из combobox. + + Returns: + list[str]: Список доступных классов объектов + """ + logger.info("Получение списка опций combobox 'Класс объекта учета'...") + + available_options = self.selection_bar.get_available_options() + + logger.info(f"Доступные опции класса объекта: {available_options}") + return available_options + + def get_selected_object_class(self) -> str: + """ + Получает выбранный класс объекта учета. + + Returns: + str: Выбранный класс объекта или пустая строка если ничего не выбрано + """ + # Получаем заголовок панели выбора + return self.selection_bar.get_selection_bar_title() + def fill_rack_data(self, name: str, height: str = "42", depth: str = "1000", serial: str = "", inventory: str = "", comment: str = "", cable_entry: str = "", state: str = "", owner: str = "", @@ -349,31 +370,6 @@ class CreateRackElementTab(BasePage): logger.info("Все поля формы стойки очищены") - def get_object_class_options(self) -> list[str]: - """ - Получает список доступных опций из combobox. - - Returns: - list[str]: Список доступных классов объектов - """ - return self.dropdown.get_combobox_options( - ComboboxLocators.OBJECT_CLASS_COMBOBOX, - ComboboxLocators.LISTBOX_SELECTOR, - ComboboxLocators.COMBOBOX_ICON - ) - - def get_selected_object_class(self) -> str: - """ - Получает выбранный класс объекта учета. - - Returns: - str: Выбранный класс объекта или пустая строка если ничего не выбрано - """ - return self.dropdown.get_selected_combobox_value( - ComboboxLocators.OBJECT_CLASS_COMBOBOX, - ComboboxLocators.SELECTED_VALUE_SPAN - ) - # =============== МЕТОДЫ ПРОВЕРОК ======================== def check_rack_exists(self, rack_name: str) -> bool: """ diff --git a/pages/rack_tab/__pycache__/rack_create.cpython-313.pyc b/pages/rack_tab/__pycache__/rack_create.cpython-313.pyc deleted file mode 100644 index 561470c..0000000 Binary files a/pages/rack_tab/__pycache__/rack_create.cpython-313.pyc and /dev/null differ diff --git a/pages/rack_tab/__pycache__/rack_general_info.cpython-313.pyc b/pages/rack_tab/__pycache__/rack_general_info.cpython-313.pyc deleted file mode 100644 index 94269cb..0000000 Binary files a/pages/rack_tab/__pycache__/rack_general_info.cpython-313.pyc and /dev/null differ diff --git a/pages/rack_tab/__pycache__/rack_tab.cpython-313.pyc b/pages/rack_tab/__pycache__/rack_tab.cpython-313.pyc deleted file mode 100644 index cdf158a..0000000 Binary files a/pages/rack_tab/__pycache__/rack_tab.cpython-313.pyc and /dev/null differ