254 lines
11 KiB
Python
254 lines
11 KiB
Python
"""Модуль компонента панели выбора значения.
|
||
|
||
Содержит класс для работы с компонентом панели выбора значения через 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)
|
||
print(self.selection_bar_locator)
|
||
|
||
# Действия:
|
||
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) -> list[str]:
|
||
"""Возвращает список всех доступных опций из выпадающего списка.
|
||
|
||
Returns:
|
||
list[str]: Список доступных опций
|
||
"""
|
||
|
||
logger.info("Getting available options from dropdown list...")
|
||
|
||
# Открываем выпадающий список
|
||
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"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()
|
||
return selected_values[0].splitlines()
|
||
|
||
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.page.locator(SelectionBarLocators.LIST_ACTIVE).wait_for(state="attached")
|
||
# 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 check_field_error_highlighted(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
|
||
|
||
assert has_error, 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_error_not_highlighted(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
|
||
|
||
# Проверяем отсутствие классов ошибки
|
||
if parent_container.count() > 0:
|
||
has_error = parent_container.locator(SelectionBarLocators.ERROR_CSS_SELECTORS).count() > 0
|
||
|
||
assert not has_error, f"Field '{field_name}' is highlighted with error"
|
||
|
||
logger.info(f"Field '{field_name}' correctly has no error highlighting")
|
||
|
||
def check_field_visibility(self, msg: str) -> None:
|
||
"""Проверка видимости элемента на странице.
|
||
|
||
Args:
|
||
msg: сообщение об ошибке при неудачной проверке.
|
||
|
||
Raises:
|
||
AssertionError: если элемент не виден на странице.
|
||
"""
|
||
|
||
self.check_visibility(self.selection_bar_locator, msg)
|
||
|
||
|
||
def should_be_clear_selection_button(self) -> None:
|
||
"""Проверяет наличие кнопки отмены выбранного значения.
|
||
|
||
Raises:
|
||
AssertionError: Если кнопка отсутствует.
|
||
"""
|
||
|
||
clear_button_locator = self.selection_bar_locator.locator(
|
||
SelectionBarLocators.CLEAR_SELECTION_BUTTON
|
||
)
|
||
expect(clear_button_locator).to_be_visible(), "Clear selection button is missing"
|
||
|
||
def should_be_open_list_button(self) -> None:
|
||
"""Проверяет наличие кнопки раскрытия списка параметров.
|
||
|
||
Raises:
|
||
AssertionError: Если кнопка отсутствует.
|
||
"""
|
||
|
||
open_list_button_locator = self.selection_bar_locator.locator(
|
||
SelectionBarLocators.OPEN_PARAMETERS_LIST_BUTTON
|
||
)
|
||
expect(open_list_button_locator).to_be_visible(), "Open parameters list button is missing"
|