Radislav 2025-09-11 10:47:53 +03:00
commit 73123bceda
10 changed files with 600 additions and 47 deletions

View File

@ -3,8 +3,8 @@
Класс DropdownList наследует базовый функционал BaseComponent и добавляет Класс DropdownList наследует базовый функционал BaseComponent и добавляет
методы для взаимодействия с выпадающими списками на странице. методы для взаимодействия с выпадающими списками на странице.
""" """
import re
from playwright.sync_api import Page from playwright.sync_api import Page, Locator
from tools.logger import get_logger from tools.logger import get_logger
from components.base_component import BaseComponent from components.base_component import BaseComponent
@ -34,7 +34,59 @@ class DropdownList(BaseComponent):
text (str): Текст элемента для выбора. text (str): Текст элемента для выбора.
""" """
self.page.get_by_role("listitem").filter(has_text=text).click() element = self.page.get_by_role("listitem").filter(has_text=text)
if element.count() > 1:
rtext = f"^{text}$"
element = self.page.get_by_role("listitem").filter(has_text=re.compile(rtext))
element.click()
def get_item_names(self, locator: str | Locator) -> list[str]:
"""Возвращает тексты всех элементов по указанному локатору.
Args:
locator: Локатор элементов или строка с CSS/XPath.
Returns:
Список текстов элементов.
"""
loc = self.get_locator(locator)
texts = loc.all_inner_texts()
return texts[0].splitlines()
def scroll_until_end(self, locator: str | Locator) -> None:
"""
Скроллит список до тех пор, пока не перестанут подгружаться новые элементы.
Args:
locator: Локатор элементов или строка с CSS/XPath.
"""
loc = self.get_locator(locator)
items_count = 0
attempts = 0
max_attempts = 3
last_item_name = ""
while attempts < max_attempts:
self.page.wait_for_timeout(300)
item_names = self.get_item_names(loc)
current_count = len(item_names)
if current_count == items_count:
attempts += 1
else:
items_count = current_count
attempts = 0
last_item_name = item_names[current_count-1]
element = self.page.get_by_role("listitem").filter(has_text=last_item_name)
element.scroll_into_view_if_needed()
self.page.wait_for_timeout(300)
self.check_item_with_text(last_item_name)
# Проверки: # Проверки:
def check_item_with_text(self, text: str) -> None: def check_item_with_text(self, text: str) -> None:
@ -47,6 +99,36 @@ class DropdownList(BaseComponent):
AssertionError: Если элемент отсутствует или недоступен. AssertionError: Если элемент отсутствует или недоступен.
""" """
enabled = self.page.get_by_role("listitem").filter(has_text=text).is_enabled() element = self.page.get_by_role("listitem").filter(has_text=text)
if element.count() > 1:
rtext = f"^{text}$"
element = self.page.get_by_role("listitem").filter(has_text=re.compile(rtext))
enabled = element.is_enabled()
if not enabled: if not enabled:
assert False, f"Dropdown list item '{text}' is missing or disabled" assert False, f"Dropdown list item '{text}' is missing or disabled"
def check_vertical_scrolling(self, locator: str | Locator) -> bool:
"""
Проверяет функцию вертикального скроллинга списка.
Args:
locator: Локатор элементов или строка с CSS/XPath.
Returns:
True или False значение в зависимости от скроллируемый список или нет.
"""
loc = self.get_locator(locator)
is_scrollable_vertically = self.is_scrollable_vertically(loc)
if is_scrollable_vertically:
self.scroll_until_end(loc)
item_names = self.get_item_names(loc)
first_item_name = item_names[0]
self.scroll_up(loc)
self.page.wait_for_timeout(300)
self.check_item_with_text(first_item_name)
return is_scrollable_vertically

View File

@ -55,6 +55,12 @@ class BaseElement:
logger.info(f"Get text for {self.type_of} '{self.name}'") logger.info(f"Get text for {self.type_of} '{self.name}'")
return self.locator.nth(index).text_content() return self.locator.nth(index).text_content()
def update_locator(self, new_locator: Locator) -> None:
"""Меняет значение локатора для элемента"""
logger.info(f"Update locator for {self.type_of} '{self.name}'")
self.locator = new_locator
def wait_for_element(self, timeout: int = 12000) -> None: def wait_for_element(self, timeout: int = 12000) -> None:
"""Ожидает появление элемента в течение заданного времени.""" """Ожидает появление элемента в течение заданного времени."""

View File

@ -28,17 +28,23 @@ class Checkbox(BaseElement):
return "checkbox" return "checkbox"
# Действия: # Действия:
def check(self) -> None: def check(self, force=False) -> None:
"""Отмечает чекбокс (устанавливает галочку).""" """Отмечает чекбокс (устанавливает галочку)."""
logger.info(f"Checking checkbox '{self.name}'") logger.info(f"Checking checkbox '{self.name}'")
self.locator.check() if force:
self.locator.check(force=True)
else:
self.locator.check()
def uncheck(self) -> None: def uncheck(self, force=False) -> None:
"""Снимает отметку с чекбокса (убирает галочку).""" """Снимает отметку с чекбокса (убирает галочку)."""
logger.info(f"Unchecking checkbox '{self.name}'") logger.info(f"Unchecking checkbox '{self.name}'")
self.locator.uncheck() if force:
self.locator.uncheck(force=True)
else:
self.locator.uncheck()
# Проверки: # Проверки:
def is_checked(self) -> bool: def is_checked(self) -> bool:

