diff --git a/components/checkbox_group_component.py b/components/checkbox_group_component.py new file mode 100644 index 0000000..9f52260 --- /dev/null +++ b/components/checkbox_group_component.py @@ -0,0 +1,155 @@ +"""Модуль компонента группы чек-боксов. + +Содержит класс CheckboxGroupComponent для работы с группами чек-боксов, +в том числе в выпадающих списках с множественным выбором. +""" + +import re +from playwright.sync_api import Page, Locator, expect +from tools.logger import get_logger +from components.base_component import BaseComponent + +logger = get_logger("CHECKBOX_GROUP_COMPONENT") + +class CheckboxGroupComponent(BaseComponent): + """Компонент для работы с группами чек-боксов. + + Позволяет выбирать/снимать выбор с чек-боксов в группе, + получать список выбранных элементов и проверять их состояние. + Может использоваться как для выпадающих списков с множественным выбором, + так и для любых других групп чек-боксов на странице. + """ + + def __init__(self, page: Page) -> None: + """Инициализирует компонент группы чек-боксов. + + Args: + page: Экземпляр страницы Playwright. + """ + super().__init__(page) + + def get_checkbox_locator(self, text: str, container_locator: Locator | None = None) -> Locator: + """Возвращает локатор чек-бокса с указанным текстом. + + Args: + text (str): Текст элемента для выбора. + container_locator (Locator | None): Локатор контейнера с чек-боксами. + Если не указан, поиск по всей странице. + + Returns: + Locator: Локатор чек-бокса. + """ + if container_locator: + checkbox_locator = container_locator.get_by_role("listitem").filter(has_text=text).get_by_role("checkbox") + else: + checkbox_locator = self.page.get_by_role("listitem").filter(has_text=text).get_by_role("checkbox") + + if checkbox_locator.count() > 1: + rtext = f"^{text}$" + if container_locator: + checkbox_locator = container_locator.get_by_role("listitem").filter( + has_text=re.compile(rtext) + ).get_by_role("checkbox") + else: + checkbox_locator = self.page.get_by_role("listitem").filter( + has_text=re.compile(rtext) + ).get_by_role("checkbox") + + expect(checkbox_locator).to_be_visible(), \ + f"Checkbox with text '{text}' is missing or not visible" + return checkbox_locator + + def uncheck_by_text(self, text: str, container_locator: Locator | None = None) -> None: + """Снимает выбор с чек-бокса по указанному тексту. + + Args: + text (str): Текст чек-бокса для снятия выбора. + container_locator (Locator | None): Локатор контейнера с чек-боксами. + """ + logger.info(f"Unchecking checkbox with text: {text}") + self.get_checkbox_locator(text, container_locator).uncheck(force=True) + + def check_by_text(self, text: str, container_locator: Locator | None = None) -> None: + """Выбирает чек-бокс по указанному тексту. + + Args: + text (str): Текст чек-бокса для выбора. + container_locator (Locator | None): Локатор контейнера с чек-боксами. + """ + logger.info(f"Checking checkbox with text: {text}") + self.get_checkbox_locator(text, container_locator).check(force=True) + + def get_checked_items(self, container_locator: str | Locator) -> list[str]: + """Возвращает список текстов отмеченных чек-боксов. + + Args: + container_locator (str | Locator): Локатор контейнера с группой чек-боксов. + + Returns: + list[str]: Список текстов выбранных чек-боксов. + """ + checked_items = [] + list_container = self.get_locator(container_locator) + items = list_container.get_by_role("listitem").all() + + for item in items: + if item.get_by_role("checkbox").is_checked(): + item_text = item.text_content().strip() + if item_text: + checked_items.append(item_text) + + logger.info(f"Checked items: {checked_items}") + return checked_items + + def are_items_checked(self, container_locator: str | Locator, expected_items: list[str]) -> bool: + """Проверяет, что указанные чек-боксы выбраны. + + Args: + container_locator (str | Locator): Локатор контейнера с группой чек-боксов. + expected_items (list[str]): Список ожидаемых выбранных элементов. + + Returns: + bool: True если все указанные чек-боксы выбраны. + """ + checked_items = self.get_checked_items(container_locator) + return all(item in checked_items for item in expected_items) + + def check_all(self, container_locator: str | Locator) -> None: + """Выбирает все чек-боксы в группе. + + Args: + container_locator (str | Locator): Локатор контейнера с группой чек-боксов. + """ + logger.info("Checking all checkboxes in group") + list_container = self.get_locator(container_locator) + checkboxes = list_container.get_by_role("checkbox").all() + + for checkbox in checkboxes: + if not checkbox.is_checked(): + checkbox.check(force=True) + + def uncheck_all(self, container_locator: str | Locator) -> None: + """Снимает выбор со всех чек-боксов в группе. + + Args: + container_locator (str | Locator): Локатор контейнера с группой чек-боксов. + """ + logger.info("Unchecking all checkboxes in group") + list_container = self.get_locator(container_locator) + checkboxes = list_container.get_by_role("checkbox").all() + + for checkbox in checkboxes: + if checkbox.is_checked(): + checkbox.uncheck(force=True) + + def get_items_count(self, container_locator: str | Locator) -> int: + """Возвращает количество чек-боксов в группе. + + Args: + container_locator (str | Locator): Локатор контейнера с группой чек-боксов. + + Returns: + int: Количество чек-боксов. + """ + list_container = self.get_locator(container_locator) + return list_container.get_by_role("checkbox").count() diff --git a/components_derived/interactive_dropdown_list.py b/components_derived/interactive_dropdown_list.py deleted file mode 100644 index e85fd30..0000000 --- a/components_derived/interactive_dropdown_list.py +++ /dev/null @@ -1,84 +0,0 @@ -"""Модуль interactive_dropdown_list_component содержит класс для работы с интерактивными выпадающими списками, -позволяющими сделать выбор нескольких элементов. - -Класс InteractiveDropdownList наследует базовый функционал BaseComponent и добавляет -методы для взаимодействия с интерактивными выпадающими списками на странице. -""" - -import re -from playwright.sync_api import Page, Locator, expect -from tools.logger import get_logger -from components.base_component import BaseComponent - -logger = get_logger("INTERACTIVE_DROPDOWN_LIST") - -class InteractiveDropdownList(BaseComponent): - """Класс для работы с выпадающими списками. - - Наследует функциональность BaseElement и добавляет специфичные - методы для выбора и проверки элементов списка. - """ - - def __init__(self, page: Page) -> None: - """Инициализирует компонент интерактивного выпадающего списка. - - Args: - page: Экземпляр страницы Playwright. - """ - - super().__init__(page) - - # Действия: - def get_checkbox_locator(self, text: str) -> Locator: - """Возвращает локатор чек-бокса для элемента списка с указанным текстом. - - Args: - text (str): Текст элемента для выбора. - """ - - checkbox_locator = self.page.get_by_role("listitem").filter(has_text=text).get_by_role("checkbox") - if checkbox_locator.count() > 1: - rtext = f"^{text}$" - checkbox_locator = self.page.get_by_role("listitem").filter( - has_text=re.compile(rtext) - ).get_by_role("checkbox") - - expect(checkbox_locator).to_be_visible(), \ - f"Checkbox for dropdown list item with text {text} is missing" - return checkbox_locator - - def deselect_item_with_text(self, text: str) -> None: - """Выбирает элемент списка по указанному тексту. - - Args: - text (str): Текст элемента для выбора. - """ - - self.get_checkbox_locator(text).uncheck(force=True) - - def select_item_with_text(self, text: str) -> None: - """Выбирает элемент списка по указанному тексту. - - Args: - text (str): Текст элемента для выбора. - """ - self.get_checkbox_locator(text).check(force=True) - - def get_selected_items(self, locator: str|Locator) -> list[str]: - """Возвращает список отмеченных элементов.""" - - selected_items = [] - - list_locator = self.get_locator(locator) - - items = list_locator.get_by_role("listitem").all() - - for item in items: - if item.get_by_role("checkbox").is_checked(): - item_text = item.text_content().strip() - if item_text: - selected_items.append(item_text) - - return selected_items - - # Проверки: diff --git a/pages/push_notifications_settings_tab.py b/pages/push_notifications_settings_tab.py index d53e97b..67d6054 100644 --- a/pages/push_notifications_settings_tab.py +++ b/pages/push_notifications_settings_tab.py @@ -9,7 +9,7 @@ from locators.settings_form_locators import SettingsFormLocators from elements.text_input_element import TextInput from components.alert_component import AlertComponent from components_derived.settings_form_component import SettingsFormComponent -from components_derived.interactive_dropdown_list import InteractiveDropdownList +from components.checkbox_group_component import CheckboxGroupComponent # Изменен импорт from pages.base_page import BasePage @@ -40,13 +40,13 @@ class PushNotificationsSettingsTab(BasePage): message_setting_input = TextInput(page, loc_message_input, "message_setting_input") self.settings_form.add_content_item("message_setting_input", message_setting_input) - loc = self.input_fields_locators.get("Пользователи") users_setting_input = TextInput(page, loc.get_by_role("combobox"), "users_setting_input") self.settings_form.add_content_item("users_setting_input", users_setting_input) - self.settings_form.add_content_item("users_list", InteractiveDropdownList(page)) + # Используем новый компонент CheckboxGroupComponent + self.settings_form.add_content_item("users_checkbox_group", CheckboxGroupComponent(page)) self.settings_form.add_tooltip_button(page.locator(SettingsFormLocators.PUSH_NOTIFICATIONS_BUTTON_SUBMIT), "submit_button") @@ -104,10 +104,10 @@ class PushNotificationsSettingsTab(BasePage): assert len(users) != 0, "Users list should not be empty" self.settings_form.get_content_item("users_setting_input").click() - users_list = self.settings_form.get_content_item("users_list") + users_checkbox_group = self.settings_form.get_content_item("users_checkbox_group") for user in users: - users_list.deselect_item_with_text(user) + users_checkbox_group.uncheck_by_text(user) # Закрываем выпадающий список (кликаем вне его) self.page.mouse.click(10, 10) @@ -118,10 +118,10 @@ class PushNotificationsSettingsTab(BasePage): assert len(users) != 0, "Users list should not be empty" self.settings_form.get_content_item("users_setting_input").click() - users_list = self.settings_form.get_content_item("users_list") + users_checkbox_group = self.settings_form.get_content_item("users_checkbox_group") for user in users: - users_list.select_item_with_text(user) + users_checkbox_group.check_by_text(user) # Закрываем выпадающий список (кликаем вне его) self.page.mouse.click(10, 10) @@ -142,10 +142,10 @@ class PushNotificationsSettingsTab(BasePage): f"Misscomparison input field names: Expected {expected_input_field_names}, Actual {actual_input_field_names}" for name in self.settings_form.content_items.keys(): - if name == "users_list": + if name == "users_checkbox_group": self.settings_form.get_content_item("users_setting_input").click() - users_list = self.settings_form.get_content_item(name) - selected_users = users_list.get_selected_items(SettingsFormLocators.DROPDOWN_LIST) + users_checkbox_group = self.settings_form.get_content_item(name) + selected_users = users_checkbox_group.get_checked_items(SettingsFormLocators.DROPDOWN_LIST) assert len(selected_users) == 0, "There should be no selected users" else: item = self.settings_form.get_content_item(name)