"""Модуль компонента панели выбора значения. Содержит класс для работы с компонентом панели выбора значения через 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("SELECTION_BAR") class SelectionBarComponent(BaseComponent): """Компонент панели выбора значения. Предоставляет методы для взаимодействия с элементами компонента панели выбора значения. """ def __init__(self, page: Page, locator_or_text: str | Locator) -> None: """Инициализирует компонент панели выбора значения. Args: page: Экземпляр страницы Playwright. locator_or_text: Локатор панели выбора значения (строка или объект Locator) или текст для поиска """ super().__init__(page) # Определяем локатор в зависимости от типа параметра if isinstance(locator_or_text, Locator): # Если передан готовый Locator self.selection_bar_locator = locator_or_text elif locator_or_text.startswith(('//', '.', '#', 'xpath=', 'css=')): # Если передан строковый локатор self.selection_bar_locator = self.get_locator(locator_or_text) else: # Если передан текст - ищем по тексту label xpath = SelectionBarLocators.COMBOBOX_BY_LABEL_XPATH.format(locator_or_text) self.selection_bar_locator = self.page.locator(xpath) # При нажатии на панель появляется выпадающий список с параметрами фильтрации для выбора 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_available_options(self, locator=None) -> list[str]: """Возвращает список всех доступных опций из выпадающего списка. Returns: list[str]: Список доступных опций """ logger.info("Getting available options from dropdown list...") # Открываем выпадающий список self.open_values_list() # Ждем появления списка self.wait_for_timeout(1000) # Получаем все элементы списка if locator: options = self.selected_values_list.get_item_names(locator) else: 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"Found available options: {len(options)} - {options}") return options def get_selection_bar_title(self) -> str: """Возвращает название панели выбора значения""" title_locator = self.selection_bar_locator.locator(SelectionBarLocators.TITLE_LOCATOR) 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() ret_value = [] if len(selected_values[0]) > 1: ret_value = selected_values[0].splitlines() elif len(selected_values[0]) == 1: ret_value.append(selected_values[0]) return ret_value def clear_combobox_field(self, field_name: str, field_locator: str) -> None: """Очищает значение в combobox поле с помощью кнопки закрытия (крестика). Args: field_name: Название поля для очистки field_locator: Локатор поля combobox """ logger.info(f"Clearing combobox field '{field_name}' using close button...") # Находим поле по локатору field_container = self.page.locator(field_locator).first # Проверяем что поле видимо if not field_container.is_visible(): logger.info(f"Field '{field_name}' is not visible, skipping clearing") return # Прокручиваем до поля field_container.scroll_into_view_if_needed() self.wait_for_timeout(500) # Ищем кнопку закрытия (крестик) внутри контейнера поля close_button = field_container.locator( ComboboxLocators.COMBOBOX_CLOSE_BUTTON ) # Проверяем наличие и видимость кнопки закрытия if close_button.count() > 0 and close_button.is_visible(): # Если кнопка закрытия видима - кликаем на нее close_button.click() self.wait_for_timeout(500) logger.info(f"Combobox field '{field_name}' cleared using close button") else: # Если кнопки закрытия нет, просто логируем этот факт msg = f"Close button not found for field '{field_name}', clearing not performed" logger.info(msg) def open_values_list(self) -> None: """Открытие выпадающего списка путем нажатия на панель выбора значения""" expect(self.selection_bar_locator).to_be_visible() # Проверяем, не открыт ли уже список parent_class = self.selection_bar_locator.get_attribute("class") if parent_class and SelectionBarLocators.MENU_ACTIVE_CLASS in parent_class: logger.info("Values list is already open") return # Используем force click для обхода перекрывающих элементов logger.info("Using force click to open the list") self.selection_bar_locator.click(force=True) # Ждем появления выпадающего списка self.wait_for_timeout(1500) 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) def wait_for_timeout(self, timeout: int) -> None: """Ожидает указанное количество миллисекунд. Args: timeout: Время ожидания в миллисекундах """ self.page.wait_for_timeout(timeout) # Проверки: def check_field_highlighted_error(self, field_name: str, field_locator: str) -> None: """Проверяет, что поле подсвечено цветом ошибки (валидация не пройдена). Args: field_name: Название поля для проверки field_locator: Локатор поля для проверки """ logger.info(f"Checking field '{field_name}' for error highlighting...") field_element = self.page.locator(field_locator).first # Проверяем что поле видимо self.check_visibility(field_element, f"Field '{field_name}' not found") # Ищем родительский контейнер parent_container = field_element.locator(SelectionBarLocators.INPUT_PARENT_CONTAINER).first # Проверка классов ошибки с использованием локатора из SelectionBarLocators if parent_container.count() > 0: has_error = parent_container.locator(SelectionBarLocators.ERROR_CSS_SELECTORS).count() > 0 if not has_error: raise AssertionError(f"Field '{field_name}' is not highlighted with error color") logger.info(f"Field '{field_name}' is correctly highlighted with error color") def check_field_not_highlighted_error(self, field_name: str, field_locator: str) -> None: """Проверяет, что поле НЕ подсвечено цветом ошибки (валидация успешна). Args: field_name: Название поля для проверки field_locator: Локатор поля для проверки """ logger.info(f"Checking field '{field_name}' for absence of error highlighting...") field_element = self.page.locator(field_locator).first # Проверяем что поле видимо self.check_visibility(field_element, f"Field '{field_name}' not found") # Ищем родительский контейнер parent_container = field_element.locator(SelectionBarLocators.INPUT_PARENT_CONTAINER).first # Проверяем отсутствие классов ошибки с использованием локатора из SelectionBarLocators if parent_container.count() > 0: has_error = parent_container.locator(SelectionBarLocators.ERROR_CSS_SELECTORS).count() > 0 if has_error: raise AssertionError(f"Field '{field_name}' is highlighted with error") logger.info(f"Field '{field_name}' correctly has no error highlighting")