diff --git a/components/base_component.py b/components/base_component.py index 8855159..f960f3e 100644 --- a/components/base_component.py +++ b/components/base_component.py @@ -59,6 +59,20 @@ class BaseComponent: # return elements # Проверки: + def check_absence(self, locator: str | Locator, msg: str) -> None: + """Проверка отсутствия элемента на странице. + + Args: + locator: локатор элемента (строка или объект Locator). + msg: сообщение об ошибке при неудачной проверке. + + Raises: + AssertionError: если элемент виден на странице. + """ + + loc = self.get_locator(locator) + expect(loc).to_be_hidden(timeout=12000), msg + def check_visibility(self, locator: str | Locator, msg: str) -> None: """Проверка видимости элемента на странице. diff --git a/components/eventbar_component.py b/components/eventbar_component.py index 552ec1a..8237bb8 100644 --- a/components/eventbar_component.py +++ b/components/eventbar_component.py @@ -56,17 +56,18 @@ class EventPanelComponent(BaseComponent): get_by_role("button").filter(has_text='expand_more') button_locator.click() - def click_user_button(self) -> None: + def click_user_button(self) -> UserCard: """Выполняет нажатие кнопки пользователя.""" self.should_be_user_button() self.user_button.click() + return self.user_card def do_logout(self) -> None: """Выполняет выход из системы.""" - self.click_user_button() - self.user_card.click_logout_button() + user_card = self.click_user_button() + user_card.click_logout_button() def get_event_tooltip_texts(self) -> []: """Возвращает список текстов всплывающих подсказок кнопок счетчиков событий.""" diff --git a/components_derived/dialog_user_settings.py b/components_derived/dialog_user_settings.py new file mode 100644 index 0000000..9363d4e --- /dev/null +++ b/components_derived/dialog_user_settings.py @@ -0,0 +1,180 @@ +"""Модуль диалогового окна просмотра сессионных данных пользователя. + +Содержит класс для работы с диалоговым окном просмотра +сессионных данных пользователя через Playwright. +""" + +from playwright.sync_api import Page, Locator +from tools.logger import get_logger +from locators.user_card_locators import UserCardLocators +from elements.tooltip_button_element import TooltipButton +from elements.text_element import Text +from elements.button_element import Button +from components.table_component import TableComponent +from components.base_component import BaseComponent + +logger = get_logger("USER_SETTINGS_DIALOG") + + +class UserSettingsDialogWindow(BaseComponent): + """Компонент диалоговое окно просмотра сессионных данных пользователя. + + Предоставляет методы для взаимодействия с элементами + диалогового окна просмотра сессионных данных пользовател. + """ + + def __init__(self, page: Page): + """Инициализирует компонент диалоговое окно просмотра сессионных данных пользовател. + + Args: + page: Экземпляр страницы Playwright. + """ + + super().__init__(page) + + dialog_window_locator = page.locator(UserCardLocators.DIALOG_USER_SETTINGS) + + self.dialog_window_title = Text(page, + dialog_window_locator.\ + locator(UserCardLocators.TITLE_DIALOG_USER_SETTINGS), + "dialog window title") + self.close_button = Button(page, + dialog_window_locator.\ + locator(UserCardLocators.HEADER_DIALOG_USER_SETTINGS). \ + get_by_role("button"), + "close button") + + self.user_settings_table = TableComponent(page) + + # Действия: + def click_close_button(self): + """Нажимает кнопку закрытия окна. + + Выполняет клик по кнопке 'Закрыть' на строке с заголовком окна. + """ + + self.close_button.click() + + def get_delete_button_from_row(self, row_index: int) -> TooltipButton: + """Возвращает кнопку удаления сеанса для указанной строки. + + Args: + row_index: Индекс строки в таблице. + + Returns: + TooltipButton: Кнопка с подсказкой. + + Raises: + AssertionError: Если строка не найдена. + """ + + row_locator = self.user_settings_table.get_row_locator( + UserCardLocators.TABLE_WORK_AREA, + row_index + ) + assert isinstance(row_locator, Locator), f"Row with index {row_index} is missing" + + button_locator = row_locator.get_by_role("button") + return TooltipButton(self.page, button_locator, "delete_button") + + # Проверки: + def check_content(self) -> None: + """Проверяет содержимое окно просмотра сессионных данных пользователя.""" + + self.dialog_window_title.check_have_text("Настройки", \ + "Title 'Настройки' is missing on user settings window top") + self.close_button.check_visibility("Close button is missing on user settings window top") + + self.should_be_user_settings_table() + self.check_user_settings_table_content() + + def check_window_absence(self) -> None: + """Проверка отсутствия окна на странице. + + Raises: + AssertionError: если окнo присутствует на странице. + """ + + self.check_absence(UserCardLocators.DIALOG_USER_SETTINGS, \ + "User settings dialog window is present") + + def check_window_visibility(self) -> None: + """Проверка видимости окна на странице. + + Raises: + AssertionError: если окнo отсутствует на странице. + """ + + self.check_visibility(UserCardLocators.DIALOG_USER_SETTINGS, \ + "User settings dialog window is missing") + + + def check_user_settings_table_content(self) -> None: + """Проверяет содержимое таблицы сессионных данных пользователя. + + + Raises: + AssertionError: Если таблица пуста или заголовки неверны. + """ + + expected_headers = [ + 'ПОЛЬЗОВАТЕЛЬ', + 'IP АДРЕС', + 'ВРЕМЯ НАЧАЛА СЕССИИ', + 'ДЕЙСТВИЯ' + ] + + table_content = self.user_settings_table.read(UserCardLocators.TABLE_WORK_AREA) + len_table_content = len(table_content) + + if len_table_content == 0: + assert False, "The contents of the table are missing" + + actual_headers = table_content[0] + + assert actual_headers == expected_headers,\ + f"Expected table headers {expected_headers} are not equal {actual_headers}" + + if len_table_content == 1: + assert False, "Table body is missing" + + for index in range(len_table_content - 1): + self.should_be_delete_button_on_user_settings_table_row(index, "Удалить") + + def should_be_user_settings_table(self) -> None: + """Проверяет наличие таблицы сессионных данных пользователя. + + Raises: + AssertionError: Если таблица отсутствует. + """ + + self.user_settings_table.check_visibility( + UserCardLocators.TABLE_WORK_AREA, + "User settings table is missing") + + def should_be_delete_button_on_user_settings_table_row(self, + row_index: int, + tooltip: str + ) -> None: + """Проверяет наличие кнопки удаления в строке таблицы. + + Args: + row_index: Индекс проверяемой строки. + tooltip: Ожидаемый текст подсказки. + + Raises: + AssertionError: Если кнопка отсутствует или подсказка неверна. + """ + + delete_button = self.get_delete_button_from_row(row_index) + + # Ожидаем исчезновения предыдущих подсказок перед проверкой + delete_button.wait_for_tooltip_to_disappear() + + delete_button.check_visibility( + f"Delete session button is missing on {row_index} row" + ) + delete_button.check_tooltip_with_text(tooltip) + + # Ожидаем исчезновения подсказки после проверки + delete_button.wait_for_tooltip_to_disappear() diff --git a/components_derived/user_card.py b/components_derived/user_card.py index 4edde84..cc0cb63 100644 --- a/components_derived/user_card.py +++ b/components_derived/user_card.py @@ -11,6 +11,7 @@ from elements.button_element import Button from data.roles_dict import roles_dict from data.environment import host from components.base_component import BaseComponent +from components_derived.dialog_user_settings import UserSettingsDialogWindow logger = get_logger("USER_CARD") @@ -60,8 +61,33 @@ class UserCard(BaseComponent): "settings button" ) + # self.close_button = Button( + # page, + # page.get_by_role("button", name="Закрыть"), + # "close button" + # ) + + # окна, отрываемые после нажатия кнопок + self.user_settings_dialog_window = UserSettingsDialogWindow(page) + # Действия: - def click_logout_button(self): + # def click_close_button(self): + # """Нажимает кнопку выхода из карточки пользователя. + + # Выполняет клик по кнопке 'Закрыть' в карточке пользователя. + # """ + + # self.close_button.click() + + def click_change_password_button(self) -> None: + """Нажимает кнопку открытия окна изменения пароля. + + Выполняет клик по кнопке 'Изменить пароль' в карточке пользователя. + """ + + self.change_password_button.click() + + def click_logout_button(self) -> None: """Нажимает кнопку выхода из системы. Выполняет клик по кнопке 'Выйти' в карточке пользователя. @@ -69,9 +95,19 @@ class UserCard(BaseComponent): self.logout_button.click() + def click_settings_button(self) -> UserSettingsDialogWindow: + """Нажимает кнопку открытия окна пользовательских сессий. + + Выполняет клик по кнопке 'Настройки' в карточке пользователя. + """ + + self.settings_button.click() + return self.user_settings_dialog_window + # Проверки: - def check_content(self): - """Проверяет наличие и корректность элементов карточки пользователя.""" + def check_content(self) -> None: + """Проверяет наличие и корректность элементов карточки пользователя + в зависимости от его роли в системе.""" current_user_credential = host.get_current_user_credential() @@ -96,4 +132,9 @@ class UserCard(BaseComponent): self.logout_button.check_visibility("Logout button is missing on user card") self.change_password_button.check_visibility("Change password button is missing on user card") - self.settings_button.check_visibility("Settings button is missing on user card") + # self.close_button.check_visibility("Close button is missing on user card") + + admin_roles = ["Администратор", + "Специалист информационной безопасности"] + if role in admin_roles: + self.settings_button.check_visibility("Settings button is missing on user card") diff --git a/elements/tooltip_button_element.py b/elements/tooltip_button_element.py index f8f71cf..9ac1ce1 100644 --- a/elements/tooltip_button_element.py +++ b/elements/tooltip_button_element.py @@ -47,6 +47,14 @@ class TooltipButton(BaseElement): self.page.wait_for_timeout(300) return tooltip.text_content().strip() + def wait_for_tooltip_to_disappear(self, timeout: int = 5000) -> None: + """Ожидает исчезновения всех активных всплывающих подсказок.""" + + self.page.mouse.click(10, 10) + tooltip_locator = self.page.locator(".v-tooltip__content.menuable__content__active") + + tooltip_locator.wait_for(state="hidden", timeout=timeout) + # Проверки: def check_tooltip_with_text(self, expected_text: str) -> None: """Проверяет соответствие текста всплывающей подсказки. diff --git a/locators/user_card_locators.py b/locators/user_card_locators.py index 498cb4d..d393d47 100644 --- a/locators/user_card_locators.py +++ b/locators/user_card_locators.py @@ -9,7 +9,15 @@ class UserCardLocators: Содержит XPath локаторы для: CARD_USER (str): карточки текущего пользователя. + DIALOG_USER_SETTINGS (str): окна просмотра сессионных данных пользователей. + HEADER_DIALOG_USER_SETTINGS (str): строки с заголовком окна и кнопкой закрытия. + TITLE_DIALOG_USER_SETTINGS (str): заголовка окна. + TABLE_WORK_AREA (str): таблицы с сессионными данными пользователей. """ CARD_USER = "//div[@class='v-card__text']" + DIALOG_USER_SETTINGS = "//div[@class='dialog-drag']" + HEADER_DIALOG_USER_SETTINGS = "xpath=/div[@class='dialog-header']" + TITLE_DIALOG_USER_SETTINGS = "xpath=/div[@class='dialog-header']/div[@class='title']" + TABLE_WORK_AREA = "//div[@class='dialog-body']//table" diff --git a/pages/base_page.py b/pages/base_page.py index 025927e..f52513a 100644 --- a/pages/base_page.py +++ b/pages/base_page.py @@ -3,12 +3,11 @@ Содержит общие методы для взаимодействия со страницей и API. """ import time - +import json from typing import Dict, Any from playwright.sync_api import Page, Response, APIRequestContext, expect from data.environment import host from tools.logger import get_logger -import json logger = get_logger("BASE_PAGE") @@ -246,11 +245,3 @@ class BasePage: return True assert compare_lists(actual, expected), msg - - def wait_for_tooltip_to_disappear(self, timeout: int = 5000) -> None: - """Ожидает исчезновения всех активных всплывающих подсказок.""" - - self.page.mouse.click(10, 10) - tooltip_locator = self.page.locator(".v-tooltip__content.menuable__content__active") - - tooltip_locator.wait_for(state="hidden", timeout=timeout) diff --git a/pages/main_page.py b/pages/main_page.py index 5269bda..0bebeb8 100644 --- a/pages/main_page.py +++ b/pages/main_page.py @@ -6,6 +6,7 @@ from playwright.sync_api import Page from locators.navigation_panel_locators import NavigationPanelLocators +from components_derived.user_card import UserCard from components.navbar_component import NavigationPanelComponent from components.eventbar_component import EventPanelComponent from pages.base_page import BasePage @@ -61,10 +62,10 @@ class MainPage(BasePage): self.event_panel.click_expand_more_button() - def click_user_button(self) -> None: + def click_user_button(self) -> UserCard: """Выполняет нажатие кнопки пользователя.""" - self.event_panel.click_user_button() + return self.event_panel.click_user_button() def do_logout(self) -> None: """Выполняет выход из системы.""" @@ -164,7 +165,7 @@ class MainPage(BasePage): item_name ) - def check_user_card_content(self): - """Проверяет наличие и корректность элементов карточки пользователя.""" + # def check_user_card_content(self): + # """Проверяет наличие и корректность элементов карточки пользователя.""" - self.event_panel.check_user_card_content() + # self.event_panel.check_user_card_content() diff --git a/pages/session_tab.py b/pages/session_tab.py index e80087e..e277f9c 100644 --- a/pages/session_tab.py +++ b/pages/session_tab.py @@ -331,18 +331,18 @@ class SessionsTab(BasePage): Raises: AssertionError: Если кнопка отсутствует или подсказка неверна. """ + delete_button = self.get_delete_session_button_from_row(row_index) # Ожидаем исчезновения предыдущих подсказок перед проверкой - self.wait_for_tooltip_to_disappear() + delete_button.wait_for_tooltip_to_disappear() - delete_button = self.get_delete_session_button_from_row(row_index) delete_button.check_visibility( f"Delete session button is missing on {row_index} row" ) delete_button.check_tooltip_with_text(tooltip) # Ожидаем исчезновения подсказки после проверки - self.wait_for_tooltip_to_disappear() + delete_button.wait_for_tooltip_to_disappear() def should_be_session_in_table(self, token: str) -> None: diff --git a/tests/e2e/test_event_panel.py b/tests/e2e/test_event_panel.py index f8d28cd..d82247a 100644 --- a/tests/e2e/test_event_panel.py +++ b/tests/e2e/test_event_panel.py @@ -4,7 +4,7 @@ панели событий в приложении. """ -import pytest +# import pytest from playwright.sync_api import Page from pages.main_page import MainPage from pages.login_page import LoginPage @@ -116,19 +116,3 @@ class TestEventPanel: "Expand less button should be present" assert mp.check_expand_more_button(), \ "Expand more button should be absent" - - # @pytest.mark.develop - def test_user_card_content(self, browser: Page) -> None: - """Проверяет наличие и корректность элементов карточки пользователя. - - Args: - browser: Экземпляр страницы Playwright. - """ - - lp = LoginPage(browser) - lp.do_login() - - mp = MainPage(browser) - - mp.click_user_button() - mp.check_user_card_content() diff --git a/tests/e2e/test_user_card.py b/tests/e2e/test_user_card.py new file mode 100644 index 0000000..5edbeac --- /dev/null +++ b/tests/e2e/test_user_card.py @@ -0,0 +1,76 @@ +"""Модуль тестов карточки пользователя. + +Содержит тесты для проверки функциональности +карточки пользователя в приложении. +""" + +import pytest +from playwright.sync_api import Page +from pages.main_page import MainPage +from pages.login_page import LoginPage + +# @pytest.mark.smoke +class TestUserCard: + """Класс тестов для проверки карточки пользователя. + + Тесты покрывают следующие сценарии: + 1. test_user_card_content: Проверяет содержимое карточки пользователя + + Атрибуты: + browser: Фикстура для работы с браузером. + """ + + # @pytest.mark.develop + def test_user_card_content(self, browser: Page) -> None: + """Проверяет наличие и корректность элементов карточки пользователя. + + Args: + browser: Экземпляр страницы Playwright. + """ + + lp = LoginPage(browser) + lp.do_login() + + mp = MainPage(browser) + + user_card = mp.click_user_button() + user_card.check_content() + + # @pytest.mark.develop + def test_open_close_user_settings_window(self, browser: Page) -> None: + """Проверяет возможностьоткрытия и закрытия диалогового окна просмотра сессионных данных пользователя. + + Args: + browser: Экземпляр страницы Playwright. + """ + + lp = LoginPage(browser) + lp.do_login() + + mp = MainPage(browser) + + user_card = mp.click_user_button() + user_settings_window = user_card.click_settings_button() + + user_settings_window.check_window_visibility() + user_settings_window.click_close_button() + user_settings_window.check_window_absence() + + # @pytest.mark.develop + def test_user_settings_window_content(self, browser: Page) -> None: + """Проверяет наличие и корректность элементов диалогового окна просмотра сессионных данных пользователя. + + Args: + browser: Экземпляр страницы Playwright. + """ + + lp = LoginPage(browser) + lp.do_login() + + mp = MainPage(browser) + + user_card = mp.click_user_button() + user_settings_window = user_card.click_settings_button() + + user_settings_window.check_window_visibility() + user_settings_window.check_content()