View File

@ -11,10 +11,7 @@ class ModalWindowLocators:
MODAL_WINDOW (str): активного модального окна MODAL_WINDOW (str): активного модального окна
INPUT_FORM_USER_DATA (str): формы ввода пользовательских данных INPUT_FORM_USER_DATA (str): формы ввода пользовательских данных
TEXT_FIELD_INPUT_FORM_USER_DATA (str): текстового поля ввода TEXT_FIELD_INPUT_FORM_USER_DATA (str): текстового поля ввода
MENU_INPUT_FORM_USER_DATA (str): меню выбора ролей
ROLES_FIELD_INPUT_FORM_USER_DATA (str): поля выбора ролей
ROLES_MENU_INPUT_FORM_USER_DATA (str): меню выбора ролей
LABEL_INPUT_FORM_USER_DATA (str): метки поля ввода LABEL_INPUT_FORM_USER_DATA (str): метки поля ввода
""" """
@ -22,6 +19,5 @@ class ModalWindowLocators:
INPUT_FORM_USER_DATA = "//form[@class='v-form']" INPUT_FORM_USER_DATA = "//form[@class='v-form']"
TEXT_FIELD_INPUT_FORM_USER_DATA = "xpath=div[2]/div/div/div/div/input" TEXT_FIELD_INPUT_FORM_USER_DATA = "xpath=div[2]/div/div/div/div/input"
ROLES_FIELD_INPUT_FORM_USER_DATA = "xpath=div[2]/div/div/div/div/div[1]" MENU_INPUT_FORM_USER_DATA = "//div[contains(@class, 'menuable__content__active')]"
ROLES_MENU_INPUT_FORM_USER_DATA = "//div[contains(@class, 'menuable__content__active')]"
LABEL_INPUT_FORM_USER_DATA = "//label[contains(@class,'v-label')]/span" LABEL_INPUT_FORM_USER_DATA = "//label[contains(@class,'v-label')]/span"

View File

