Перенос компонентов в main:

- selection_bar_component.py
- sidebar_filter_component.py
- selection_bar_locators.py
radislav/tests_rack
Radislav 2025-11-22 11:23:06 +03:00
parent 6c6f8c18f2
commit 7b9f1f3fd9
2 changed files with 162 additions and 28 deletions

View File

@ -6,6 +6,7 @@
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
@ -18,18 +19,27 @@ class SelectionBarComponent(BaseComponent):
Предоставляет методы для взаимодействия с элементами компонента панели выбора значения.
"""
def __init__(self, page: Page, locator: str | Locator):
def __init__(self, page: Page, locator_or_text: str | Locator) -> None:
"""Инициализирует компонент панели выбора значения.
Args:
page: Экземпляр страницы Playwright.
locator: Локатор панели выбора значения (строка или объект Locator)
locator_or_text: Локатор панели выбора значения (строка или объект Locator)
или текст для поиска
"""
super().__init__(page)
# Локатор панели параметра фильтрации
self.selection_bar_locator = self.get_locator(locator)
# Определяем локатор в зависимости от типа параметра
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)
@ -37,59 +47,169 @@ class SelectionBarComponent(BaseComponent):
# Действия:
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 = self.selection_bar_locator.locator(
SelectionBarLocators.CLEAR_SELECTION_BUTTON
)
clear_button_locator.click()
def get_available_options(self) -> list[str]:
"""Возвращает список всех доступных опций из выпадающего списка """
"""Возвращает список всех доступных опций из выпадающего списка.
logger.info("Получение списка доступных опций из выпадающего списка...")
Returns:
list[str]: Список доступных опций
"""
logger.info("Getting available options from dropdown list...")
# Открываем выпадающий список
self.open_values_list()
# Ждем появления списка
self.page.wait_for_timeout(1000)
self.wait_for_timeout(1000)
# Получаем все элементы списка
options = self.selected_values_list.get_item_names(SelectionBarLocators.LIST_ITEMS)
options = self.selected_values_list.get_item_names(
SelectionBarLocators.LIST_ITEMS
)
# Закрываем список (кликаем вне его)
self.page.mouse.click(10, 10)
self.page.wait_for_timeout(500)
self.wait_for_timeout(500)
logger.info(f"Найдено доступных опций: {len(options)} - {options}")
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("//label")
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_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()
self.selection_bar_locator.click()
# Проверяем, не открыт ли уже список
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")

View File

@ -11,6 +11,7 @@ class SelectionBarLocators:
- Кнопок открытия и очистки
- Выбранных значений
- Элементов выпадающего списка
- Combobox полей
"""
OPEN_PARAMETERS_LIST_BUTTON = "div.v-input__icon--append"
@ -20,3 +21,16 @@ class SelectionBarLocators:
# Локаторы для элементов выпадающего списка
LISTBOX = "//div[@role='listbox']"
LIST_ITEMS = "//div[@role='listbox']//div[@role='listitem']"
# Локатор для родительского контейнера поля ввода
INPUT_PARENT_CONTAINER = "xpath=./ancestor::div[contains(@class, 'v-input')]"
# CSS селекторы для ошибок валидации
ERROR_CSS_SELECTORS = ".error--text, .v-input--error"
# Локаторы для заголовков и поиска по тексту
TITLE_LOCATOR = "//label"
COMBOBOX_BY_LABEL_XPATH = "//div[@role='combobox' and .//label[text()='{}']]"
# Класс для проверки активности меню
MENU_ACTIVE_CLASS = "v-select--is-menu-active"