@ -0,0 +1,364 @@
"""Модуль modal_add_user содержит класс для работы с модальным окном добавления пользователя.
Класс AddUserModalWindow наследует базовый функционал ModalWindowComponent
и реализует специфичные методы для работы с формами добавления пользователей.
"""
import re
from playwright.sync_api import Page
from tools.logger import get_logger
from locators.modal_window_locators import ModalWindowLocators
from elements.text_input_element import TextInput
from elements.text_element import Text
from elements.checkbox_element import Checkbox
from data.roles_dict import roles_dict
from components.modal_window_component import ModalWindowComponent
from components.dropdown_list_component import DropdownList
from components.confirm_component import ConfirmComponent
logger = get_logger("ADD_USER_FROM_ACTIVE_DIRECTORY_MODAL_WINDOW")
class AddADUserModalWindow(ModalWindowComponent):
"""Модальное окно добавления нового пользователя.
Наследует ModalWindowComponent и добавляет элементы формы:
- Поля ввода (имя, пароль, email и др.)
- Чекбоксы (Active Directory, Push-уведомления)
- Выпадающие списки групп, пользователей AD, ролей
- Кнопки действий
"""
def __init__(self, page: Page):
"""Инициализирует элементы формы добавления пользователя."""
super().__init__(page)
# Локаторы элементов формы
input_form_locator = page.locator(ModalWindowLocators.INPUT_FORM_USER_DATA)
text_field_locator = ModalWindowLocators.TEXT_FIELD_INPUT_FORM_USER_DATA
label_locator = ModalWindowLocators.LABEL_INPUT_FORM_USER_DATA
# Настройка заголовка и кнопки закрытия тулбара
self.window_title = "Добавить нового пользователя"
locator_button_toolbar_close = self.page.get_by_role("navigation").filter(
has_text=re.compile(self.window_title)
).get_by_role("button")
self.add_toolbar_title(self.window_title)
self.add_toolbar_button(locator_button_toolbar_close, "close")
# Добавление элементов формы
checkbox_1 = Checkbox(
page,
self.page.get_by_role("checkbox").nth(0),
"active_directory"
)
self.add_content_item("active_directory_checkbox", checkbox_1)
label_1 = Text(
page,
self.page.locator(label_locator).nth(0),
"active_directory_checkbox_label"
)
self.add_content_item("active_directory_checkbox_label", label_1)
# Начальный набор полей формы
group_loc = input_form_locator.get_by_role("combobox").nth(0)
group_input = TextInput(page, group_loc, "group_input")
self.add_content_item("group_input", group_input)
self.add_content_item(
"group_list",
DropdownList(page)
)
locator_button_search = self.page.get_by_role("button", name="Поиск")
self.add_button(locator_button_search, "search")
loc = input_form_locator.locator("xpath=div[3]").locator(text_field_locator)
name_input = TextInput(page, loc, "name_input")
self.add_content_item("name_input", name_input)
role_loc = input_form_locator.get_by_role("combobox").nth(1)
role_input = TextInput(page, role_loc, "role_input")
self.add_content_item("role_input", role_input)
self.add_content_item(
"roles_list",
DropdownList(page)
)
loc = input_form_locator.locator("xpath=div[6]").locator(text_field_locator)
commentary_input = TextInput(page, loc, "commentary_input")
self.add_content_item("commentary_input", commentary_input)
loc = input_form_locator.locator("xpath=div[7]").locator(text_field_locator)
email_input = TextInput(page, loc, "email_input")
self.add_content_item("email_input", email_input)
loc = input_form_locator.locator("xpath=div[8]").locator(text_field_locator)
phone_input = TextInput(page, loc, "phone_input")
self.add_content_item("phone_input", phone_input)
checkbox_2 = Checkbox(
page,
page.get_by_role("checkbox").nth(1),
"push_notification"
)
self.add_content_item("push_notification_checkbox", checkbox_2)
label_2 = Text(
page,
self.page.locator(label_locator).nth(1),
"push_notification_checkbox_label"
)
self.add_content_item("push_notification_checkbox_label", label_2)
# Добавление кнопок действий
locator_button_add = self.page.get_by_role("button", name="Добавить")
self.add_button(locator_button_add, "add")
locator_button_close = self.page.get_by_role("button", name="Закрыть")
self.add_button(locator_button_close, "close")
self.new_user_confirm = ConfirmComponent(page, " Отмена ", " Добавить ")
# Действия:
def check_active_directory_checkbox(self):
"""Включает чек-бокс Active Directory. """
self.get_content_item("active_directory_checkbox").check(force=True)
def uncheck_active_directory_checkbox(self):
"""Выключает чек-бокс Active Directory. """
self.get_content_item("active_directory_checkbox").uncheck(force=True)
def update_input_form_fields(self, expand):
"""Персчитывает локаторы полей формы ввода при добавлении/удалении дополнительного поля. """
input_form_locator = self.page.locator(ModalWindowLocators.INPUT_FORM_USER_DATA)
text_field_locator = ModalWindowLocators.TEXT_FIELD_INPUT_FORM_USER_DATA
if expand:
new_loc = input_form_locator.locator("xpath=div[4]").locator(text_field_locator)
self.get_content_item("name_input").update_locator(new_loc)
new_loc = input_form_locator.locator("xpath=div[7]").locator(text_field_locator)
self.get_content_item("commentary_input").update_locator(new_loc)
new_loc = input_form_locator.locator("xpath=div[8]").locator(text_field_locator)
self.get_content_item("email_input").update_locator(new_loc)
new_loc = input_form_locator.locator("xpath=div[9]").locator(text_field_locator)
self.get_content_item("phone_input").update_locator(new_loc)
role_loc = input_form_locator.get_by_role("combobox").nth(2)
self.get_content_item("role_input").update_locator(role_loc)
else:
new_loc = input_form_locator.locator("xpath=div[3]").locator(text_field_locator)
self.get_content_item("name_input").update_locator(new_loc)
new_loc = input_form_locator.locator("xpath=div[6]").locator(text_field_locator)
self.get_content_item("commentary_input").update_locator(new_loc)
new_loc = input_form_locator.locator("xpath=div[7]").locator(text_field_locator)
self.get_content_item("email_input").update_locator(new_loc)
new_loc = input_form_locator.locator("xpath=div[8]").locator(text_field_locator)
self.get_content_item("phone_input").update_locator(new_loc)
role_loc = input_form_locator.get_by_role("combobox").nth(1)
self.get_content_item("role_input").update_locator(role_loc)
def new_user(self, user_data):
"""Заполняет форму и добавляет нового пользователя.
Args:
user_data (dict): Данные пользователя (имя, роль, пароль и др.)
"""
menu_locator = self.page.locator(ModalWindowLocators.MENU_INPUT_FORM_USER_DATA)
input_form_locator = self.page.locator(ModalWindowLocators.INPUT_FORM_USER_DATA)
group_name = user_data.get("group")
if group_name is None:
assert False, "Value of 'group' is missing"
name = user_data.get("name")
if name is None:
assert False, "Value of 'name' is missing"
role = user_data.get("role")
if role is None:
assert False, "Value of 'role' is missing"
group_field = self.get_content_item("group_input")
group_field.click()
group_list = self.get_content_item("group_list")
group_list.scroll_until_end(menu_locator)
group_names = group_list.get_item_names(menu_locator)
if group_name not in group_names:
assert False, f"Required group name {group_name} is missing"
group_list.check_item_with_text(group_name)
group_list.click_item_with_text(group_name)
search_button = self.get_button_by_name("search")
search_button.click()
count = input_form_locator.get_by_role("combobox").count()
if count == 2:
assert False, f"Selected group {group_name} is empty. Use another group."
user_AD_loc = input_form_locator.get_by_role("combobox").nth(1)
user_AD_input = TextInput(self.page, user_AD_loc, "user_AD_input")
self.add_content_item("user_AD_input", user_AD_input)
self.add_content_item(
"user_AD_list",
DropdownList(self.page)
)
user_AD_input.click()
user_AD_list = self.get_content_item("user_AD_list")
user_AD_list.scroll_until_end(menu_locator)
user_AD_names = group_list.get_item_names(menu_locator)
if name not in user_AD_names:
assert False, f"Required user name {name} is missing"
user_AD_list.check_item_with_text(name)
user_AD_list.click_item_with_text(name)
role_field = self.get_content_item("role_input")
role_field.click()
roles_list = self.get_content_item("roles_list")
roles_list.check_item_with_text(user_data["role"])
roles_list.click_item_with_text(user_data["role"])
# Отправка формы
add_button = self.get_button_by_name("add")
add_button.click()
# Подтверждение действия
title = "Добавить нового пользователя"
self.new_user_confirm.check_title(
title,
f"Confirmation dialog window with title '{title}' is missing"
)
# На первом этапе реального пользователя не создаем
self.new_user_confirm.click_cancel_button()
self.close_window()
def close_window(self):
"""Закрывает модальное окно через кнопку 'Закрыть'."""
close_button = self.get_button_by_name("close")
close_button.click()
def close_window_by_toolbar_button(self):
"""Закрывает модальное окно через кнопку в тулбаре."""
self.click_toolbar_close_button()
# Проверки:
def check_content(self):
"""Проверяет наличие и корректность всех элементов формы."""
input_form_locator = self.page.locator(ModalWindowLocators.INPUT_FORM_USER_DATA)
menu_locator = self.page.locator(ModalWindowLocators.MENU_INPUT_FORM_USER_DATA)
self.check_by_window_title()
is_checked = self.get_content_item("active_directory_checkbox").is_checked()
if not is_checked:
assert False, \
"The checkbox 'Active Directory'should be checked for the add user from Active Directory window"
self.check_toolbar_button_presence("close")
self.check_toolbar_button_tooltip("close", "Закрыть")
no_op_names = ["roles_list", "group_list"]
for name in self.content_items.keys():
item = self.get_content_item(name)
if name == "active_directory_checkbox_label":
item.check_have_text(
"Active Directory",
"Label 'Active Directory' is missing"
)
elif name == "push_notification_checkbox_label":
item.check_have_text(
"Подписка на Push-уведомления",
"Label 'Подписка на Push-уведомления' is missing"
)
elif name == "group_input":
item.click()
group_list = self.get_content_item("group_list")
group_list.check_presence(menu_locator,
"Groups list is missing")
is_scrollable_vertically = group_list.check_vertical_scrolling(menu_locator)
assert is_scrollable_vertically, "Groups list should be scrollable_vertically"
self.page.keyboard.press("Escape")
elif name == "role_input":
item.click()
roles_list = self.get_content_item("roles_list")
roles_list.check_presence(menu_locator,
"Roles list is missing")
is_scrollable_vertically = roles_list.check_vertical_scrolling(menu_locator)
assert not is_scrollable_vertically, \
"Roles list should not be scrollable_vertically"
for role in roles_dict.values():
# временно, пока есть несоответствие со списком ролей в вкладке Сессии
if role == "Пользователь":
continue
roles_list.check_item_with_text(role)
self.page.keyboard.press("Escape")
elif name in no_op_names:
continue
else:
item.check_presence(
f"Modal window content item with name '{name}' is missing"
)
self.check_button_presence("search")
self.check_button_presence("add")
self.check_button_presence("close")
search_button = self.get_button_by_name("search")
search_button.click()
user_AD_loc = input_form_locator.get_by_role("combobox").nth(1)
user_AD_input = TextInput(self.page, user_AD_loc, "user_AD_input")
self.add_content_item("user_AD_input", user_AD_input)
self.add_content_item(
"user_AD_list",
DropdownList(self.page)
)
user_AD_input.click()
user_AD_list = self.get_content_item("user_AD_list")
user_AD_list.check_presence(menu_locator,
"Users AD list is missing")
is_scrollable_vertically = user_AD_list.check_vertical_scrolling(menu_locator)
assert is_scrollable_vertically, "Users AD list should be scrollable_vertically"
self.page.keyboard.press("Escape")
self.update_input_form_fields(expand=True)
self.get_content_item("name_input").check_presence(
"Modal window content item with name 'name_input' is missing")
self.get_content_item("role_input").check_presence(
"Modal window content item with name 'role_input' is missing")
self.get_content_item("commentary_input").check_presence(
"Modal window content item with name 'commentary_input' is missing")
self.get_content_item("email_input").check_presence(
"Modal window content item with name 'email_input' is missing")
self.get_content_item("phone_input").check_presence(
"Modal window content item with name 'phone_input' is missing")

View File

@ -1,6 +1,6 @@
"""Модуль modal_add_user содержит класс для работы с модальным окном добавления пользователя. """Модуль modal_add_local_user содержит класс для работы с модальным окном добавления локального пользователя.
Класс AddUserModalWindow наследует базовый функционал ModalWindowComponent Класс AddLocalUserModalWindow наследует базовый функционал ModalWindowComponent
и реализует специфичные методы для работы с формами добавления пользователей. и реализует специфичные методы для работы с формами добавления пользователей.
""" """
@ -17,10 +17,10 @@ from components.dropdown_list_component import DropdownList
from components.confirm_component import ConfirmComponent from components.confirm_component import ConfirmComponent
logger = get_logger("ADD_USER_MODAL_WINDOW") logger = get_logger("ADD_LOCAL_USER_MODAL_WINDOW")
class AddUserModalWindow(ModalWindowComponent): class AddLocalUserModalWindow(ModalWindowComponent):
"""Модальное окно добавления нового пользователя. """Модальное окно добавления нового пользователя.
Наследует ModalWindowComponent и добавляет элементы формы: Наследует ModalWindowComponent и добавляет элементы формы:
@ -37,7 +37,6 @@ class AddUserModalWindow(ModalWindowComponent):
# Локаторы элементов формы # Локаторы элементов формы
text_field_locator = ModalWindowLocators.TEXT_FIELD_INPUT_FORM_USER_DATA text_field_locator = ModalWindowLocators.TEXT_FIELD_INPUT_FORM_USER_DATA
roles_field_locator = ModalWindowLocators.ROLES_FIELD_INPUT_FORM_USER_DATA
input_form_locator = ModalWindowLocators.INPUT_FORM_USER_DATA input_form_locator = ModalWindowLocators.INPUT_FORM_USER_DATA
label_locator = ModalWindowLocators.LABEL_INPUT_FORM_USER_DATA label_locator = ModalWindowLocators.LABEL_INPUT_FORM_USER_DATA
@ -53,9 +52,10 @@ class AddUserModalWindow(ModalWindowComponent):
# Добавление элементов формы # Добавление элементов формы
checkbox_1 = Checkbox( checkbox_1 = Checkbox(
page, page,
self.page.get_by_role("checkbox").nth(0), self.page.locator(input_form_locator).get_by_role("checkbox").nth(0),
"active_directory" "active_directory"
) )
self.add_content_item("active_directory_checkbox", checkbox_1) self.add_content_item("active_directory_checkbox", checkbox_1)
label_1 = Text( label_1 = Text(
@ -69,7 +69,7 @@ class AddUserModalWindow(ModalWindowComponent):
name_input = TextInput(page, loc, "name_input") name_input = TextInput(page, loc, "name_input")
self.add_content_item("name_input", name_input) self.add_content_item("name_input", name_input)
role_loc = self.page.locator(input_form_locator).locator("xpath=div[3]").locator(roles_field_locator) role_loc = self.page.locator(input_form_locator).get_by_role("combobox").nth(0)
role_input = TextInput(page, role_loc, "role_input") role_input = TextInput(page, role_loc, "role_input")
self.add_content_item("role_input", role_input) self.add_content_item("role_input", role_input)
self.add_content_item( self.add_content_item(
@ -95,7 +95,7 @@ class AddUserModalWindow(ModalWindowComponent):
checkbox_2 = Checkbox( checkbox_2 = Checkbox(
page, page,
page.get_by_role("checkbox").nth(1), self.page.locator(input_form_locator).get_by_role("checkbox").nth(1),
"push_notification" "push_notification"
) )
self.add_content_item("push_notification_checkbox", checkbox_2) self.add_content_item("push_notification_checkbox", checkbox_2)
@ -116,6 +116,17 @@ class AddUserModalWindow(ModalWindowComponent):
self.new_user_confirm = ConfirmComponent(page, " Отмена ", " Добавить ") self.new_user_confirm = ConfirmComponent(page, " Отмена ", " Добавить ")
# Действия:
def check_active_directory_checkbox(self):
"""Включает чек-бокс Active Directory. """
self.get_content_item("active_directory_checkbox").check(force=True)
def uncheck_active_directory_checkbox(self):
"""Выключает чек-бокс Active Directory. """
self.get_content_item("active_directory_checkbox").uncheck(force=True)
def new_user(self, user_data): def new_user(self, user_data):
"""Заполняет форму и добавляет нового пользователя. """Заполняет форму и добавляет нового пользователя.
@ -125,13 +136,6 @@ class AddUserModalWindow(ModalWindowComponent):
fields = user_data.keys() fields = user_data.keys()
if "active_directory_checked" in fields:
checkbox = self.get_content_item("active_directory_checkbox")
if user_data["active_directory_checked"]:
checkbox.check()
else:
checkbox.uncheck()
if "name" in fields: if "name" in fields:
input_field = self.get_content_item("name_input") input_field = self.get_content_item("name_input")
input_field.input_value(user_data["name"]) input_field.input_value(user_data["name"])
@ -190,11 +194,19 @@ class AddUserModalWindow(ModalWindowComponent):
self.click_toolbar_close_button() self.click_toolbar_close_button()
# Проверки:
def check_content(self): def check_content(self):
"""Проверяет наличие и корректность всех элементов формы.""" """Проверяет наличие и корректность всех элементов формы."""
menu_locator = self.page.locator(ModalWindowLocators.MENU_INPUT_FORM_USER_DATA)
self.check_by_window_title() self.check_by_window_title()
is_checked = self.get_content_item("active_directory_checkbox").is_checked()
if is_checked:
assert False, \
"The checkbox 'Active Directory'should not be checked for the add local user window"
self.check_toolbar_button_presence("close") self.check_toolbar_button_presence("close")
self.check_toolbar_button_tooltip("close", "Закрыть") self.check_toolbar_button_tooltip("close", "Закрыть")
@ -214,9 +226,13 @@ class AddUserModalWindow(ModalWindowComponent):
elif name == "role_input": elif name == "role_input":
item.click() item.click()
roles_list = self.get_content_item("roles_list") roles_list = self.get_content_item("roles_list")
roles_list.check_presence(self.page.locator(ModalWindowLocators.ROLES_MENU_INPUT_FORM_USER_DATA), roles_list.check_presence(menu_locator,
"Roles list is missing") "Roles list is missing")
is_scrollable_vertically = roles_list.check_vertical_scrolling(menu_locator)
assert not is_scrollable_vertically, \
"Roles list should not be scrollable_vertically"
for role in roles_dict.values(): for role in roles_dict.values():
# временно, пока есть несоответствие со списком ролей в вкладке Сессии # временно, пока есть несоответствие со списком ролей в вкладке Сессии
if role == "Пользователь": if role == "Пользователь":

View File

@ -35,7 +35,6 @@ class EditUserModalWindow(ModalWindowComponent):
# Локаторы элементов формы # Локаторы элементов формы
text_field_locator = ModalWindowLocators.TEXT_FIELD_INPUT_FORM_USER_DATA text_field_locator = ModalWindowLocators.TEXT_FIELD_INPUT_FORM_USER_DATA
roles_field_locator = ModalWindowLocators.ROLES_FIELD_INPUT_FORM_USER_DATA
input_form_locator = ModalWindowLocators.INPUT_FORM_USER_DATA input_form_locator = ModalWindowLocators.INPUT_FORM_USER_DATA
label_locator = ModalWindowLocators.LABEL_INPUT_FORM_USER_DATA label_locator = ModalWindowLocators.LABEL_INPUT_FORM_USER_DATA
@ -53,7 +52,7 @@ class EditUserModalWindow(ModalWindowComponent):
name_input = TextInput(page, loc, "name_input") name_input = TextInput(page, loc, "name_input")
self.add_content_item("name_input", name_input) self.add_content_item("name_input", name_input)
role_loc = self.page.locator(input_form_locator).locator("xpath=div[2]").locator(roles_field_locator) role_loc = self.page.locator(input_form_locator).get_by_role("combobox").nth(0)
role_input = TextInput(page, role_loc, "role_input") role_input = TextInput(page, role_loc, "role_input")
self.add_content_item("role_input", role_input) self.add_content_item("role_input", role_input)
self.add_content_item( self.add_content_item(
@ -193,6 +192,8 @@ class EditUserModalWindow(ModalWindowComponent):
role (str): Ожидаемая роль пользователя role (str): Ожидаемая роль пользователя
""" """
menu_locator = self.page.locator(ModalWindowLocators.MENU_INPUT_FORM_USER_DATA)
self.check_by_window_title() self.check_by_window_title()
self.check_toolbar_button_presence("close") self.check_toolbar_button_presence("close")
self.check_toolbar_button_tooltip("close", "Закрыть") self.check_toolbar_button_tooltip("close", "Закрыть")
@ -214,7 +215,7 @@ class EditUserModalWindow(ModalWindowComponent):
elif name == "role_input": elif name == "role_input":
item.click() item.click()
roles_list = self.get_content_item("roles_list") roles_list = self.get_content_item("roles_list")
roles_list.check_presence(self.page.locator(ModalWindowLocators.ROLES_MENU_INPUT_FORM_USER_DATA), roles_list.check_presence(menu_locator,
"Roles list is missing") "Roles list is missing")
roles_list.check_item_with_text(role) roles_list.check_item_with_text(role)
elif name == "roles_list": elif name == "roles_list":

View File

@ -7,7 +7,8 @@
import re import re
from playwright.sync_api import Page from playwright.sync_api import Page
from modal_windows.modal_edit_user import EditUserModalWindow from modal_windows.modal_edit_user import EditUserModalWindow
from modal_windows.modal_add_user import AddUserModalWindow from modal_windows.modal_add_local_user import AddLocalUserModalWindow
from modal_windows.modal_add_AD_user import AddADUserModalWindow
from locators.table_locators import TableLocators from locators.table_locators import TableLocators
from data.roles_dict import roles_dict from data.roles_dict import roles_dict
from components.toolbar_component import ToolbarComponent from components.toolbar_component import ToolbarComponent
@ -58,14 +59,16 @@ class UsersTab(BasePage):
AssertionError: Если тип окна не поддерживается. AssertionError: Если тип окна не поддерживается.
""" """
if window_type == "add_user": if window_type == "add_local_user":
self.modal_windows["add_user"] = AddUserModalWindow(self.page) self.modal_windows["add_local_user"] = AddLocalUserModalWindow(self.page)
elif window_type == "add_AD_user":
self.modal_windows["add_AD_user"] = AddADUserModalWindow(self.page)
elif window_type == "edit_user": elif window_type == "edit_user":
self.modal_windows[title] = EditUserModalWindow(self.page, title) self.modal_windows[title] = EditUserModalWindow(self.page, title)
else: else:
assert False, "Unsupported modal window type" assert False, "Unsupported modal window type"
def get_modal_window(self, title: str) -> None: def get_modal_window(self, title: str):
"""Возвращает модальное окно по заголовку. """Возвращает модальное окно по заголовку.
Args: Args:
@ -119,15 +122,25 @@ class UsersTab(BasePage):
modal_window.close_window() modal_window.close_window()
self.delete_modal_window(title) self.delete_modal_window(title)
def close_add_AD_user_window_by_toolbar_button(self) -> None:
"""Закрывает окно добавления пользователя через тулбар."""
self.close_modal_window_by_toolbar_button("add_AD_user")
def close_add_AD_user_window(self) -> None:
"""Закрывает окно добавления пользователя."""
self.close_modal_window("add_AD_user")
def close_add_user_window_by_toolbar_button(self) -> None: def close_add_user_window_by_toolbar_button(self) -> None:
"""Закрывает окно добавления пользователя через тулбар.""" """Закрывает окно добавления пользователя через тулбар."""
self.close_modal_window_by_toolbar_button("add_user") self.close_modal_window_by_toolbar_button("add_local_user")
def close_add_user_window(self) -> None: def close_add_user_window(self) -> None:
"""Закрывает окно добавления пользователя.""" """Закрывает окно добавления пользователя."""
self.close_modal_window("add_user") self.close_modal_window("add_local_user")
def close_edit_user_window_by_toolbar_button(self, title: str) -> None: def close_edit_user_window_by_toolbar_button(self, title: str) -> None:
"""Закрывает окно редактирования через кнопку в тулбаре. """Закрывает окно редактирования через кнопку в тулбаре.
@ -147,6 +160,7 @@ class UsersTab(BasePage):
self.close_modal_window(title) self.close_modal_window(title)
def add_new_user(self, user_data: dict) -> bool: def add_new_user(self, user_data: dict) -> bool:
"""Добавляет нового пользователя или обрабатывает ошибку при дубликате. """Добавляет нового пользователя или обрабатывает ошибку при дубликате.
@ -161,7 +175,17 @@ class UsersTab(BasePage):
или если текст alert не соответствует ожидаемому. или если текст alert не соответствует ожидаемому.
""" """
self.get_modal_window("add_user").new_user(user_data) add_user_window = self.get_modal_window("add_local_user")
auth_type = user_data.get("auth_type")
if auth_type == "active_directory":
add_user_window.check_active_directory_checkbox()
self.add_modal_window("add_AD_user", "")
add_user_window = self.get_modal_window("add_AD_user")
add_user_window.new_user(user_data)
return True
add_user_window.new_user(user_data)
is_added = False is_added = False
alert_type = self.alert.get_alert_type() alert_type = self.alert.get_alert_type()
@ -274,8 +298,8 @@ class UsersTab(BasePage):
self.toolbar.check_button_presence("add_user") self.toolbar.check_button_presence("add_user")
self.toolbar.click_button("add_user") self.toolbar.click_button("add_user")
self.add_modal_window("add_user", "") self.add_modal_window("add_local_user", "")
self.get_modal_window("add_user").check_by_window_title() self.get_modal_window("add_local_user").check_by_window_title()
def open_edit_user_page_by_index(self, row_index: int) -> tuple: def open_edit_user_page_by_index(self, row_index: int) -> tuple:
"""Открывает окно редактирования по индексу строки. """Открывает окно редактирования по индексу строки.
@ -335,6 +359,28 @@ class UsersTab(BasePage):
self.add_modal_window("edit_user", user_name) self.add_modal_window("edit_user", user_name)
self.get_modal_window(user_name).check_by_window_title() self.get_modal_window(user_name).check_by_window_title()
def transform_to_add_AD_user_window(self):
"""Трансформирует модальное окно добавления локального пользователя
в окно добавления пользователя Active Directory с помощью нажатия
чек-бокса Active Directory.
"""
self.get_modal_window("add_local_user").check_active_directory_checkbox()
modal_window = self.modal_windows.get("add_AD_user")
if modal_window is None:
self.add_modal_window("add_AD_user", "")
def transform_to_add_user_window(self):
"""Трансформирует модальное окно добавления пользователя Active Directory
в окно добавления локального пользователя с помощью снятия отметки с
чек-бокса Active Directory.
"""
self.get_modal_window("add_AD_user").uncheck_active_directory_checkbox()
modal_window = self.modal_windows.get("add_local_user")
if modal_window is None:
self.add_modal_window("add_local_user", "")
# Проверки: # Проверки:
def check_users_table_content(self, verify: bool = False) -> None: def check_users_table_content(self, verify: bool = False) -> None:
"""Проверяет содержимое таблицы пользователей. """Проверяет содержимое таблицы пользователей.
@ -367,9 +413,14 @@ class UsersTab(BasePage):
self.verify_users_table_content(table_content) self.verify_users_table_content(table_content)
def check_add_user_window_content(self) -> None: def check_add_user_window_content(self) -> None:
"""Проверяет содержимое окна добавления пользователя.""" """Проверяет содержимое окна добавления локального пользователя."""
self.get_modal_window("add_user").check_content() self.get_modal_window("add_local_user").check_content()
def check_add_AD_user_window_content(self) -> None:
"""Проверяет содержимое окна добавления пользователя через Active Directory."""
self.get_modal_window("add_AD_user").check_content()
def check_edit_user_window_content(self, user_name: str, role: str) -> None: def check_edit_user_window_content(self, user_name: str, role: str) -> None:
"""Проверяет содержимое окна редактирования. """Проверяет содержимое окна редактирования.

View File

@ -78,7 +78,7 @@ class TestUsersModalWindow:
ut = UsersTab(browser) ut = UsersTab(browser)
ut.open_add_user_window() ut.open_add_user_window()
modal_window = ut.get_modal_window("add_user") modal_window = ut.get_modal_window("add_local_user")
is_scrollable_vertically = modal_window.check_window_vertical_scrolling() is_scrollable_vertically = modal_window.check_window_vertical_scrolling()
assert is_scrollable_vertically, "Should be vertical scrolling" assert is_scrollable_vertically, "Should be vertical scrolling"

View File

@ -85,6 +85,7 @@ class TestUsersTab:
ut = UsersTab(browser) ut = UsersTab(browser)
ut.should_be_toolbar_buttons() ut.should_be_toolbar_buttons()
# pytest.mark.develop
def test_add_user_window_content(self, browser: Page) -> None: def test_add_user_window_content(self, browser: Page) -> None:
"""Проверяет содержимое окна добавления пользователя. """Проверяет содержимое окна добавления пользователя.
@ -95,6 +96,8 @@ class TestUsersTab:
ut = UsersTab(browser) ut = UsersTab(browser)
ut.open_add_user_window() ut.open_add_user_window()
ut.check_add_user_window_content() ut.check_add_user_window_content()
ut.transform_to_add_AD_user_window()
ut.check_add_AD_user_window_content()
def test_add_user_window_close_buttons(self, browser: Page) -> None: def test_add_user_window_close_buttons(self, browser: Page) -> None:
"""Проверяет кнопки закрытия окна добавления. """Проверяет кнопки закрытия окна добавления.
@ -110,6 +113,14 @@ class TestUsersTab:
ut.open_add_user_window() ut.open_add_user_window()
ut.close_add_user_window() ut.close_add_user_window()
ut.open_add_user_window()
ut.transform_to_add_AD_user_window()
ut.close_add_AD_user_window_by_toolbar_button()
ut.open_add_user_window()
ut.transform_to_add_AD_user_window()
ut.close_add_AD_user_window()
def test_edit_user_window_content(self, browser: Page) -> None: def test_edit_user_window_content(self, browser: Page) -> None:
"""Проверяет содержимое окна редактирования. """Проверяет содержимое окна редактирования.
@ -134,6 +145,7 @@ class TestUsersTab:
user_name, _ = ut.open_edit_user_page_by_index(0) user_name, _ = ut.open_edit_user_page_by_index(0)
ut.close_edit_user_window(user_name) ut.close_edit_user_window(user_name)
# @pytest.mark.develop
def test_add_and_delete_user(self, browser: Page, cleanup_user: None) -> None: def test_add_and_delete_user(self, browser: Page, cleanup_user: None) -> None:
"""Проверяет добавление и удаление пользователя. """Проверяет добавление и удаление пользователя.
@ -181,6 +193,25 @@ class TestUsersTab:
mp.click_subpanel_item("Пользователи") mp.click_subpanel_item("Пользователи")
ut.should_not_be_user_in_table(user_data["name"], user_data["role"]) ut.should_not_be_user_in_table(user_data["name"], user_data["role"])
# @pytest.mark.develop
def test_add_AD_user(self, browser: Page, cleanup_user: None) -> None:
"""Проверяет добавление пользователя Active Directory.
Args:
browser: Экземпляр страницы Playwright.
cleanup_user: Фикстура для очистки пользователя.
"""
user_data: Dict[str, str] = {"auth_type":"active_directory",
"group": "Администраторы",
"name": "Администратор",
"role": "Администратор"}
ut = UsersTab(browser)
ut.open_add_user_window()
ut.add_new_user(user_data)
def test_reset_password(self, browser: Page, cleanup_autoadmin: None) -> None: def test_reset_password(self, browser: Page, cleanup_autoadmin: None) -> None:
"""Проверяет сброс пароля пользователя. """Проверяет сброс пароля пользователя.