Initial commit
commit
51123880b9
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -0,0 +1,12 @@
|
|||
class BasePageLocators():
|
||||
TABLE_HEADERS_CELLS = "//thead[contains(@class,'scrolltable__header')]/tr[contains(@class,'scrolltable__row')]/th"
|
||||
TABLE_BODY = "//tbody[contains(@class,'scrolltable__body')]/tr[contains(@class,'scrolltable__row')]"
|
||||
|
||||
ALERT_WINDOW = "//div[@role='alert']"
|
||||
ALERT_WINDOW_TEXT_ERROR = "//div[@class='v-alert error']/div"
|
||||
ALERT_WINDOW_TEXT_SUCCESS = "//div[@class='v-alert success']/div"
|
||||
ALERT_WINDOW_TEXT_INFO = "//div[@class='v-alert info']/div"
|
||||
ALERT_WINDOW_TEXT_WARNING = "//div[@class='v-alert warning']/div"
|
||||
|
||||
TOOLTIP = "//div[contains(@class,'v-tooltip__content menuable__content__active')]"
|
||||
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
class ConfigurationPageLocators():
|
||||
CONFIG_NAVIGATION_PANEL = "//ul/li[3]/div[@class='v-expansion-panel__body']"
|
||||
|
||||
CONFIG_NAVIGATION_PANEL_USER_BUTTON = "//ul/li[3]/div[@class='v-expansion-panel__body']//div[contains(@class,'v-treeview-node--click')]"
|
||||
CONFIG_NAVIGATION_PANEL_NOTIFICATION_BUTTON = "//ul/li[3]/div[@class='v-expansion-panel__body']//div[contains(@class,'v-treeview-node--click')][2]"
|
||||
CONFIG_NAVIGATION_PANEL_MAINTENANCE_BUTTON = "//ul/li[3]/div[@class='v-expansion-panel__body']//div[contains(@class,'v-treeview-node--click')][3]"
|
||||
CONFIG_NAVIGATION_PANEL_ZTP_BUTTON = "//ul/li[3]/div[@class='v-expansion-panel__body']//div[contains(@class,'v-treeview-node--click')][4]"
|
||||
|
||||
MAINTENANCE_NAVIGATION_PANEL = \
|
||||
"//ul/li[3]/div[@class='v-expansion-panel__body']//div[contains(@class,'v-treeview-node--click')][3]/div[@class='v-treeview-node__children']"
|
||||
MAINTENANCE_NAVIGATION_PANEL_SESSION_BUTTON = \
|
||||
"//ul/li[3]/div[@class='v-expansion-panel__body']//div[contains(@class,'v-treeview-node--click')][3]/div[@class='v-treeview-node__children']//div[contains(@class,'v-treeview-node--click')]"
|
||||
MAINTENANCE_NAVIGATION_PANEL_SERVICE_STATUS_BUTTON = \
|
||||
"//ul/li[3]/div[@class='v-expansion-panel__body']//div[contains(@class,'v-treeview-node--click')][3]/div[@class='v-treeview-node__children']//div[contains(@class,'v-treeview-node--click')][2]"
|
||||
MAINTENANCE_NAVIGATION_PANEL_LICENSING_BUTTON = \
|
||||
"//ul/li[3]/div[@class='v-expansion-panel__body']//div[contains(@class,'v-treeview-node--click')][3]/div[@class='v-treeview-node__children']//div[contains(@class,'v-treeview-node--click')][3]"
|
||||
|
||||
WORK_AREA_TITLE = "//div[@class ='v-toolbar__title']/span"
|
||||
WORK_AREA_TABLE = "//div[@class='scrollarea__body']/div/div/div/table"
|
||||
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
class LicenseTabLocators:
|
||||
JSON_ELEMENT = "//div[@class='jv-node']"
|
||||
LICENSE_TITLE = "//span[@class='title']"
|
||||
LICENSE_TITLE_DEVICE_ID = "//span[@class='title text_select']"
|
||||
LICENSE_INPUT_FORM_TEXTAREA = "//div[contains(@class,'v-input')]/div[@class='v-input__control']//div[@class='v-text-field__slot']/textarea"
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
class LoginPageLocators:
|
||||
USERNAME_INPUT = "//input[@type='text']"
|
||||
PASSWORD_INPUT = "//input[@type='password']"
|
||||
LOGIN_BTN = "//button[@type='button']"
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
class MainPageLocators:
|
||||
NAVIGATION_PANEL = "//ul"
|
||||
NAVIGATION_PANEL_DASHBOARD_BUTTON = "//ul/li[1]/div"
|
||||
NAVIGATION_PANEL_TOPOLOGY_BUTTON = "//ul/li[2]/div"
|
||||
NAVIGATION_PANEL_CONFIGURATION_BUTTON = "//ul/li[3]/div"
|
||||
|
||||
NAVIGATION_PANEL_DASHBOARD_BUTTON_HEADER = "//ul/li[1]"
|
||||
NAVIGATION_PANEL_TOPOLOGY_BUTTON_HEADER = "//ul/li[2]"
|
||||
NAVIGATION_PANEL_CONFIGURATION_BUTTON_HEADER = "//ul/li[3]"
|
||||
|
||||
|
||||
CURRENT_USER_BUTTON = "#app > div.application--wrap > div > div.layout.white > nav > div > div:nth-child(3) > div > div > div > button:nth-child(3)"
|
||||
CURRENT_USER_WINDOW = "//div[@class='v-card__text']"
|
||||
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
class SessionLocators():
|
||||
|
||||
# Область работы
|
||||
#TABLE_BODY = "//div[contains(@class, 'scrollarea__body')]//table[@class='scrolltable__container']"
|
||||
TABLE_BODY = "//div[@class='scrollarea__body']/div/div/div/table"
|
||||
TEXT_TITLE = "//div[@class ='v-toolbar__title']/span"
|
||||
|
||||
TABLE_SCROLL_CONTAINER = "//div[contains(@class, 'scrollarea__body') and .//table[@class='scrolltable__container']]" # Контейнер со скроллом
|
||||
TABLE_ROWS = f"{TABLE_SCROLL_CONTAINER}//table/tbody/tr"
|
||||
#TABLE_SCROLL_CONTAINER = "div.layout.white.column.fill-height"
|
||||
|
||||
# Ячейки таблицы
|
||||
TABLE_HEADER_CELL_SESSION_ID = "//div[@class='scrollarea__body']//td[1]/div/div"
|
||||
TABLE_HEADER_CELL_USER_ID = "//div[@class='scrollarea__body']//td[2]/div/div"
|
||||
TABLE_HEADER_CELL_LIFETIME = "//div[@class='scrollarea__body']//td[3]//div/div"
|
||||
TABLE_HEADER_CELL_ROLE = "//div[@class='scrollarea__body']//td[4]//div/div"
|
||||
TABLE_HEADER_CELL_ADDRESS = "//div[@class='scrollarea__body']//td[5]//div/div"
|
||||
|
||||
# Кнопки
|
||||
BUTTON_DELETE_SESSION = "button.v-btn--icon svg[fill='#4caf50']" # "//div[@class='scrollarea__body']//td[5]//button"
|
||||
|
||||
# Модальное окно
|
||||
MODAL_WINDOW = "div.v-dialog--active" # Основное модальное окно
|
||||
MODAL_TITLE = "//*[@id='app']/div[2]/div/div[2]/div[1]" # Заголовк модального окна
|
||||
#MODAL_SCROLL_CONTAINER_HORIZONTAL = "div.v-dialog--active div.v-card__text" # Горизонтальный скролл
|
||||
|
||||
|
||||
MODAL_CLOSE_BUTTON = "//*[@id='app']/div[2]/div/div[1]" # Кнопка закрытия "Х"
|
||||
MODAL_CANCEL_BUTTON = "div.v-dialog--active button:not(.red--text)" # Кнопка "Отмена"
|
||||
MODAL_DELETE_BUTTON = "div.v-dialog--active button.red--text" # Кнопка "Удалить"
|
||||
#SUCCESS_MESSAGE = "селектор сообщения об успешном удалении" # опционально
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
class UsersTabLocators:
|
||||
TOOLBAR_EDIT_BUTTON = "xpath=(.//*[normalize-space(text()) and normalize-space(.)='Пользователи'])[2]/following::*[name()='svg'][1]"
|
||||
TOOLBAR_ADD_USER_BUTTON = "xpath=(.//*[normalize-space(text()) and normalize-space(.)='Пользователи'])[2]/following::*[name()='svg'][1]"
|
||||
TOOLBAR_CLOSE_BUTTON = "xpath=(.//*[normalize-space(text()) and normalize-space(.)='Пользователи'])[2]/following::*[name()='svg'][2]"
|
||||
|
||||
USER_DATA_WORK_AREA_TITLE = "//div[@class ='v-toolbar__title']/span[contains(@class,'body-2')]"
|
||||
ADD_USER_WORK_AREA_CLOSE_BUTTON = "xpath=(.//*[normalize-space(text()) and normalize-space(.)='Добавить нового пользователя'])[1]/following::*[name()='svg'][1]"
|
||||
|
||||
|
||||
USER_DATA_INPUT_FORM = "//form[@class='v-form']"
|
||||
USER_DATA_INPUT_FORM_ROLES_MENU = "//div[contains(@class, 'menuable__content__active')]"
|
||||
USER_DATA_INPUT_FORM_NOTIFICATION_LABEL = "//label[contains(@class,'v-label')]/span"
|
||||
|
||||
USER_ACTION_CONFIRMATION_DIALOG = "//div[contains(@class, 'v-dialog--active')]//h3"
|
||||
Binary file not shown.
|
|
@ -0,0 +1,7 @@
|
|||
from dotenv import load_dotenv
|
||||
|
||||
load_dotenv()
|
||||
|
||||
pytest_plugins = [
|
||||
'fixtures.pages'
|
||||
]
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -0,0 +1,107 @@
|
|||
from playwright.sync_api import Page
|
||||
from data.environment import host
|
||||
from playwright.sync_api import expect
|
||||
from pages.base_page import BasePage
|
||||
from Locators.base_page import BasePageLocators
|
||||
|
||||
import jsondiff
|
||||
|
||||
class Assertions(BasePage):
|
||||
def __init__(self, page: Page) -> None:
|
||||
super().__init__(page)
|
||||
|
||||
def check_URL(self, uri, msg):
|
||||
expect(self.page).to_have_url(f"{host.get_base_url()}{uri}", timeout=60000), msg
|
||||
|
||||
def have_text(self, locator, text: str, msg): #элемент имеет текст
|
||||
loc = self.page.locator(locator)
|
||||
expect(loc).to_have_text(text), msg
|
||||
|
||||
def have_title(self, locator, title: str, msg):
|
||||
loc = self.page.locator(locator)
|
||||
expect(loc).to_have_text(title), msg
|
||||
|
||||
def check_presence(self, locator, msg):
|
||||
loc = self.page.locator(locator)
|
||||
expect(loc).to_be_visible(visible=True, timeout=12000), msg
|
||||
|
||||
def check_button_presence_with_text(self, text, msg):
|
||||
loc = self.page.get_by_role("button", name=text)
|
||||
expect(loc).to_be_visible(visible=True, timeout=12000), msg
|
||||
|
||||
def check_absence(self, locator, msg):
|
||||
loc = self.page.locator(locator)
|
||||
expect(loc).to_be_hidden(timeout=700), msg
|
||||
|
||||
def check_absence_after_period(self, locator, period, msg):
|
||||
loc = self.page.locator(locator)
|
||||
expect(loc).to_be_hidden(timeout=period), msg
|
||||
|
||||
def check_empty_input_area(self, input_area, msg):
|
||||
expect(input_area).to_be_empty(), msg
|
||||
|
||||
def check_menu_item_with_text(self, text, msg):
|
||||
count = self.page.get_by_role("listitem", name=text).count()
|
||||
assert count != 1, msg
|
||||
|
||||
def check_equals(self, actual, expected, msg):
|
||||
assert actual == expected, msg
|
||||
|
||||
def check_not_equals(self, actual, expected, msg):
|
||||
assert actual != expected, msg
|
||||
|
||||
def check_json_equals(self, actual, expected, msg):
|
||||
diff = jsondiff.diff(expected, actual, syntax='symmetric')
|
||||
assert len(diff) == 0, f"{msg}. DIFF is {diff}"
|
||||
|
||||
def check_lists_equals(self, actual, expected, msg):
|
||||
def compare_lists(list1, list2):
|
||||
if len(list1) != len(list2):
|
||||
return False
|
||||
for item1, item2 in zip(list1, list2):
|
||||
if isinstance(item1, list) and isinstance(item2, list):
|
||||
if not compare_lists(item1, item2):
|
||||
return False
|
||||
elif item1 != item2:
|
||||
return False
|
||||
return True
|
||||
|
||||
assert compare_lists(actual, expected), msg
|
||||
|
||||
def check_url_content(self, uri,msg):
|
||||
assert f"{uri}" in self.page.url, msg
|
||||
|
||||
def check_element_active(self, locator, msg):
|
||||
element_handle = self.page.wait_for_selector(locator)
|
||||
class_names = element_handle.get_attribute('class')
|
||||
assert 'active' in class_names, msg
|
||||
|
||||
def check_alert_window_with_text(self, alert_type, text):
|
||||
self.check_presence(BasePageLocators.ALERT_WINDOW, "No alert window for action notification")
|
||||
|
||||
if alert_type == "error":
|
||||
self.have_text(BasePageLocators.ALERT_WINDOW_TEXT_ERROR, text, \
|
||||
"Unexpected error message in alert window")
|
||||
elif alert_type == "success":
|
||||
self.have_text(BasePageLocators.ALERT_WINDOW_TEXT_SUCCESS, text, \
|
||||
"Unexpected message about success action in alert window")
|
||||
elif alert_type == "info":
|
||||
self.have_text(BasePageLocators.ALERT_WINDOW_TEXT_WARNING, text, \
|
||||
"Unexpected info message in alert window")
|
||||
elif alert_type == "warning":
|
||||
self.have_text(BasePageLocators.ALERT_WINDOW_TEXT_WARNING, text, \
|
||||
"Unexpected warning message about success action in alert window")
|
||||
else:
|
||||
assert False, "Unsupported type of alert window"
|
||||
self.check_absence_after_period(BasePageLocators.ALERT_WINDOW, 30000, \
|
||||
"Alert window for action notification should disappear")
|
||||
|
||||
def check_tooltip_with_text(self, locator, text):
|
||||
self.page.locator(locator).hover()
|
||||
tooltip = self.page.locator(BasePageLocators.TOOLTIP)
|
||||
assert tooltip.text_content().strip() == text, "Unexpected tooltip text"
|
||||
|
||||
def check_confirmation_dialog_with_title(self, locator, title):
|
||||
loc = self.page.locator(locator)
|
||||
expect(loc).to_contain_text(title), f"Confirmation dialog window with title {title} is not present"
|
||||
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
import os
|
||||
|
||||
class Constants:
|
||||
try:
|
||||
login = os.getenv('AUTH_LOGIN')
|
||||
password = os.getenv('AUTH_PASSWORD')
|
||||
except KeyError:
|
||||
print("LOGIN OR PASSWORD WASN'T FOUND")
|
||||
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
import os
|
||||
|
||||
class Environment:
|
||||
TEST = 'test'
|
||||
DEVELOP = 'develop'
|
||||
|
||||
URLS = {
|
||||
TEST: 'http://192.168.2.76/',
|
||||
DEVELOP: 'http://192.168.50.69/'
|
||||
}
|
||||
|
||||
def __init__(self):
|
||||
try:
|
||||
self.env = os.getenv('ENV')
|
||||
self.access_token = ""
|
||||
except KeyError:
|
||||
self.env = self.TEST
|
||||
|
||||
def get_base_url(self):
|
||||
if self.env in self.URLS:
|
||||
return self.URLS[self.env]
|
||||
else:
|
||||
raise Exception(f"Unknown value of ENV variable {self.env}")
|
||||
|
||||
def set_access_token(self, token):
|
||||
self.token = token
|
||||
|
||||
def get_access_token(self):
|
||||
return self.token
|
||||
|
||||
host = Environment()
|
||||
Binary file not shown.
|
|
@ -0,0 +1,95 @@
|
|||
import pytest
|
||||
from playwright.sync_api import Browser, BrowserContext, Page, sync_playwright
|
||||
import os
|
||||
|
||||
|
||||
|
||||
def pytest_addoption(parser):
|
||||
"""Пользовательские опции командной строки"""
|
||||
parser.addoption('--bn', action='store', default="chrome", help="Choose browser: chrome, remote_chrome or firefox")
|
||||
parser.addoption('--h', action='store', default=False, help='Choose headless: True or False')
|
||||
parser.addoption('--s', action='store', default={'width': 1520, 'height': 380}, help='Size window: width,height')
|
||||
# parser.addoption('--s', action='store', default={'width': 1920, 'height': 300}, help='Size window: width,height')
|
||||
parser.addoption('--slow', action='store', default=200, help='Choose slow_mo for robot action')
|
||||
parser.addoption('--t', action='store', default=60000, help='Choose timeout')
|
||||
parser.addoption('--l', action='store', default='ru-RU', help='Choose locale')
|
||||
# parser.addini('qs_to_api_token', default=os.getenv("QASE_TOKEN"), help='Qase app token')
|
||||
|
||||
|
||||
|
||||
@pytest.fixture(scope='class')
|
||||
def browser(request) -> Page:
|
||||
playwright = sync_playwright().start()
|
||||
if request.config.getoption("bn") == 'remote_chrome':
|
||||
browser = get_remote_chrome(playwright, request)
|
||||
context = get_context(browser, request, 'remote')
|
||||
page_data = context.new_page()
|
||||
elif request.config.getoption("bn") == 'firefox':
|
||||
browser = get_firefox_browser(playwright, request)
|
||||
context = get_context(browser, request, 'local')
|
||||
page_data = context.new_page()
|
||||
elif request.config.getoption("bn") == 'chrome':
|
||||
browser = get_chrome_browser(playwright, request)
|
||||
context = get_context(browser, request, 'local')
|
||||
page_data = context.new_page()
|
||||
else:
|
||||
browser = get_chrome_browser(playwright, request)
|
||||
context = get_context(browser, request, 'local')
|
||||
page_data = context.new_page()
|
||||
yield page_data
|
||||
for context in browser.contexts:
|
||||
context.close()
|
||||
browser.close()
|
||||
playwright.stop()
|
||||
|
||||
|
||||
def get_firefox_browser(playwright, request) -> Browser:
|
||||
return playwright.firefox.launch(
|
||||
headless=request.config.getoption("h"),
|
||||
slow_mo=request.config.getoption("slow"),
|
||||
)
|
||||
|
||||
|
||||
def get_chrome_browser(playwright, request) -> Browser:
|
||||
return playwright.chromium.launch(
|
||||
headless=request.config.getoption("h"),
|
||||
slow_mo=request.config.getoption("slow"),
|
||||
args=['--s']
|
||||
)
|
||||
|
||||
def get_remote_chrome(playwright, request) -> Browser:
|
||||
return playwright.chromium.launch(
|
||||
headless=True,
|
||||
slow_mo=request.config.getoption("slow")
|
||||
)
|
||||
|
||||
|
||||
def get_context(browser, request, start) -> BrowserContext:
|
||||
if start == 'local':
|
||||
context = browser.new_context(
|
||||
# no_viewport=True,
|
||||
viewport=request.config.getoption('s'),
|
||||
locale=request.config.getoption('l')
|
||||
)
|
||||
context.set_default_timeout(
|
||||
timeout=request.config.getoption('t')
|
||||
)
|
||||
# context.add_cookies([{'url': 'https://example.ru', 'name': 'ab_test', 'value': 'd'}]) добавляем куки, если нужны
|
||||
return context
|
||||
|
||||
elif start == 'remote':
|
||||
context = browser.new_context(
|
||||
viewport=request.config.getoption('s'),
|
||||
locale=request.config.getoption('l')
|
||||
)
|
||||
context.set_default_timeout(
|
||||
timeout=request.config.getoption('t')
|
||||
)
|
||||
# context.add_cookies([{'url': 'https://example.ru', 'name': 'ab_test', 'value': 'd'}]) добавляем куки, если нужны
|
||||
return context
|
||||
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
def return_back(browser):
|
||||
browser.go_back()
|
||||
|
|
@ -0,0 +1,93 @@
|
|||
import pytest
|
||||
from playwright.sync_api import Browser, BrowserContext, Page, sync_playwright
|
||||
import os
|
||||
|
||||
|
||||
|
||||
def pytest_addoption(parser):
|
||||
"""Пользовательские опции командной строки"""
|
||||
parser.addoption('--bn', action='store', default="chrome", help="Choose browser: chrome, remote_chrome or firefox")
|
||||
parser.addoption('--h', action='store', default=False, help='Choose headless: True or False')
|
||||
parser.addoption('--s', action='store', default={'width': 1920, 'height': 1080}, help='Size window: width,height')
|
||||
parser.addoption('--slow', action='store', default=200, help='Choose slow_mo for robot action')
|
||||
parser.addoption('--t', action='store', default=60000, help='Choose timeout')
|
||||
parser.addoption('--l', action='store', default='ru-RU', help='Choose locale')
|
||||
# parser.addini('qs_to_api_token', default=os.getenv("QASE_TOKEN"), help='Qase app token')
|
||||
|
||||
|
||||
|
||||
@pytest.fixture(scope='class')
|
||||
def browser(request) -> Page:
|
||||
playwright = sync_playwright().start()
|
||||
if request.config.getoption("bn") == 'remote_chrome':
|
||||
browser = get_remote_chrome(playwright, request)
|
||||
context = get_context(browser, request, 'remote')
|
||||
page_data = context.new_page()
|
||||
elif request.config.getoption("bn") == 'firefox':
|
||||
browser = get_firefox_browser(playwright, request)
|
||||
context = get_context(browser, request, 'local')
|
||||
page_data = context.new_page()
|
||||
elif request.config.getoption("bn") == 'chrome':
|
||||
browser = get_chrome_browser(playwright, request)
|
||||
context = get_context(browser, request, 'local')
|
||||
page_data = context.new_page()
|
||||
else:
|
||||
browser = get_chrome_browser(playwright, request)
|
||||
context = get_context(browser, request, 'local')
|
||||
page_data = context.new_page()
|
||||
yield page_data
|
||||
for context in browser.contexts:
|
||||
context.close()
|
||||
browser.close()
|
||||
playwright.stop()
|
||||
|
||||
|
||||
def get_firefox_browser(playwright, request) -> Browser:
|
||||
return playwright.firefox.launch(
|
||||
headless=request.config.getoption("h"),
|
||||
slow_mo=request.config.getoption("slow"),
|
||||
)
|
||||
|
||||
|
||||
def get_chrome_browser(playwright, request) -> Browser:
|
||||
return playwright.chromium.launch(
|
||||
headless=request.config.getoption("h"),
|
||||
slow_mo=request.config.getoption("slow"),
|
||||
args=['--start-maximized']
|
||||
)
|
||||
|
||||
def get_remote_chrome(playwright, request) -> Browser:
|
||||
return playwright.chromium.launch(
|
||||
headless=True,
|
||||
slow_mo=request.config.getoption("slow")
|
||||
)
|
||||
|
||||
|
||||
def get_context(browser, request, start) -> BrowserContext:
|
||||
if start == 'local':
|
||||
context = browser.new_context(
|
||||
no_viewport=True,
|
||||
locale=request.config.getoption('l')
|
||||
)
|
||||
context.set_default_timeout(
|
||||
timeout=request.config.getoption('t')
|
||||
)
|
||||
# context.add_cookies([{'url': 'https://example.ru', 'name': 'ab_test', 'value': 'd'}]) добавляем куки, если нужны
|
||||
return context
|
||||
|
||||
elif start == 'remote':
|
||||
context = browser.new_context(
|
||||
viewport=request.config.getoption('s'),
|
||||
locale=request.config.getoption('l')
|
||||
)
|
||||
context.set_default_timeout(
|
||||
timeout=request.config.getoption('t')
|
||||
)
|
||||
# context.add_cookies([{'url': 'https://example.ru', 'name': 'ab_test', 'value': 'd'}]) добавляем куки, если нужны
|
||||
return context
|
||||
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
def return_back(browser):
|
||||
browser.go_back()
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -0,0 +1,296 @@
|
|||
from playwright.sync_api import Page, TimeoutError, Response, APIRequestContext, expect
|
||||
from data.environment import host
|
||||
from Locators.base_page import BasePageLocators
|
||||
import time
|
||||
import json
|
||||
|
||||
class BasePage:
|
||||
def __init__(self, page: Page):
|
||||
self.page = page
|
||||
self.token = ""
|
||||
|
||||
def open(self, uri) -> Response | None:
|
||||
return self.page.goto(f"{host.get_base_url()}{uri}", wait_until='domcontentloaded')
|
||||
|
||||
def get_api_request_context(self) -> APIRequestContext:
|
||||
return self.page.context.request
|
||||
|
||||
#return page url
|
||||
def current_url(self) -> str:
|
||||
return self.page.url
|
||||
|
||||
# click on element
|
||||
def click(self, locator: str) -> None:
|
||||
self.page.click(locator)
|
||||
|
||||
# input in field
|
||||
def input(self, locator: str, data: str) -> None:
|
||||
self.page.locator(locator).fill(data)
|
||||
|
||||
# clear input field
|
||||
def clear_input(self, locator: str) -> None:
|
||||
self.page.locator(locator).press('Control+A')
|
||||
self.page.locator(locator).press('Backspace')
|
||||
|
||||
def page_reload(self) ->None:
|
||||
self.page.reload()
|
||||
|
||||
# wait for element
|
||||
def wait_for_element(self, locator, timeout=12000) -> None:
|
||||
self.page.wait_for_selector(locator, timeout=timeout)
|
||||
|
||||
# wait for all elements
|
||||
def wait_for_all_elements(self, locator, timeout=5000):
|
||||
elements = self.page.query_selector_all(locator)
|
||||
|
||||
for element in elements:
|
||||
self.page.wait_for_selector(locator, timeout=timeout)
|
||||
|
||||
return elements
|
||||
|
||||
# if element presents then ok
|
||||
def is_element_present(self, locator: str, timeout: int = 5000) -> bool:
|
||||
try:
|
||||
self.page.wait_for_selector(locator, timeout=timeout)
|
||||
except TimeoutError:
|
||||
return False
|
||||
return True
|
||||
|
||||
# if element is not present then ok
|
||||
def is_element_NOT_presence(self, locator: str, timeout: int = 5000) -> bool:
|
||||
try:
|
||||
self.page.wait_for_selector(locator, timeout=timeout)
|
||||
except TimeoutError:
|
||||
return True
|
||||
return False
|
||||
|
||||
# get text. If we have once locator then index is 0
|
||||
def get_text(self, locator: str, index: int) -> str:
|
||||
return self.page.locator(locator).nth(index).text_content()
|
||||
|
||||
# Traverse the table
|
||||
def read_table_data(self, locator) -> []:
|
||||
table_data = []
|
||||
|
||||
table = self.page.locator(locator)
|
||||
|
||||
# read table header
|
||||
header_cells = table.locator(BasePageLocators.TABLE_HEADERS_CELLS)
|
||||
header_data = []
|
||||
for h in range(header_cells.count()):
|
||||
header_cell_text = header_cells.nth(h).inner_text()
|
||||
header_data.append(header_cell_text)
|
||||
table_data.append(header_data)
|
||||
|
||||
# read table cells by rows
|
||||
rows = table.locator(BasePageLocators.TABLE_BODY)
|
||||
for i in range(rows.count()):
|
||||
row = rows.nth(i)
|
||||
cells = row.locator("td")
|
||||
row_data = []
|
||||
for j in range(cells.count()):
|
||||
cell_text = cells.nth(j).inner_text()
|
||||
row_data.append(cell_text)
|
||||
table_data.append(row_data)
|
||||
|
||||
return table_data
|
||||
|
||||
# send get request to api
|
||||
def send_get_api_request(self, uri):
|
||||
api_request_context = self.get_api_request_context()
|
||||
token = host.get_access_token()
|
||||
headers = {"Accept": "application/json", "Authorization": f"Bearer {token}"}
|
||||
response = api_request_context.get(f"{host.get_base_url()}{uri}", headers = headers)
|
||||
return response
|
||||
|
||||
# send get request to api
|
||||
def send_post_api_request(self, uri, payload):
|
||||
api_request_context = self.get_api_request_context()
|
||||
token = host.get_access_token()
|
||||
headers = {"Accept": "application/json", "Authorization": f"Bearer {token}"}
|
||||
response = api_request_context.post(f"{host.get_base_url()}{uri}", headers = headers, data=payload)
|
||||
return response
|
||||
|
||||
# get response body
|
||||
def get_response_body(self, response):
|
||||
try:
|
||||
response_body = response.json()
|
||||
except json.JSONDecodeError:
|
||||
print("Failed to decode JSON response")
|
||||
return None
|
||||
return response_body
|
||||
|
||||
def should_be_horizontal_scroll(self) -> None:
|
||||
"""
|
||||
Проверяет горизонтальный скролл с плавной прокруткой.
|
||||
"""
|
||||
modal_selector = "div.v-dialog.v-dialog--active"
|
||||
modal = self.page.locator(modal_selector).first
|
||||
|
||||
try:
|
||||
# Ожидаем появления окна
|
||||
modal.wait_for(state="visible", timeout=5000)
|
||||
|
||||
# Получаем размеры через page.evaluate
|
||||
scroll_data = self.page.evaluate("""() => {
|
||||
const modal = document.querySelector('div.v-dialog.v-dialog--active');
|
||||
return {
|
||||
scrollWidth: modal.scrollWidth,
|
||||
clientWidth: modal.clientWidth,
|
||||
scrollLeft: modal.scrollLeft
|
||||
};
|
||||
}""")
|
||||
|
||||
print(f"Окно: Общая ширина: {scroll_data['scrollWidth']}px, "
|
||||
f"Видимая область: {scroll_data['clientWidth']}px, "
|
||||
f"Начальная позиция: {scroll_data['scrollLeft']}px")
|
||||
|
||||
if scroll_data['scrollWidth'] > scroll_data['clientWidth']:
|
||||
print("Тестируем скролл...")
|
||||
|
||||
# Плавный скролл вправо
|
||||
self.page.evaluate("""() => {
|
||||
const modal = document.querySelector('div.v-dialog.v-dialog--active');
|
||||
return new Promise(resolve => {
|
||||
const target = modal.scrollWidth - modal.clientWidth;
|
||||
const duration = 1000;
|
||||
const start = modal.scrollLeft;
|
||||
const startTime = performance.now();
|
||||
|
||||
function scrollStep(timestamp) {
|
||||
const progress = (timestamp - startTime) / duration;
|
||||
modal.scrollLeft = start + (target - start) * Math.min(progress, 1);
|
||||
if (progress < 1) {
|
||||
window.requestAnimationFrame(scrollStep);
|
||||
} else {
|
||||
resolve();
|
||||
}
|
||||
}
|
||||
window.requestAnimationFrame(scrollStep);
|
||||
});
|
||||
}""")
|
||||
|
||||
# Проверяем конечную позицию
|
||||
final_scroll = self.page.evaluate("""() => {
|
||||
return document.querySelector('div.v-dialog.v-dialog--active').scrollLeft;
|
||||
}""")
|
||||
print("Успешно проскроллили вправо")
|
||||
|
||||
# Плавный скролл влево
|
||||
self.page.evaluate("""() => {
|
||||
const modal = document.querySelector('div.v-dialog.v-dialog--active');
|
||||
return new Promise(resolve => {
|
||||
const duration = 1000;
|
||||
const start = modal.scrollLeft;
|
||||
const startTime = performance.now();
|
||||
|
||||
function scrollStep(timestamp) {
|
||||
const progress = (timestamp - startTime) / duration;
|
||||
modal.scrollLeft = start - start * Math.min(progress, 1);
|
||||
if (progress < 1) {
|
||||
window.requestAnimationFrame(scrollStep);
|
||||
} else {
|
||||
resolve();
|
||||
}
|
||||
}
|
||||
window.requestAnimationFrame(scrollStep);
|
||||
});
|
||||
}""")
|
||||
|
||||
# Проверяем возврат в начало
|
||||
final_scroll = self.page.evaluate("""() => {
|
||||
return document.querySelector('div.v-dialog.v-dialog--active').scrollLeft;
|
||||
}""")
|
||||
assert final_scroll == 0, "Не удалось вернуться в начальную позицию скролла"
|
||||
print("Успешно проскроллили влево")
|
||||
else:
|
||||
print("Окно не требует горизонтального скролла.")
|
||||
|
||||
except Exception as e:
|
||||
print(f"Ошибка при проверке скролла окна: {str(e)}")
|
||||
raise
|
||||
|
||||
def should_be_vertical_scroll(self, wrapper_selector: str = "div.scrolltable__wrapper") -> None:
|
||||
"""
|
||||
Проверяет вертикальный скролл в указанном контейнере.
|
||||
Args:
|
||||
wrapper_selector: CSS-селектор скроллируемого контейнера.
|
||||
По умолчанию: "div.scrolltable__wrapper".
|
||||
"""
|
||||
# Ожидаем загрузки таблицы
|
||||
table_wrapper = self.page.locator(wrapper_selector).first
|
||||
table_wrapper.wait_for(state="visible", timeout=10000)
|
||||
|
||||
try:
|
||||
# Пытаемся найти скроллируемый элемент с небольшим таймаутом
|
||||
scrollable_element = table_wrapper.locator("tbody.scrolltable__scroll").first
|
||||
scrollable_element.wait_for(state="attached", timeout=3000)
|
||||
|
||||
# Проверяем параметры скролла
|
||||
scroll_height = scrollable_element.evaluate("el => el.scrollHeight")
|
||||
client_height = scrollable_element.evaluate("el => el.clientHeight")
|
||||
scroll_data = scrollable_element.evaluate("el => el.scrollLeft")
|
||||
|
||||
|
||||
print(f"Окно: Общая ширина: {scroll_height}px, "
|
||||
f"Видимая область: {client_height}px, "
|
||||
f"Начальная позиция: {scroll_data}px")
|
||||
|
||||
if scroll_height > client_height:
|
||||
print("Тестируем скролл...")
|
||||
|
||||
# 1. Плавный скролл вниз
|
||||
scrollable_element.evaluate("""el => {
|
||||
const target = el.scrollHeight;
|
||||
const duration = 1000;
|
||||
const start = el.scrollTop;
|
||||
const startTime = performance.now();
|
||||
|
||||
function scrollStep(timestamp) {
|
||||
const progress = (timestamp - startTime) / duration;
|
||||
el.scrollTop = start + (target - start) * Math.min(progress, 1);
|
||||
if (progress < 1) {
|
||||
window.requestAnimationFrame(scrollStep);
|
||||
}
|
||||
}
|
||||
window.requestAnimationFrame(scrollStep);
|
||||
}""")
|
||||
time.sleep(1.5) # Ожидаем завершения скролла
|
||||
|
||||
# Проверяем последнюю строку
|
||||
last_row = table_wrapper.locator("tbody tr").last
|
||||
expect(last_row).to_be_visible()
|
||||
print("Успешно проскроллили вниз")
|
||||
|
||||
# 2. Плавный скролл вверх
|
||||
scrollable_element.evaluate("""el => {
|
||||
const duration = 1000;
|
||||
const start = el.scrollTop;
|
||||
const startTime = performance.now();
|
||||
|
||||
function scrollStep(timestamp) {
|
||||
const progress = (timestamp - startTime) / duration;
|
||||
el.scrollTop = start - start * Math.min(progress, 1);
|
||||
if (progress < 1) {
|
||||
window.requestAnimationFrame(scrollStep);
|
||||
}
|
||||
}
|
||||
window.requestAnimationFrame(scrollStep);
|
||||
}""")
|
||||
time.sleep(1.5) # Ожидаем завершения скролла
|
||||
|
||||
# Проверяем первую строку
|
||||
first_row = table_wrapper.locator("tbody tr").first
|
||||
expect(first_row).to_be_visible()
|
||||
print("Успешно проскроллили вверх")
|
||||
else:
|
||||
print("Весь контент виден без скролла")
|
||||
|
||||
except Exception as e:
|
||||
print(f"Элемент для скролла не найден или не скроллится: {e}")
|
||||
# Проверяем, есть ли хотя бы строки в таблице
|
||||
rows = table_wrapper.locator("tbody tr")
|
||||
if rows.count() > 0:
|
||||
print(f"Найдено {rows.count()} строк в таблице без скролла")
|
||||
else:
|
||||
print("Таблица пуста или не найдена")
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
from pages.base_page import BasePage
|
||||
from Locators.configuration_page import ConfigurationPageLocators
|
||||
from data.assertions import Assertions
|
||||
from playwright.sync_api import Page
|
||||
|
||||
import json
|
||||
|
||||
class ConfigurationPage(BasePage):
|
||||
def __init__(self, page: Page) -> None:
|
||||
super().__init__(page)
|
||||
self.assertion = Assertions(page)
|
||||
|
||||
def should_be_configuration_navigation_panel(self):
|
||||
self.assertion.check_presence(ConfigurationPageLocators.CONFIG_NAVIGATION_PANEL, \
|
||||
"Configuration navigation panel is not present on the Configuration page")
|
||||
def should_be_maintenance_navigation_panel(self):
|
||||
self.assertion.check_presence(ConfigurationPageLocators.MAINTENANCE_NAVIGATION_PANEL, \
|
||||
"Maintenance navigation panel is not present on the Configuration page")
|
||||
|
||||
def click_configuration_navigation_panel_item(self, item_name):
|
||||
button_locator = None
|
||||
|
||||
if item_name == "users":
|
||||
button_locator = ConfigurationPageLocators.CONFIG_NAVIGATION_PANEL_USER_BUTTON
|
||||
elif item_name == "notification":
|
||||
button_locator = ConfigurationPageLocators.CONFIG_NAVIGATION_PANEL_NOTIFICATION_BUTTON
|
||||
elif item_name == "maintenance":
|
||||
button_locator = ConfigurationPageLocators.CONFIG_NAVIGATION_PANEL_MAINTENANCE_BUTTON
|
||||
elif item_name == "ztp":
|
||||
button_locator = ConfigurationPageLocators.CONFIG_NAVIGATION_PANEL_ZTP_BUTTON
|
||||
else:
|
||||
assert False, "Unsupported configuration navigation panel item"
|
||||
|
||||
self.click(button_locator)
|
||||
|
||||
def click_maintenance_navigation_panel_item(self, item_name):
|
||||
button_locator = None
|
||||
|
||||
if item_name == "session":
|
||||
button_locator = ConfigurationPageLocators.MAINTENANCE_NAVIGATION_PANEL_SESSION_BUTTON
|
||||
elif item_name == "service_status":
|
||||
button_locator = ConfigurationPageLocators.MAINTENANCE_NAVIGATION_PANEL_SERVICE_STATUS_BUTTON
|
||||
elif item_name == "licensing":
|
||||
button_locator = ConfigurationPageLocators.MAINTENANCE_NAVIGATION_PANEL_LICENSING_BUTTON
|
||||
else:
|
||||
assert False, "Unsupported configuration navigation panel item"
|
||||
|
||||
self.click(button_locator)
|
||||
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
from pages.base_page import BasePage
|
||||
# from Locators.email_tab import EmailTabLocators
|
||||
from data.assertions import Assertions
|
||||
from playwright.sync_api import Page
|
||||
|
||||
class EmailTab(BasePage):
|
||||
def __init__(self, page: Page) -> None:
|
||||
super().__init__(page)
|
||||
self.assertion = Assertions(page)
|
||||
|
|
@ -0,0 +1,102 @@
|
|||
from pages.base_page import BasePage
|
||||
from Locators.configuration_page import ConfigurationPageLocators
|
||||
from Locators.license_tab import LicenseTabLocators
|
||||
from data.assertions import Assertions
|
||||
from playwright.sync_api import Page
|
||||
|
||||
import json
|
||||
|
||||
class LicenseTab(BasePage):
|
||||
def __init__(self, page: Page) -> None:
|
||||
super().__init__(page)
|
||||
self.assertion = Assertions(page)
|
||||
|
||||
def fill_license_input_form(self, value):
|
||||
button_text = "Обновить лицензию"
|
||||
|
||||
self.clear_input(LicenseTabLocators.LICENSE_INPUT_FORM_TEXTAREA)
|
||||
self.input(LicenseTabLocators.LICENSE_INPUT_FORM_TEXTAREA, value)
|
||||
|
||||
self.page.get_by_role("button", name=button_text).click()
|
||||
|
||||
def should_be_error_alert_window_with_text(self, text):
|
||||
self.assertion.check_alert_window_with_text("error", text)
|
||||
|
||||
def should_be_license_work_area(self):
|
||||
self.assertion.have_title(ConfigurationPageLocators.WORK_AREA_TITLE, "Лицензирование", \
|
||||
"Expected work area page title is not equal real title")
|
||||
self.should_be_json_content()
|
||||
self.should_be_license_input_form()
|
||||
|
||||
def should_be_license_input_form(self):
|
||||
# get form title and compare with cmdb value
|
||||
form_title = "Идентификатор:"
|
||||
title = self.get_text(LicenseTabLocators.LICENSE_TITLE, 0)
|
||||
self.assertion.check_equals(title.strip(), form_title, \
|
||||
f"Expected input form title {title} is not equal {form_title}")
|
||||
|
||||
device_id = self.get_text(LicenseTabLocators.LICENSE_TITLE_DEVICE_ID, 0).strip()
|
||||
|
||||
response = self.send_get_api_request("e-cmdb/api/lic/deviceid")
|
||||
response_body = self.get_response_body(response)
|
||||
|
||||
self.assertion.check_equals(device_id, response_body["deviceId"], \
|
||||
f"Expected ID value {device_id} is not equal {response_body['deviceId']}")
|
||||
|
||||
# check input form presence
|
||||
self.assertion.check_presence(LicenseTabLocators.LICENSE_INPUT_FORM_TEXTAREA, \
|
||||
"License input form is not present on the License work area")
|
||||
# check input form button
|
||||
button_text = "Обновить лицензию"
|
||||
self.assertion.check_button_presence_with_text(button_text, f"License input form button with text {button_text} is not present")
|
||||
|
||||
def should_be_json_content(self):
|
||||
def format_json_string(json_string):
|
||||
substrings = json_string.splitlines()
|
||||
|
||||
formatted_string_list = []
|
||||
|
||||
last_substring = substrings.pop()
|
||||
|
||||
for substring in substrings:
|
||||
if substring.find(':') == -1:
|
||||
if substring == '{':
|
||||
formatted_string_list.append(substring)
|
||||
elif substring == '}':
|
||||
s1 = formatted_string_list.pop()
|
||||
formatted_string_list.append(s1.rstrip(','))
|
||||
formatted_string_list.append(substring+ ',')
|
||||
else:
|
||||
formatted_string_list.append(substring + ',')
|
||||
continue
|
||||
|
||||
key, value = substring.split(':')
|
||||
|
||||
s = ':'.join(['"'+key+'" '," " + value])
|
||||
if value == '{':
|
||||
formatted_string_list.append(s)
|
||||
else:
|
||||
formatted_string_list.append(s + ',')
|
||||
|
||||
s2 = formatted_string_list.pop()
|
||||
formatted_string_list.append(s2.rstrip(','))
|
||||
|
||||
formatted_string_list.append(last_substring)
|
||||
|
||||
return " " .join(formatted_string_list)
|
||||
|
||||
## read json_content from work area
|
||||
json_string = self.page.locator(LicenseTabLocators.JSON_ELEMENT).inner_text()
|
||||
formatted_json_string = format_json_string(json_string)
|
||||
expected_json_data = json.loads(formatted_json_string)
|
||||
|
||||
# send request to backend to get license info
|
||||
response = self.send_get_api_request("e-cmdb/api/lic")
|
||||
response_body = self.get_response_body(response)
|
||||
|
||||
## temporarily
|
||||
del response_body["netManagment"]
|
||||
response_body["ui"].pop("lcc")
|
||||
|
||||
self.assertion.check_json_equals(expected_json_data, response_body, \
|
||||
"Expected json content is not equal actual:")
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
from pages.base_page import BasePage
|
||||
from data.constants import Constants
|
||||
from Locators.login import LoginPageLocators
|
||||
from data.assertions import Assertions
|
||||
from data.environment import host
|
||||
from playwright.sync_api import Page
|
||||
|
||||
class LoginPage(BasePage):
|
||||
def __init__(self, page: Page) -> None:
|
||||
super().__init__(page)
|
||||
self.token = ""
|
||||
self.assertion = Assertions(page)
|
||||
|
||||
def do_login(self, username: str = None, password: str = None):
|
||||
"""Выполняет вход в систему.
|
||||
Если username/password не указаны, использует значения из Constants"""
|
||||
def handle_response(response):
|
||||
if "login" in response.url:
|
||||
response_body = self.get_response_body(response)
|
||||
if response_body:
|
||||
token = response_body.get("access_token")
|
||||
host.set_access_token(token)
|
||||
|
||||
self.page.on("response", handle_response)
|
||||
|
||||
self.open("")
|
||||
|
||||
# Используем переданные значения или значения по умолчанию из Constants
|
||||
actual_username = username if username is not None else Constants.login
|
||||
actual_password = password if password is not None else Constants.password
|
||||
|
||||
self.clear_input(LoginPageLocators.USERNAME_INPUT)
|
||||
self.input(LoginPageLocators.USERNAME_INPUT, actual_username)
|
||||
|
||||
self.clear_input(LoginPageLocators.PASSWORD_INPUT)
|
||||
self.input(LoginPageLocators.PASSWORD_INPUT, actual_password)
|
||||
|
||||
self.click(LoginPageLocators.LOGIN_BTN)
|
||||
|
||||
self.assertion.check_URL("dashboard", "An unexpected page has been opened")
|
||||
|
||||
def do_unsuccessful_login(self, username: str = "someuser", password: str = "password"):
|
||||
"""Выполняет попытку входа с неверными учетными данными.
|
||||
Можно передать свои неверные данные или использовать значения по умолчанию"""
|
||||
incorrect_credentials_text = "Неверная пара логин/пароль"
|
||||
|
||||
self.open("")
|
||||
|
||||
self.clear_input(LoginPageLocators.USERNAME_INPUT)
|
||||
self.input(LoginPageLocators.USERNAME_INPUT, username)
|
||||
|
||||
self.clear_input(LoginPageLocators.PASSWORD_INPUT)
|
||||
self.input(LoginPageLocators.PASSWORD_INPUT, password)
|
||||
|
||||
self.click(LoginPageLocators.LOGIN_BTN)
|
||||
|
||||
self.assertion.check_alert_window_with_text("error", incorrect_credentials_text)
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
from pages.base_page import BasePage
|
||||
from Locators.main_page import MainPageLocators
|
||||
from data.assertions import Assertions
|
||||
from playwright.sync_api import Page
|
||||
|
||||
class MainPage(BasePage):
|
||||
def __init__(self, page: Page) -> None:
|
||||
super().__init__(page)
|
||||
self.assertion = Assertions(page)
|
||||
|
||||
def should_be_navigation_panel(self):
|
||||
self.assertion.check_presence(MainPageLocators.NAVIGATION_PANEL, "Navigation panel is not present")
|
||||
|
||||
def click_main_navigation_panel_item(self, item_name):
|
||||
button_locator = None
|
||||
header_locator = None
|
||||
|
||||
if item_name == "dashboard":
|
||||
button_locator = MainPageLocators.NAVIGATION_PANEL_DASHBOARD_BUTTON
|
||||
header_locator = MainPageLocators.NAVIGATION_PANEL_DASHBOARD_BUTTON_HEADER
|
||||
elif item_name == "topology":
|
||||
button_locator = MainPageLocators.NAVIGATION_PANEL_TOPOLOGY_BUTTON
|
||||
header_locator = MainPageLocators.NAVIGATION_PANEL_TOPOLOGY_BUTTON_HEADER
|
||||
elif item_name == "configuration":
|
||||
button_locator = MainPageLocators.NAVIGATION_PANEL_CONFIGURATION_BUTTON
|
||||
header_locator = MainPageLocators.NAVIGATION_PANEL_CONFIGURATION_BUTTON_HEADER
|
||||
else:
|
||||
assert False, "Unsupported main navigation panel item"
|
||||
|
||||
self.click(button_locator)
|
||||
self.assertion.check_URL(item_name, "An unexpected page has been opened")
|
||||
self.assertion.check_element_active(header_locator, f"{item_name} button is not active")
|
||||
|
||||
def do_logout(self):
|
||||
self.click(MainPageLocators.CURRENT_USER_BUTTON)
|
||||
|
||||
self.assertion.check_presence(MainPageLocators.CURRENT_USER_WINDOW, "Window with current user data has not been opened")
|
||||
|
||||
logout_button_text = "Выйти"
|
||||
self.page.get_by_role("button", name=logout_button_text).click()
|
||||
|
||||
self.assertion.check_URL("login", "An unexpected page has been opened")
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
from pages.base_page import BasePage
|
||||
from Locators.configuration_page import ConfigurationPageLocators
|
||||
from data.assertions import Assertions
|
||||
from playwright.sync_api import Page
|
||||
|
||||
class ServiceStatusTab(BasePage):
|
||||
def __init__(self, page: Page) -> None:
|
||||
super().__init__(page)
|
||||
self.assertion = Assertions(page)
|
||||
|
||||
def should_be_service_status_work_area(self):
|
||||
self.assertion.have_title(ConfigurationPageLocators.WORK_AREA_TITLE, "Статус обслуживания", \
|
||||
"Expected work area page title is not equal real title")
|
||||
|
||||
self.should_be_service_status_table()
|
||||
|
||||
|
||||
def should_be_service_status_table(self):
|
||||
headers = ['Контейнер', 'Время создания', 'Статус', 'Время работы', 'Image ID', 'Image ТЭГ']
|
||||
|
||||
service_status_table = self.read_table_data(ConfigurationPageLocators.WORK_AREA_TABLE)
|
||||
|
||||
service_status_table_headers = service_status_table[0]
|
||||
self.assertion.check_equals(service_status_table_headers, headers, \
|
||||
f"Expected table headers {service_status_table_headers} are not equal {headers}")
|
||||
self.assertion.check_not_equals(len(service_status_table) - 1, 0, \
|
||||
"Service status table is empty")
|
||||
|
|
@ -0,0 +1,221 @@
|
|||
from pages.base_page import BasePage
|
||||
from Locators.session_locators import SessionLocators
|
||||
from data.assertions import Assertions
|
||||
from playwright.sync_api import Page, expect
|
||||
import time
|
||||
|
||||
class SessionTab(BasePage):
|
||||
def __init__(self, page: Page) -> None:
|
||||
super().__init__(page)
|
||||
self.assertions = Assertions(page)
|
||||
self.expected_headers = ['ID сессии', 'ID пользователя', 'Время жизни', 'Роль', 'Адрес']
|
||||
|
||||
def should_be_session_table(self) -> None:
|
||||
""" Проверка таблицы сессий """
|
||||
|
||||
self.assertions.have_title(
|
||||
SessionLocators.TEXT_TITLE,
|
||||
'Сессия',
|
||||
"Заголовок страницы не соответствует ожидаемому"
|
||||
)
|
||||
|
||||
# Проверка наименования заголовков таблицы сессий
|
||||
session_table_data = self.read_table_data(SessionLocators.TABLE_BODY)
|
||||
actual_headers = session_table_data[0]
|
||||
|
||||
self.assertions.check_equals(actual_headers, self.expected_headers, "Заголовки таблицы не соответствуют ожидаемым")
|
||||
|
||||
# Проверка, что таблица не пустая
|
||||
self.assertions.check_not_equals(len(session_table_data) - 1, 0, "Таблица сессий пуста")
|
||||
|
||||
# Проверка наличия всех необходимых колонок
|
||||
required_columns = [
|
||||
SessionLocators.TABLE_HEADER_CELL_SESSION_ID,
|
||||
SessionLocators.TABLE_HEADER_CELL_USER_ID,
|
||||
SessionLocators.TABLE_HEADER_CELL_LIFETIME,
|
||||
SessionLocators.TABLE_HEADER_CELL_ROLE,
|
||||
SessionLocators.TABLE_HEADER_CELL_ADDRESS
|
||||
]
|
||||
|
||||
for locator in required_columns:
|
||||
self.is_element_present(locator, 1000)
|
||||
|
||||
|
||||
def should_be_session_table_data_vs_api(self) -> None:
|
||||
""" Проверка соответствие данных в таблице сессий с данными из API """
|
||||
ROLE_MAPPING = {
|
||||
'user': 'Пользователь',
|
||||
'administrator': 'Администратор'
|
||||
}
|
||||
|
||||
# Получение данных из UI
|
||||
ui_session_id = self.get_text(SessionLocators.TABLE_HEADER_CELL_SESSION_ID, 0).strip()
|
||||
ui_session_userId = self.get_text(SessionLocators.TABLE_HEADER_CELL_USER_ID, 0).strip()
|
||||
ui_session_roles = self.get_text(SessionLocators.TABLE_HEADER_CELL_ROLE, 0).strip()
|
||||
ui_session_ip = self.get_text(SessionLocators.TABLE_HEADER_CELL_ADDRESS, 0).strip()
|
||||
|
||||
# Получение данных из API
|
||||
response = self.send_get_api_request("e-nms/auth/sessions")
|
||||
response_body = self.get_response_body(response)
|
||||
|
||||
api_session_id = response_body[0].get('id')
|
||||
api_session_userId = response_body[0].get('userId')
|
||||
api_session_roles = response_body[0].get('roles', [])
|
||||
api_session_ip = response_body[0].get('ip')
|
||||
|
||||
# Преобразование и сортировка ролей из API
|
||||
translated_roles = [ROLE_MAPPING.get(role.lower(), role) for role in api_session_roles]
|
||||
api_session_roles_str = ', '.join(sorted(translated_roles))
|
||||
|
||||
# Сортировка ролей из UI для сравнения
|
||||
ui_roles_sorted = ', '.join(sorted(role.strip() for role in ui_session_roles.split(',')))
|
||||
|
||||
# Проверки соответствия данных
|
||||
self.assertions.check_equals(ui_session_id, api_session_id, "ID сессии не совпадает")
|
||||
self.assertions.check_equals(ui_session_userId, api_session_userId, "ID пользователя не совпадает")
|
||||
self.assertions.check_equals(ui_roles_sorted, api_session_roles_str, "Роли не совпадают")
|
||||
self.assertions.check_equals(ui_session_ip, api_session_ip, "IP-адрес не совпадает")
|
||||
|
||||
# Логирование для отладки
|
||||
#print(f"Session ID (UI/API): {ui_session_id}/{api_session_id}")
|
||||
#print(f"User ID (UI/API): {ui_session_userId}/{api_session_userId}")
|
||||
#print(f"Roles (UI/API): {ui_session_roles}/{api_session_roles}")
|
||||
#print(f"IP Address (UI/API): {ui_session_ip}/{api_session_ip}")
|
||||
|
||||
def should_be_new_session_added(self) -> None:
|
||||
"""
|
||||
Проверка добавленных записей в таблицу сессий
|
||||
"""
|
||||
|
||||
def should_be_vertical_scroll_session(self) -> None:
|
||||
""" Проверка вертикального скролла таблицы сессий """
|
||||
|
||||
self.should_be_vertical_scroll(SessionLocators.TABLE_SCROLL_CONTAINER)
|
||||
|
||||
|
||||
def open_last_session_modal(self) -> None:
|
||||
"""Открывает модальное окно удаления через последнюю строку таблицы сессий"""
|
||||
print("\n=== Открытие модального окна через последнюю строку ===")
|
||||
|
||||
# Ожидаем загрузки таблицы
|
||||
self.page.wait_for_selector(SessionLocators.TABLE_BODY, state="visible", timeout=5000)
|
||||
print("✓ Таблица сессий загружена")
|
||||
|
||||
# Получаем все строки таблицы
|
||||
rows = self.page.locator(SessionLocators.TABLE_ROWS)
|
||||
row_count = rows.count()
|
||||
|
||||
if row_count == 0:
|
||||
raise AssertionError("Таблица сессий пуста, нечего удалять!")
|
||||
|
||||
print(f"Всего строк в таблице: {row_count}")
|
||||
|
||||
# Берём последнюю строку
|
||||
last_row = rows.last
|
||||
print("✓ Последняя строка получена")
|
||||
|
||||
# Прокручиваем к последней строке (если нужно)
|
||||
last_row.scroll_into_view_if_needed()
|
||||
|
||||
# Локатор кнопки удаления в последней строке
|
||||
delete_button = last_row.locator(SessionLocators.BUTTON_DELETE_SESSION)
|
||||
|
||||
# Проверяем и кликаем кнопку удаления
|
||||
expect(delete_button).to_be_visible(timeout=5000)
|
||||
print("Нажимаем кнопку удаления в последней строке...")
|
||||
delete_button.click()
|
||||
|
||||
# Проверяем появление модального окна
|
||||
modal = self.page.locator(SessionLocators.MODAL_WINDOW)
|
||||
expect(modal).to_be_visible(timeout=5000)
|
||||
print("✓ Модальное окно удаления успешно открыто")
|
||||
|
||||
# Проверка заголовка окна
|
||||
if hasattr(SessionLocators, 'MODAL_TITLE'):
|
||||
modal_title = self.page.locator(SessionLocators.MODAL_TITLE)
|
||||
expect(modal_title).to_contain_text("Удаление")
|
||||
print("✓ Заголовок модального окна корректен")
|
||||
|
||||
print("=== Модальное окно через последнюю строку открыто успешно ===\n")
|
||||
|
||||
def should_be_horizontal_scroll_session_modal(self) -> None:
|
||||
""" Проверка горизонтального скролла модального окна """
|
||||
self.should_be_horizontal_scroll()
|
||||
|
||||
|
||||
def should_be_close_modal_window_by_button(self, button_type: str) -> None:
|
||||
"""
|
||||
Проверка кнопок модального окна подтверждения удаления сессии с детальным логированием
|
||||
:param button_type: Тип кнопки ('close', 'cancel', 'delete')
|
||||
"""
|
||||
print(f"\n=== Начало проверки модального окна для кнопки '{button_type}' ===")
|
||||
|
||||
# 1. Проверка видимости модального окна перед действиями
|
||||
modal = self.page.locator(SessionLocators.MODAL_WINDOW)
|
||||
expect(modal).to_be_visible()
|
||||
print("✓ Модальное окно отображается перед взаимодействием")
|
||||
|
||||
if button_type == 'close':
|
||||
# 2. Нажатие кнопки закрытия (X)
|
||||
print("Нажимаем кнопку закрытия (X)...")
|
||||
close_button = self.page.locator(SessionLocators.MODAL_CLOSE_BUTTON)
|
||||
close_button.click()
|
||||
|
||||
# 3. Проверка закрытия окна
|
||||
expect(modal).not_to_be_visible()
|
||||
print("✓ Проверяем, что окно закрылось после нажатия 'X'")
|
||||
|
||||
elif button_type == 'cancel':
|
||||
# 2. Нажатие кнопки "Отмена"
|
||||
print("Нажимаем кнопку 'Отмена'...")
|
||||
cancel_button = self.page.locator(SessionLocators.MODAL_CANCEL_BUTTON)
|
||||
cancel_button.click()
|
||||
|
||||
# 3. Проверка закрытия окна
|
||||
expect(modal).not_to_be_visible()
|
||||
print("✓ Проверяем, что окно закрылось после нажатия 'Отмена'")
|
||||
|
||||
elif button_type == 'delete':
|
||||
# 2. Подготовка к удалению
|
||||
rows_before = self.page.locator(SessionLocators.TABLE_ROWS).count()
|
||||
print(f"Количество строк до удаления: {rows_before}")
|
||||
|
||||
# 3. Нажатие кнопки "Удалить"
|
||||
print("Нажимаем кнопку 'Удалить'...")
|
||||
delete_button = self.page.locator(SessionLocators.MODAL_DELETE_BUTTON)
|
||||
delete_button.click()
|
||||
"""
|
||||
# 4. Проверка сообщения об успехе
|
||||
success_msg = self.page.locator(SessionLocators.SUCCESS_MESSAGE)
|
||||
expect(success_msg).to_be_visible(timeout=5000)
|
||||
expect(success_msg).to_contain_text("Сессия успешно удалена")
|
||||
print("✓ Сообщение об успешном удалении отображается")
|
||||
"""
|
||||
# 5. Проверка закрытия окна
|
||||
expect(modal).not_to_be_visible()
|
||||
print("✓ Проверяем, что окно закрылось после нажатия 'Удалить'")
|
||||
"""
|
||||
# 6. Проверка исчезновения сообщения (если нужно)
|
||||
expect(success_msg).not_to_be_visible(timeout=10000)
|
||||
print("✓ Сообщение автоматически скрылось (если предусмотрено UI)")
|
||||
"""
|
||||
# 7. Проверка изменения таблицы
|
||||
rows_after = self.page.locator(SessionLocators.TABLE_ROWS).count()
|
||||
self.assertions.check_equals(rows_after, rows_before - 1,
|
||||
"Количество строк не изменилось после удаления")
|
||||
print(f"✓ Количество строк после удаления: {rows_after} (уменьшилось на 1)")
|
||||
|
||||
print(f"=== Проверка для кнопки '{button_type}' успешно завершена ===\n")
|
||||
|
||||
|
||||
def delete_all_created_sessions(self, username) -> None:
|
||||
""" Проверка удаления созданных ссесий """
|
||||
|
||||
def delete_current_session(self) -> None:
|
||||
""" Проверка удаления текущей сессии """
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,432 @@
|
|||
from pages.base_page import BasePage
|
||||
from Locators.base_page import BasePageLocators
|
||||
from Locators.configuration_page import ConfigurationPageLocators
|
||||
from Locators.users_tab import UsersTabLocators
|
||||
from data.assertions import Assertions
|
||||
from playwright.sync_api import Page
|
||||
|
||||
import re
|
||||
|
||||
class UsersTab(BasePage):
|
||||
def __init__(self, page: Page) -> None:
|
||||
super().__init__(page)
|
||||
self.assertion = Assertions(page)
|
||||
self.role_dict = {"administrator": "Администратор",
|
||||
"manager":"Контактное лицо",
|
||||
"operator":"Оператор",
|
||||
"inform_secur_user" : "Специалист информационной безопасности"}
|
||||
|
||||
def add_new_user(self, user_data):
|
||||
fields = user_data.keys()
|
||||
|
||||
self.assertion.check_presence(UsersTabLocators.USER_DATA_INPUT_FORM, \
|
||||
"Input form for add new user is not present")
|
||||
|
||||
## input user name
|
||||
if "name" in fields:
|
||||
loc = "xpath=div[2]/div[2]/div/div/div/div/input"
|
||||
self.page.locator(UsersTabLocators.USER_DATA_INPUT_FORM).locator(loc).fill(user_data["name"])
|
||||
|
||||
|
||||
## input user role
|
||||
if "role" in fields:
|
||||
loc = "xpath=div[3]/div[2]/div/div/div/div/div[1]"
|
||||
self.page.locator(UsersTabLocators.USER_DATA_INPUT_FORM).locator(loc).click()
|
||||
|
||||
self.assertion.check_presence(UsersTabLocators.USER_DATA_INPUT_FORM_ROLES_MENU, \
|
||||
"Roles drop-down menu is not present")
|
||||
role = user_data["role"]
|
||||
self.assertion.check_menu_item_with_text(role, f"No menu item with text: {role}")
|
||||
self.page.get_by_role("listitem").filter(has_text=role).click()
|
||||
|
||||
## input password
|
||||
if "password" in fields:
|
||||
loc = "xpath=div[4]/div[2]/div/div/div/div/input"
|
||||
self.page.locator(UsersTabLocators.USER_DATA_INPUT_FORM).locator(loc).fill(user_data["password"])
|
||||
|
||||
## input commentary
|
||||
if "commentary" in fields:
|
||||
loc = "xpath=div[5]/div[2]/div/div/div/div/input"
|
||||
self.page.locator(UsersTabLocators.USER_DATA_INPUT_FORM).locator(loc).fill(user_data["commentary"])
|
||||
|
||||
## input e-mail
|
||||
if "email" in fields:
|
||||
loc = "xpath=div[6]/div[2]/div/div/div/div/input"
|
||||
self.page.locator(UsersTabLocators.USER_DATA_INPUT_FORM).locator(loc).fill(user_data["email"])
|
||||
|
||||
## input phone number for sms
|
||||
if "phone_number" in fields:
|
||||
loc = "xpath=div[7]/div[2]/div/div/div/div/input"
|
||||
self.page.locator(UsersTabLocators.USER_DATA_INPUT_FORM).locator(loc).fill(user_data["phone_number"])
|
||||
|
||||
##to be done: checkbox
|
||||
|
||||
## click add user button
|
||||
add_button_text = "Добавить"
|
||||
self.assertion.check_button_presence_with_text(add_button_text, f"Add user input form button with text {add_button_text} is not present")
|
||||
self.page.get_by_role("button", name=add_button_text).click()
|
||||
|
||||
##check add user confirmation dialog
|
||||
confirm_add_button_text = " Добавить "
|
||||
self.assertion.check_confirmation_dialog_with_title(UsersTabLocators.USER_ACTION_CONFIRMATION_DIALOG, "Добавить нового пользователя")
|
||||
self.page.get_by_role("button", name=confirm_add_button_text).first.click()
|
||||
|
||||
## check message about successfull user addition
|
||||
self.assertion.check_alert_window_with_text("success", ' Новый пользователь \n успешно добавлен! ')
|
||||
|
||||
|
||||
def close_user_window_by_toolbar_button(self, window_title):
|
||||
BUTTON_CLOSE_ON_TOOLBAR = f"xpath=(.//*[normalize-space(text()) and normalize-space(.)='{window_title}'])[1]/following::*[name()='svg'][1]"
|
||||
self.assertion.check_presence(BUTTON_CLOSE_ON_TOOLBAR, \
|
||||
"Close button is not presenet on toolbar")
|
||||
self.click(BUTTON_CLOSE_ON_TOOLBAR)
|
||||
|
||||
self.assertion.check_absence(UsersTabLocators.USER_DATA_WORK_AREA_TITLE, \
|
||||
f"{window_title} window should be closed")
|
||||
|
||||
def close_user_window(self, window_title):
|
||||
close_button_text = "Закрыть"
|
||||
self.assertion.check_button_presence_with_text(close_button_text, f"Edit user input form button with text {close_button_text} is not present")
|
||||
self.page.get_by_role("button", name=close_button_text).click()
|
||||
|
||||
self.assertion.check_absence(UsersTabLocators.USER_DATA_WORK_AREA_TITLE, \
|
||||
f"{window_title} window should be closed")
|
||||
|
||||
def delete_user(self):
|
||||
remove_button_text = "Удалить"
|
||||
self.assertion.check_button_presence_with_text(remove_button_text, f"Edit user input form button with text {remove_button_text} is not present")
|
||||
self.page.get_by_role("button", name=remove_button_text).click()
|
||||
|
||||
##check add user confirmation dialog
|
||||
confirm_remove_button_text = " Удалить "
|
||||
self.assertion.check_confirmation_dialog_with_title(UsersTabLocators.USER_ACTION_CONFIRMATION_DIALOG, "Удаление")
|
||||
self.page.get_by_role("button", name=confirm_remove_button_text).first.click()
|
||||
|
||||
## check message about successfull user deletion
|
||||
self.assertion.check_alert_window_with_text("success", '\nПользователь удалён\n')
|
||||
|
||||
def edit_user(self, user_data):
|
||||
fields = user_data.keys()
|
||||
|
||||
self.assertion.check_presence(UsersTabLocators.USER_DATA_INPUT_FORM, \
|
||||
"Input form for edit user is not present")
|
||||
|
||||
## input user name
|
||||
if "name" in fields:
|
||||
loc = "xpath=div[2]/div[2]/div/div/div/div/input"
|
||||
self.page.locator(UsersTabLocators.USER_DATA_INPUT_FORM).locator(loc).fill(user_data["name"])
|
||||
|
||||
|
||||
## input user role
|
||||
if "role" in fields:
|
||||
loc = "xpath=div[3]/div[2]/div/div/div/div/div[1]"
|
||||
self.page.locator(UsersTabLocators.USER_DATA_INPUT_FORM).locator(loc).click()
|
||||
|
||||
self.assertion.check_presence(UsersTabLocators.USER_DATA_INPUT_FORM_ROLES_MENU, \
|
||||
"Roles drop-down menu is not present")
|
||||
role = user_data["role"]
|
||||
self.assertion.check_menu_item_with_text(role, f"No menu item with text: {role}")
|
||||
self.page.get_by_role("listitem").filter(has_text=role).click()
|
||||
|
||||
## input commentary
|
||||
if "commentary" in fields:
|
||||
loc = "xpath=div[5]/div[2]/div/div/div/div/input"
|
||||
self.page.locator(UsersTabLocators.USER_DATA_INPUT_FORM).locator(loc).fill(user_data["commentary"])
|
||||
|
||||
## input e-mail
|
||||
if "email" in fields:
|
||||
loc = "xpath=div[5]/div[2]/div/div/div/div/input"
|
||||
self.page.locator(UsersTabLocators.USER_DATA_INPUT_FORM).locator(loc).fill(user_data["email"])
|
||||
|
||||
## input phone number for sms
|
||||
if "phone_number" in fields:
|
||||
loc = "xpath=div[6]/div[2]/div/div/div/div/input"
|
||||
self.page.locator(UsersTabLocators.USER_DATA_INPUT_FORM).locator(loc).fill(user_data["phone_number"])
|
||||
|
||||
##to be done: checkbox
|
||||
|
||||
## click add user button
|
||||
add_button_text = "Сохранить"
|
||||
self.assertion.check_button_presence_with_text(add_button_text, f"Add user input form button with text {add_button_text} is not present")
|
||||
self.page.get_by_role("button", name=add_button_text).click()
|
||||
|
||||
##check add user confirmation dialog
|
||||
confirm_add_button_text = " Сохранить "
|
||||
self.assertion.check_confirmation_dialog_with_title(UsersTabLocators.USER_ACTION_CONFIRMATION_DIALOG, "Сохранение")
|
||||
self.page.get_by_role("button", name=confirm_add_button_text).first.click()
|
||||
|
||||
## check message about successfull user addition. Temporarily without translation
|
||||
self.assertion.check_alert_window_with_text("success", '\nupdate success\n')
|
||||
|
||||
|
||||
def open_add_user_page(self):
|
||||
self.assertion.check_presence(UsersTabLocators.TOOLBAR_EDIT_BUTTON, \
|
||||
"Edit button is not presenet on toolbar")
|
||||
self.click(UsersTabLocators.TOOLBAR_EDIT_BUTTON)
|
||||
self.assertion.check_presence(UsersTabLocators.TOOLBAR_ADD_USER_BUTTON, \
|
||||
"Add User button is not presenet on toolbar")
|
||||
|
||||
self.click(UsersTabLocators.TOOLBAR_ADD_USER_BUTTON)
|
||||
|
||||
# check that new work area with title has been opened
|
||||
self.assertion.have_title(UsersTabLocators.USER_DATA_WORK_AREA_TITLE, "Добавить нового пользователя", \
|
||||
"Expected work area page title is not equal real title")
|
||||
|
||||
def open_edit_user_page_by_index(self, row_index):
|
||||
## temporarily
|
||||
tmp_dict = {"admin":"Администратор", "manager":"Контактное лицо", "operator":"Оператор"}
|
||||
|
||||
users_table = self.read_table_data(ConfigurationPageLocators.WORK_AREA_TABLE)
|
||||
self.assertion.check_not_equals(len(users_table) - 1, 0, "Users table is empty")
|
||||
|
||||
# remove header
|
||||
del users_table[0]
|
||||
|
||||
# check row_index
|
||||
if row_index > len(users_table):
|
||||
assert False, "Row_index is out of range"
|
||||
|
||||
# get user name and role
|
||||
user_name = users_table[row_index][0]
|
||||
for key, val in tmp_dict.items():
|
||||
if user_name == val:
|
||||
user_name = key
|
||||
|
||||
role = users_table[row_index][2]
|
||||
|
||||
# click to found table row
|
||||
self.page.locator(ConfigurationPageLocators.WORK_AREA_TABLE).locator(BasePageLocators.TABLE_BODY).nth(row_index).click()
|
||||
|
||||
# check that edit user work area with user name title has been opened
|
||||
self.assertion.have_title(UsersTabLocators.USER_DATA_WORK_AREA_TITLE, user_name, \
|
||||
"Expected edit user work area page title is not equal real title")
|
||||
return user_name, role
|
||||
|
||||
def reset_password(self):
|
||||
new_password = ""
|
||||
|
||||
reset_password_button_text = "Сбросить пароль"
|
||||
self.assertion.check_button_presence_with_text(reset_password_button_text, f"Edit user input form button with text {reset_password_button_text} is not present")
|
||||
self.page.get_by_role("button", name=reset_password_button_text).click()
|
||||
|
||||
alert_message = self.get_text(BasePageLocators.ALERT_WINDOW_TEXT_SUCCESS, 0)
|
||||
if len(alert_message) > 0:
|
||||
new_password = re.findall(r'[\d]+', alert_message)[0]
|
||||
|
||||
return new_password
|
||||
|
||||
def open_edit_user_page_by_name(self, name, role):
|
||||
row_index = self.find_user_in_table(name, role)
|
||||
if row_index == -1:
|
||||
assert False, f"User with name {name} and role {role} has not been found"
|
||||
|
||||
# click to found table row
|
||||
self.page.locator(ConfigurationPageLocators.WORK_AREA_TABLE).locator(BasePageLocators.TABLE_BODY).nth(row_index).click()
|
||||
|
||||
# check that edit user work area with user name title has been opened
|
||||
self.assertion.have_title(UsersTabLocators.USER_DATA_WORK_AREA_TITLE, name, \
|
||||
"Expected edit user work area page title is not equal real title")
|
||||
|
||||
def should_be_users_work_area(self):
|
||||
self.assertion.have_title(ConfigurationPageLocators.WORK_AREA_TITLE, "Пользователи", \
|
||||
"Expected work area page title is not equal real title")
|
||||
|
||||
self.assertion.check_presence(UsersTabLocators.TOOLBAR_EDIT_BUTTON, \
|
||||
"Edit button is not presenet on toolbar")
|
||||
self.should_be_users_table()
|
||||
|
||||
def should_be_users_page_toolbar_buttons(self):
|
||||
self.assertion.check_presence(UsersTabLocators.TOOLBAR_EDIT_BUTTON, \
|
||||
"Edit button is not presenet on toolbar")
|
||||
self.assertion.check_tooltip_with_text(UsersTabLocators.TOOLBAR_EDIT_BUTTON, "Редактировать")
|
||||
|
||||
self.click(UsersTabLocators.TOOLBAR_EDIT_BUTTON)
|
||||
self.assertion.check_presence(UsersTabLocators.TOOLBAR_ADD_USER_BUTTON, \
|
||||
"Add User button is not presenet on toolbar")
|
||||
self.assertion.check_presence(UsersTabLocators.TOOLBAR_CLOSE_BUTTON, \
|
||||
"Close button is not presenet on toolbar")
|
||||
|
||||
self.assertion.check_tooltip_with_text(UsersTabLocators.TOOLBAR_ADD_USER_BUTTON, "Добавить")
|
||||
self.assertion.check_tooltip_with_text(UsersTabLocators.TOOLBAR_CLOSE_BUTTON, "Закрыть")
|
||||
|
||||
self.click(UsersTabLocators.TOOLBAR_CLOSE_BUTTON)
|
||||
self.assertion.check_presence(UsersTabLocators.TOOLBAR_EDIT_BUTTON, \
|
||||
"Edit button is not presenet on toolbar")
|
||||
|
||||
def should_be_add_user_work_area(self):
|
||||
self.assertion.have_title(UsersTabLocators.USER_DATA_WORK_AREA_TITLE, "Добавить нового пользователя", \
|
||||
"Expected add user window title is not equal real title")
|
||||
self.assertion.check_presence(UsersTabLocators.ADD_USER_WORK_AREA_CLOSE_BUTTON, \
|
||||
"Close button is not presenet on toolbar")
|
||||
self.assertion.check_tooltip_with_text(UsersTabLocators.ADD_USER_WORK_AREA_CLOSE_BUTTON, "Закрыть")
|
||||
|
||||
# check input form
|
||||
self.should_be_add_user_input_form()
|
||||
|
||||
# check input form buttons
|
||||
add_button_text = "Добавить"
|
||||
self.assertion.check_button_presence_with_text(add_button_text, f"Add user input form button with text {add_button_text} is not present")
|
||||
|
||||
close_button_text = "Закрыть"
|
||||
self.assertion.check_button_presence_with_text(close_button_text, f"Add user input form button with text {close_button_text} is not present")
|
||||
|
||||
def should_be_edit_user_work_area(self, user_name, role):
|
||||
EDIT_USER_WORK_AREA_CLOSE_BUTTON = f"xpath=(.//*[normalize-space(text()) and normalize-space(.)='{user_name}'])[1]/following::*[name()='svg'][1]"
|
||||
|
||||
self.assertion.have_title(UsersTabLocators.USER_DATA_WORK_AREA_TITLE, f"{user_name}", \
|
||||
"Expected edit user window title is not equal real title")
|
||||
|
||||
self.assertion.check_presence(EDIT_USER_WORK_AREA_CLOSE_BUTTON, \
|
||||
"Close button is not presenet on toolbar")
|
||||
self.assertion.check_tooltip_with_text(EDIT_USER_WORK_AREA_CLOSE_BUTTON, "Закрыть")
|
||||
|
||||
# check edit user input form
|
||||
self.should_be_edit_user_input_form(user_name, role)
|
||||
|
||||
# check input form buttons
|
||||
save_button_text = "Сохранить"
|
||||
self.assertion.check_button_presence_with_text(save_button_text, f"Edit user input form button with text {save_button_text} is not present")
|
||||
|
||||
remove_button_text = "Удалить"
|
||||
self.assertion.check_button_presence_with_text(remove_button_text, f"Edit user input form button with text {remove_button_text} is not present")
|
||||
|
||||
reset_password_button_text = "Сбросить пароль"
|
||||
self.assertion.check_button_presence_with_text(reset_password_button_text, f"Edit user input form button with text {reset_password_button_text} is not present")
|
||||
|
||||
close_button_text = "Закрыть"
|
||||
self.assertion.check_button_presence_with_text(close_button_text, f"Edit user input form button with text {close_button_text} is not present")
|
||||
|
||||
def should_be_users_table(self):
|
||||
headers = ['Имя пользователя', 'hash_password', 'Роль', 'E-mail', 'Номер для СМС']
|
||||
|
||||
users_table = self.read_table_data(ConfigurationPageLocators.WORK_AREA_TABLE)
|
||||
|
||||
users_table_headers = users_table[0]
|
||||
self.assertion.check_equals(users_table_headers, headers, \
|
||||
f"Expected table headers {users_table_headers} are not equal {headers}")
|
||||
self.assertion.check_not_equals(len(users_table) - 1, 0, \
|
||||
"Users table is empty")
|
||||
self.verify_users_table_content(users_table)
|
||||
|
||||
def should_be_add_user_input_form(self):
|
||||
self.assertion.check_presence(UsersTabLocators.USER_DATA_INPUT_FORM, \
|
||||
"Input form for add new user is not present")
|
||||
|
||||
n = 7
|
||||
for i in range (1, n + 1):
|
||||
loc = f"xpath=div[{i}]/div[2]/div/div/div/div/input"
|
||||
input_area = self.page.locator(UsersTabLocators.USER_DATA_INPUT_FORM).locator(loc)
|
||||
if i == 1:
|
||||
checked = self.page.get_by_role("checkbox").first.is_checked()
|
||||
self.assertion.check_equals(checked, False, "Checkbox is checked by default")
|
||||
|
||||
loc = f"xpath={UsersTabLocators.USER_DATA_INPUT_FORM}/div[1]/div[2]/div/div/div{UsersTabLocators.USER_DATA_INPUT_FORM_NOTIFICATION_LABEL}"
|
||||
self.assertion.have_text(loc, "ad", \
|
||||
"Label for ad is not present")
|
||||
elif i == 3:
|
||||
loc = f"xpath=div[{i}]/div[2]/div/div/div/div/div[1]"
|
||||
self.page.locator(UsersTabLocators.USER_DATA_INPUT_FORM).locator(loc).click()
|
||||
|
||||
self.assertion.check_presence(UsersTabLocators.USER_DATA_INPUT_FORM_ROLES_MENU, \
|
||||
"Roles drop-down menu is not present")
|
||||
roles = self.role_dict.values()
|
||||
|
||||
for role in roles:
|
||||
self.assertion.check_menu_item_with_text(role, f"No menu item with text: {role}")
|
||||
else:
|
||||
self.assertion.check_empty_input_area(input_area, "No empty input area")
|
||||
|
||||
checked = self.page.get_by_role("checkbox").nth(1).is_checked()
|
||||
self.assertion.check_equals(checked, False, "Checkbox is checked by default")
|
||||
|
||||
loc = f"xpath={UsersTabLocators.USER_DATA_INPUT_FORM}/div[8]/div/div/div/div{UsersTabLocators.USER_DATA_INPUT_FORM_NOTIFICATION_LABEL}"
|
||||
self.assertion.have_text(loc, "Подписка на Push-уведомления", \
|
||||
"Label for push-notifications subscribtion is not present")
|
||||
|
||||
def should_be_edit_user_input_form(self, user_name, role):
|
||||
self.assertion.check_presence(UsersTabLocators.USER_DATA_INPUT_FORM, \
|
||||
"Input form for edit user is not present")
|
||||
|
||||
loc = "xpath=div[2]/div[2]/div/div/div/div/input"
|
||||
text_value = self.page.locator(UsersTabLocators.USER_DATA_INPUT_FORM).locator(loc).input_value()
|
||||
|
||||
|
||||
self.assertion.check_equals(text_value, user_name, "Expected user name is not equal real user name")
|
||||
|
||||
self.assertion.check_menu_item_with_text(role, f"No menu item with text: {role}")
|
||||
|
||||
def should_be_user_in_table(self, name, role):
|
||||
found = self.find_user_in_table(name, role)
|
||||
if found == -1:
|
||||
assert False, f"User with name {name} and role {role} has not been found"
|
||||
|
||||
def should_not_be_user_in_table(self, name, role):
|
||||
found = self.find_user_in_table(name, role)
|
||||
if found != -1:
|
||||
assert False, f"User with name {name} and role {role} has been found"
|
||||
|
||||
def find_user_in_table(self, name, role):
|
||||
users_table = self.read_table_data(ConfigurationPageLocators.WORK_AREA_TABLE)
|
||||
self.assertion.check_not_equals(len(users_table) - 1, 0, "Users table is empty")
|
||||
|
||||
# remove header
|
||||
del users_table[0]
|
||||
|
||||
not_found_index = -1
|
||||
row_index = 0
|
||||
|
||||
for user_info in users_table:
|
||||
if name in user_info and role in user_info:
|
||||
return row_index
|
||||
row_index += 1
|
||||
return not_found_index
|
||||
|
||||
def verify_users_table_content(self, users_table):
|
||||
expected_users_list = []
|
||||
|
||||
## temporarily
|
||||
tmp_dict = {"admin":"Администратор", "manager":"Контактное лицо", "operator":"Оператор"}
|
||||
|
||||
query = {"id": ["/catalogs/user"], "data": {"namePath": True, "children": {"flatten": True}}}
|
||||
|
||||
response = self.send_post_api_request("e-cmdb/api/query", query)
|
||||
response_body = self.get_response_body(response)
|
||||
|
||||
for item in response_body[0]["children"]:
|
||||
user_info = []
|
||||
|
||||
## temporarily
|
||||
user_name = item["name"]
|
||||
if user_name in tmp_dict.keys():
|
||||
item["name"] = tmp_dict[user_name]
|
||||
|
||||
user_info.append(item["name"])
|
||||
if item["password"] is not None:
|
||||
user_info.append(item["password"])
|
||||
else:
|
||||
user_info.append("")
|
||||
if item["role"] is not None:
|
||||
role = item["role"]
|
||||
if role in self.role_dict.keys():
|
||||
item["role"] = self.role_dict[role]
|
||||
user_info.append(item["role"])
|
||||
else:
|
||||
user_info.append("")
|
||||
if item["email"] is not None:
|
||||
user_info.append(item["email"])
|
||||
else:
|
||||
user_info.append("")
|
||||
if item["sms_phone"] is not None:
|
||||
user_info.append(item["sms_phone"])
|
||||
else:
|
||||
user_info.append("")
|
||||
|
||||
expected_users_list.append(user_info)
|
||||
|
||||
# remove header
|
||||
del users_table[0]
|
||||
|
||||
self.assertion.check_lists_equals(users_table, expected_users_list, \
|
||||
"Actual users list is not equal users list from db")
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
from pages.base_page import BasePage
|
||||
# from Locators.ztp_tab import ZTPTabLocators
|
||||
from data.assertions import Assertions
|
||||
from playwright.sync_api import Page
|
||||
|
||||
class ZTPConfigurationTab(BasePage):
|
||||
def __init__(self, page: Page) -> None:
|
||||
super().__init__(page)
|
||||
self.assertion = Assertions(page)
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
from pages.base_page import BasePage
|
||||
# from Locators.ztp_tab import ZTPTabLocators
|
||||
from data.assertions import Assertions
|
||||
from playwright.sync_api import Page
|
||||
|
||||
class ZTPTemplatesTab(BasePage):
|
||||
def __init__(self, page: Page) -> None:
|
||||
super().__init__(page)
|
||||
self.assertion = Assertions(page)
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
[pytest]
|
||||
markers =
|
||||
develop: current test development
|
||||
addopts = -v -s
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
pytest
|
||||
playwright
|
||||
requests
|
||||
qase-pytest==4.2.0
|
||||
python-dotenv
|
||||
jsondiff
|
||||
|
||||
Binary file not shown.
|
|
@ -0,0 +1,99 @@
|
|||
import pytest
|
||||
from pages.login_page import LoginPage
|
||||
from pages.main_page import MainPage
|
||||
from pages.configuration_page import ConfigurationPage
|
||||
from pages.license_tab import LicenseTab
|
||||
|
||||
import uuid
|
||||
|
||||
## @pytest.mark.smoke
|
||||
class TestLicenseTab:
|
||||
def test_license_tab_content(self, browser):
|
||||
lp = LoginPage(browser)
|
||||
lp.do_login()
|
||||
|
||||
# we are on main page
|
||||
mp = MainPage(browser)
|
||||
|
||||
# check navigation panel presence
|
||||
mp.should_be_navigation_panel()
|
||||
|
||||
# click to Configuration button in main navigation panel
|
||||
mp.click_main_navigation_panel_item("configuration")
|
||||
|
||||
# we are on configuration page
|
||||
cp = ConfigurationPage(browser)
|
||||
|
||||
# click to Technical Maintenance button in configuration navigation panel
|
||||
cp.click_configuration_navigation_panel_item("maintenance")
|
||||
|
||||
# check Maintenance navigation panel presence
|
||||
cp.should_be_maintenance_navigation_panel()
|
||||
|
||||
# click to Service Status button in configuration navigation panel
|
||||
cp.click_maintenance_navigation_panel_item("licensing")
|
||||
|
||||
# license tab has been opened
|
||||
lt = LicenseTab(browser)
|
||||
|
||||
# check service status work area
|
||||
lt.should_be_license_work_area()
|
||||
|
||||
def test_license_tab_input_form_and_check_alert(self, browser):
|
||||
def gen_test_data():
|
||||
data = []
|
||||
for i in range(3):
|
||||
data.append(uuid.uuid4().hex)
|
||||
|
||||
lowercase_str = uuid.uuid4().hex
|
||||
data.append(lowercase_str.upper())
|
||||
data.append(lowercase_str+"fffffffff")
|
||||
data.append("0")
|
||||
data.append("000000000000000000000000000000000000000000000000")
|
||||
data.append("-1")
|
||||
|
||||
return data
|
||||
|
||||
|
||||
lp = LoginPage(browser)
|
||||
lp.do_login()
|
||||
|
||||
# we are on main page
|
||||
mp = MainPage(browser)
|
||||
|
||||
# check navigation panel presence
|
||||
mp.should_be_navigation_panel()
|
||||
|
||||
# click to Configuration button in main navigation panel
|
||||
mp.click_main_navigation_panel_item("configuration")
|
||||
|
||||
# we are on configuration page
|
||||
cp = ConfigurationPage(browser)
|
||||
|
||||
# click to Technical Maintenance button in configuration navigation panel
|
||||
cp.click_configuration_navigation_panel_item("maintenance")
|
||||
|
||||
# check Maintenance navigation panel presence
|
||||
cp.should_be_maintenance_navigation_panel()
|
||||
|
||||
# click to Service Status button in configuration navigation panel
|
||||
cp.click_maintenance_navigation_panel_item("licensing")
|
||||
|
||||
# license tab has been opened
|
||||
lt = LicenseTab(browser)
|
||||
|
||||
# check that license input form presents
|
||||
lt.should_be_license_input_form()
|
||||
|
||||
# input empty string
|
||||
lt.fill_license_input_form("")
|
||||
# check alert window
|
||||
lt.should_be_error_alert_window_with_text("Неверный лицензионный ключ")
|
||||
|
||||
data = gen_test_data()
|
||||
|
||||
for data_string in data:
|
||||
# input incorrect value
|
||||
lt.fill_license_input_form(data_string)
|
||||
# check alert window
|
||||
lt.should_be_error_alert_window_with_text("Ошибка обновления лицензии")
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
import pytest
|
||||
from pages.login_page import LoginPage
|
||||
from pages.main_page import MainPage
|
||||
|
||||
## @pytest.mark.smoke
|
||||
class TestLogin:
|
||||
def test_successful_login(self, browser):
|
||||
lp = LoginPage(browser)
|
||||
lp.do_login()
|
||||
|
||||
def test_unsuccessful_login(self, browser):
|
||||
lp = LoginPage(browser)
|
||||
lp.do_unsuccessful_login()
|
||||
|
||||
def test_successful_login_and_logout(self, browser):
|
||||
lp = LoginPage(browser)
|
||||
lp.do_login()
|
||||
|
||||
# we are on main page
|
||||
mp = MainPage(browser)
|
||||
|
||||
# do logout
|
||||
mp.do_logout()
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
import pytest
|
||||
import time
|
||||
from pages.login_page import LoginPage
|
||||
from pages.main_page import MainPage
|
||||
from pages.configuration_page import ConfigurationPage
|
||||
from pages.session_tab import SessionTab
|
||||
from pages.scroll_tab import ScrollTab
|
||||
|
||||
|
||||
## @pytest.mark.smoke
|
||||
class TestSessionTab:
|
||||
def test_session_tab_content(self, browser):
|
||||
lp1 = LoginPage(browser)
|
||||
lp1.do_login()
|
||||
#'''
|
||||
users = [f"User{i}" for i in range(1, 9)] # Генерация списка пользователей
|
||||
|
||||
for username in users:
|
||||
login_page = LoginPage(browser)
|
||||
login_page.do_login(username=username, password="admin")
|
||||
#'''
|
||||
# we are on main page
|
||||
mp = MainPage(browser)
|
||||
|
||||
# check navigation panel presence
|
||||
mp.should_be_navigation_panel()
|
||||
|
||||
# click to Configuration button in main navigation panel
|
||||
mp.click_main_navigation_panel_item("configuration")
|
||||
|
||||
# we are on configuration page
|
||||
cp = ConfigurationPage(browser)
|
||||
sc = ScrollTab(browser)
|
||||
|
||||
# click to Users button in configuration navigation panel
|
||||
cp.click_configuration_navigation_panel_item("users")
|
||||
sc.check_vertical_scroll("//*[@id='app']/div[150]/div/div[1]/div/div[1]/div/div[2]/div/div/div/div/div/div/div")
|
||||
|
||||
# click to Technical Maintenance button in configuration navigation panel
|
||||
cp.click_configuration_navigation_panel_item("maintenance")
|
||||
cp.should_be_maintenance_navigation_panel()
|
||||
|
||||
# click to Session button in configuration navigation panel
|
||||
cp.click_maintenance_navigation_panel_item("session")
|
||||
sc.check_vertical_scroll("div.layout.white.column.fill-height")
|
||||
|
||||
|
||||
# click to Service Status button in configuration navigation panel
|
||||
cp.click_maintenance_navigation_panel_item("service_status")
|
||||
sc.check_vertical_scroll("//*[@id='app']/div[151]/div/div[1]/div/div[1]/div/div[2]/div/div/div/div/div/div/div")
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
import pytest
|
||||
from pages.login_page import LoginPage
|
||||
from pages.main_page import MainPage
|
||||
from pages.configuration_page import ConfigurationPage
|
||||
from pages.service_status_tab import ServiceStatusTab
|
||||
|
||||
## @pytest.mark.smoke
|
||||
class TestServiceStatusTab:
|
||||
def test_service_status_tab_content(self, browser):
|
||||
lp = LoginPage(browser)
|
||||
lp.do_login()
|
||||
|
||||
# we are on main page
|
||||
mp = MainPage(browser)
|
||||
|
||||
# check navigation panel presence
|
||||
mp.should_be_navigation_panel()
|
||||
|
||||
# click to Configuration button in main navigation panel
|
||||
mp.click_main_navigation_panel_item("configuration")
|
||||
|
||||
# we are on configuration page
|
||||
cp = ConfigurationPage(browser)
|
||||
|
||||
# click to Technical Maintenance button in configuration navigation panel
|
||||
cp.click_configuration_navigation_panel_item("maintenance")
|
||||
|
||||
# check Maintenance navigation panel presence
|
||||
cp.should_be_maintenance_navigation_panel()
|
||||
|
||||
# click to Service Status button in configuration navigation panel
|
||||
cp.click_maintenance_navigation_panel_item("service_status")
|
||||
|
||||
# service status tab has been opened
|
||||
sst = ServiceStatusTab(browser)
|
||||
|
||||
# check service status work area
|
||||
sst.should_be_service_status_work_area()
|
||||
|
||||
|
|
@ -0,0 +1,162 @@
|
|||
from pages.login_page import LoginPage
|
||||
from pages.main_page import MainPage
|
||||
from pages.users_tab import UsersTab
|
||||
from pages.configuration_page import ConfigurationPage
|
||||
from pages.session_tab import SessionTab
|
||||
|
||||
import pytest
|
||||
|
||||
## @pytest.mark.smoke # Закомментированная метка для smoke-тестов
|
||||
class TestSessionTab:
|
||||
|
||||
def test_add_users(self, browser):
|
||||
"""Тест создания 9 пользователей User1..User9 с ролью Администратор"""
|
||||
# Переходим на страницу авторизации
|
||||
lp = LoginPage(browser)
|
||||
# Выполняем вход в систему (по умолчанию)
|
||||
lp.do_login()
|
||||
|
||||
# Переходим на главную страницу
|
||||
mp = MainPage(browser)
|
||||
|
||||
# Проверяем наличие панели навигации
|
||||
mp.should_be_navigation_panel()
|
||||
|
||||
# Нажимаем на кнопку "Configuration" в главной панели навигации
|
||||
mp.click_main_navigation_panel_item("configuration")
|
||||
|
||||
# Переходим на страницу конфигурации
|
||||
cp = ConfigurationPage(browser)
|
||||
|
||||
# Нажимаем вкладку "Users" в панели навигации конфигурации
|
||||
cp.click_configuration_navigation_panel_item("users")
|
||||
|
||||
# Переходим на вкладку пользователей
|
||||
ut = UsersTab(browser)
|
||||
|
||||
# Создаем 9 пользователей
|
||||
for i in range(1, 10):
|
||||
user_data = {
|
||||
"name": f"User{i}", # Генерируем имя пользователя
|
||||
"role": "Администратор", # Устанавливаем роль
|
||||
"password": "admin" # Пароль для всех пользователей
|
||||
}
|
||||
ut.open_add_user_page() # Открываем страницу добавления пользователя
|
||||
ut.add_new_user(user_data) # Добавляем пользователя с заданными данными
|
||||
|
||||
# Двойной клик по вкладке Users ( баг )
|
||||
cp.click_configuration_navigation_panel_item("users")
|
||||
cp.click_configuration_navigation_panel_item("users")
|
||||
|
||||
# Проверяем, что пользователь появился в таблице
|
||||
ut.should_be_user_in_table(user_data["name"], user_data["role"])
|
||||
|
||||
def test_login_users(self, browser):
|
||||
"""Тест входа под созданными пользователями (создание 9 сессий)"""
|
||||
|
||||
# Генерируем список имен пользователей
|
||||
users = [f"User{i}" for i in range(1, 9)]
|
||||
|
||||
# Выполняем вход в систему 9 созданными пользователями
|
||||
for username in users:
|
||||
login_page = LoginPage(browser)
|
||||
login_page.do_login(username=username, password="admin")
|
||||
|
||||
|
||||
def test_session_tab_content(self, browser):
|
||||
"""Тест проверки содержимого вкладки сессий"""
|
||||
lp = LoginPage(browser)
|
||||
lp.do_login()
|
||||
|
||||
mp = MainPage(browser)
|
||||
|
||||
# Проверяем наличие панели навигации
|
||||
mp.should_be_navigation_panel()
|
||||
|
||||
# Нажимаем на кнопку "Configuration" в главной панели навигации
|
||||
mp.click_main_navigation_panel_item("configuration")
|
||||
|
||||
# Переходим на страницу конфигурации
|
||||
cp = ConfigurationPage(browser)
|
||||
|
||||
# Нажимаем на кнопку "Technical Maintenance" в панели навигации конфигурации
|
||||
cp.click_configuration_navigation_panel_item("maintenance")
|
||||
|
||||
# Проверяем наличие панели навигации Maintenance
|
||||
cp.should_be_maintenance_navigation_panel()
|
||||
|
||||
# Нажимаем на вкладку "Session" в панели навигации Maintenanc
|
||||
cp.click_maintenance_navigation_panel_item("session")
|
||||
|
||||
# Работаем с вкладкой сессий
|
||||
st = SessionTab(browser)
|
||||
|
||||
# Проверяем наличие таблицы сессий
|
||||
st.should_be_session_table()
|
||||
|
||||
# Проверяем соответствие данных в таблице данным из API
|
||||
st.should_be_session_table_data_vs_api()
|
||||
|
||||
#st.should_be_new_session_added() требуется разработать
|
||||
|
||||
# Проверяем наличие вертикальной прокрутки в таблице сессий
|
||||
st.should_be_vertical_scroll_session()
|
||||
|
||||
# Открываем модальное окно последней сессии
|
||||
st.open_last_session_modal()
|
||||
|
||||
# Проверяем наличие горизонтальной прокрутки в модальном окне
|
||||
st.should_be_horizontal_scroll_session_modal()
|
||||
|
||||
# Закрываем модальное окно кнопкой "close"
|
||||
st.should_be_close_modal_window_by_button("close")
|
||||
|
||||
# Закрываем модальное окно кнопкой "cancel"
|
||||
st.open_last_session_modal()
|
||||
st.should_be_close_modal_window_by_button("cancel")
|
||||
|
||||
# Закрываем модальное окно кнопкой "delete"
|
||||
st.open_last_session_modal()
|
||||
st.should_be_close_modal_window_by_button("delete")
|
||||
|
||||
|
||||
def test_delete_users(self, browser):
|
||||
"""Тест удаления созданных пользователей (в обратном порядке)"""
|
||||
lp = LoginPage(browser)
|
||||
lp.do_login()
|
||||
|
||||
# Переходим на главную страницу
|
||||
mp = MainPage(browser)
|
||||
|
||||
# Проверяем наличие панели навигации
|
||||
mp.should_be_navigation_panel()
|
||||
|
||||
# Нажимаем на кнопку "Configuration" в главной панели навигации
|
||||
mp.click_main_navigation_panel_item("configuration")
|
||||
|
||||
# Нажимаем на страницу конфигурации
|
||||
cp = ConfigurationPage(browser)
|
||||
|
||||
# Нажимаем на вкладку "Users" в панели навигации конфигурации
|
||||
cp.click_configuration_navigation_panel_item("users")
|
||||
|
||||
# Работаем с вкладкой пользователей
|
||||
ut = UsersTab(browser)
|
||||
|
||||
# Удаляем пользователей в обратном порядке (от User8 до User1)
|
||||
for i in range(9, 0, -1):
|
||||
user_data = {
|
||||
"name": f"User{i}",
|
||||
"role": "Администратор",
|
||||
}
|
||||
ut.open_edit_user_page_by_name(user_data["name"], user_data["role"])
|
||||
ut.delete_user()
|
||||
|
||||
# Двойной клик по вкладке Users (возможно, для обновления списка)
|
||||
cp.click_configuration_navigation_panel_item("users")
|
||||
cp.click_configuration_navigation_panel_item("users")
|
||||
|
||||
# Проверяем отсутствие последнего удаленного пользователя в таблице
|
||||
ut.should_not_be_user_in_table(user_data["name"], user_data["role"])
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,334 @@
|
|||
import pytest
|
||||
from pages.login_page import LoginPage
|
||||
from pages.main_page import MainPage
|
||||
from pages.configuration_page import ConfigurationPage
|
||||
from pages.users_tab import UsersTab
|
||||
|
||||
class TestUsersTab:
|
||||
def test_users_tab_content(self, browser):
|
||||
lp = LoginPage(browser)
|
||||
lp.do_login()
|
||||
|
||||
# we are on main page
|
||||
mp = MainPage(browser)
|
||||
|
||||
# check navigation panel presence
|
||||
mp.should_be_navigation_panel()
|
||||
|
||||
# click to Configuration button in main navigation panel
|
||||
mp.click_main_navigation_panel_item("configuration")
|
||||
|
||||
# we are on configuration page
|
||||
cp = ConfigurationPage(browser)
|
||||
|
||||
# click to Users button in configuration navigation panel
|
||||
cp.click_configuration_navigation_panel_item("users")
|
||||
|
||||
# users tab has been opened
|
||||
ut = UsersTab(browser)
|
||||
|
||||
# check users work area
|
||||
ut.should_be_users_work_area()
|
||||
|
||||
def test_users_tab_toolbar_buttons(self, browser):
|
||||
lp = LoginPage(browser)
|
||||
lp.do_login()
|
||||
|
||||
# we are on main page
|
||||
mp = MainPage(browser)
|
||||
|
||||
# check navigation panel presence
|
||||
mp.should_be_navigation_panel()
|
||||
|
||||
# click to Configuration button in main navigation panel
|
||||
mp.click_main_navigation_panel_item("configuration")
|
||||
|
||||
# we are on configuration page
|
||||
cp = ConfigurationPage(browser)
|
||||
|
||||
# click to Users button in configuration navigation panel
|
||||
cp.click_configuration_navigation_panel_item("users")
|
||||
|
||||
# users tab has been opened
|
||||
ut = UsersTab(browser)
|
||||
|
||||
ut.should_be_users_page_toolbar_buttons()
|
||||
|
||||
def test_add_user_window_content(self, browser):
|
||||
lp = LoginPage(browser)
|
||||
lp.do_login()
|
||||
|
||||
# we are on main page
|
||||
mp = MainPage(browser)
|
||||
|
||||
# check navigation panel presence
|
||||
mp.should_be_navigation_panel()
|
||||
|
||||
# click to Configuration button in main navigation panel
|
||||
mp.click_main_navigation_panel_item("configuration")
|
||||
|
||||
# we are on configuration page
|
||||
cp = ConfigurationPage(browser)
|
||||
|
||||
# click to Users button in configuration navigation panel
|
||||
cp.click_configuration_navigation_panel_item("users")
|
||||
|
||||
# users tab has been opened
|
||||
ut = UsersTab(browser)
|
||||
|
||||
# open add new user page
|
||||
ut.open_add_user_page()
|
||||
|
||||
# check add user work area
|
||||
ut.should_be_add_user_work_area()
|
||||
|
||||
def test_edit_user_window_content(self, browser):
|
||||
lp = LoginPage(browser)
|
||||
lp.do_login()
|
||||
|
||||
# we are on main page
|
||||
mp = MainPage(browser)
|
||||
|
||||
# check navigation panel presence
|
||||
mp.should_be_navigation_panel()
|
||||
|
||||
# click to Configuration button in main navigation panel
|
||||
mp.click_main_navigation_panel_item("configuration")
|
||||
|
||||
# we are on configuration page
|
||||
cp = ConfigurationPage(browser)
|
||||
|
||||
# click to Users button in configuration navigation panel
|
||||
cp.click_configuration_navigation_panel_item("users")
|
||||
|
||||
# users tab has been opened
|
||||
ut = UsersTab(browser)
|
||||
|
||||
# open edit user page
|
||||
user_name, role = ut.open_edit_user_page_by_index(0)
|
||||
|
||||
# check edit user work area
|
||||
ut.should_be_edit_user_work_area(user_name, role)
|
||||
|
||||
def test_edit_user_window_close_buttons(self, browser):
|
||||
lp = LoginPage(browser)
|
||||
lp.do_login()
|
||||
|
||||
# we are on main page
|
||||
mp = MainPage(browser)
|
||||
|
||||
# check navigation panel presence
|
||||
mp.should_be_navigation_panel()
|
||||
|
||||
# click to Configuration button in main navigation panel
|
||||
mp.click_main_navigation_panel_item("configuration")
|
||||
|
||||
# we are on configuration page
|
||||
cp = ConfigurationPage(browser)
|
||||
|
||||
# click to Users button in configuration navigation panel
|
||||
cp.click_configuration_navigation_panel_item("users")
|
||||
|
||||
# users tab has been opened
|
||||
ut = UsersTab(browser)
|
||||
|
||||
# open edit user page
|
||||
user_name, role = ut.open_edit_user_page_by_index(0)
|
||||
ut.close_user_window_by_toolbar_button(user_name)
|
||||
|
||||
# open edit user page
|
||||
user_name, role = ut.open_edit_user_page_by_index(0)
|
||||
ut.close_user_window(user_name)
|
||||
|
||||
def test_add_and_delete_user(self, browser):
|
||||
user_data = {"name": "User", "role": "Администратор", "password": "admin"}
|
||||
|
||||
lp = LoginPage(browser)
|
||||
lp.do_login()
|
||||
|
||||
# we are on main page
|
||||
mp = MainPage(browser)
|
||||
|
||||
# check navigation panel presence
|
||||
mp.should_be_navigation_panel()
|
||||
|
||||
# click to Configuration button in main navigation panel
|
||||
mp.click_main_navigation_panel_item("configuration")
|
||||
|
||||
# we are on configuration page
|
||||
cp = ConfigurationPage(browser)
|
||||
|
||||
# click to Users button in configuration navigation panel
|
||||
cp.click_configuration_navigation_panel_item("users")
|
||||
|
||||
# users tab has been opened
|
||||
ut = UsersTab(browser)
|
||||
|
||||
# open add new user page
|
||||
ut.open_add_user_page()
|
||||
|
||||
# create new user
|
||||
ut.add_new_user(user_data)
|
||||
|
||||
# click to Users button in configuration navigation panel to update users list (two times is bug?)
|
||||
cp.click_configuration_navigation_panel_item("users")
|
||||
cp.click_configuration_navigation_panel_item("users")
|
||||
|
||||
# check that new user has been added
|
||||
ut.should_be_user_in_table(user_data["name"], user_data["role"])
|
||||
|
||||
# open edit user page and delete user
|
||||
ut.open_edit_user_page_by_name(user_data["name"], user_data["role"])
|
||||
ut.delete_user()
|
||||
|
||||
# click to Users button in configuration navigation panel to update users list (two times is bug?)
|
||||
cp.click_configuration_navigation_panel_item("users")
|
||||
cp.click_configuration_navigation_panel_item("users")
|
||||
|
||||
# check user abcense in users list
|
||||
ut.should_not_be_user_in_table(user_data["name"], user_data["role"])
|
||||
|
||||
def test_reset_password(self, browser):
|
||||
user_data = {"name": "autoadmin", "role": "Администратор", "password": "12345"}
|
||||
|
||||
lp = LoginPage(browser)
|
||||
lp.do_login()
|
||||
|
||||
# we are on main page
|
||||
mp = MainPage(browser)
|
||||
|
||||
# check navigation panel presence
|
||||
mp.should_be_navigation_panel()
|
||||
|
||||
# click to Configuration button in main navigation panel
|
||||
mp.click_main_navigation_panel_item("configuration")
|
||||
|
||||
# we are on configuration page
|
||||
cp = ConfigurationPage(browser)
|
||||
|
||||
# click to Users button in configuration navigation panel
|
||||
cp.click_configuration_navigation_panel_item("users")
|
||||
|
||||
# users tab has been opened
|
||||
ut = UsersTab(browser)
|
||||
|
||||
# open add new user page
|
||||
ut.open_add_user_page()
|
||||
|
||||
# create new user
|
||||
ut.add_new_user(user_data)
|
||||
|
||||
# click to Users button in configuration navigation panel to update users list (two times is bug?)
|
||||
cp.click_configuration_navigation_panel_item("users")
|
||||
cp.click_configuration_navigation_panel_item("users")
|
||||
|
||||
# check that new user has been added
|
||||
ut.should_be_user_in_table(user_data["name"], user_data["role"])
|
||||
|
||||
# open edit user page
|
||||
ut.open_edit_user_page_by_name(user_data["name"], user_data["role"])
|
||||
|
||||
new_password = ut.reset_password()
|
||||
|
||||
if len(new_password) == 0: assert False, "Unsuccessful password reset"
|
||||
|
||||
new_lp = LoginPage(browser)
|
||||
new_lp.do_login(username=user_data["name"], password=new_password)
|
||||
|
||||
# we are on main page
|
||||
new_mp = MainPage(browser)
|
||||
|
||||
# do logout
|
||||
new_mp.do_logout()
|
||||
|
||||
lp_1 = LoginPage(browser)
|
||||
lp_1.do_login()
|
||||
|
||||
# we are on main page
|
||||
mp_1 = MainPage(browser)
|
||||
|
||||
# click to Configuration button in main navigation panel
|
||||
mp_1.click_main_navigation_panel_item("configuration")
|
||||
|
||||
# we are on configuration page
|
||||
cp_1 = ConfigurationPage(browser)
|
||||
|
||||
# click to Users button in configuration navigation panel
|
||||
cp_1.click_configuration_navigation_panel_item("users")
|
||||
|
||||
# users tab has been opened
|
||||
ut_1 = UsersTab(browser)
|
||||
|
||||
# open edit user page and delete user
|
||||
ut_1.open_edit_user_page_by_name(user_data["name"], user_data["role"])
|
||||
ut_1.delete_user()
|
||||
|
||||
# click to Users button in configuration navigation panel to update users list (two times is bug?)
|
||||
cp_1.click_configuration_navigation_panel_item("users")
|
||||
cp_1.click_configuration_navigation_panel_item("users")
|
||||
|
||||
# check user abcense in users list
|
||||
ut_1.should_not_be_user_in_table(user_data["name"], user_data["role"])
|
||||
|
||||
def test_edit_user_role(self, browser):
|
||||
user_data = {"name": "autooperator", "role": "Оператор", "password": "auto123@"}
|
||||
|
||||
lp = LoginPage(browser)
|
||||
lp.do_login()
|
||||
|
||||
# we are on main page
|
||||
mp = MainPage(browser)
|
||||
|
||||
# check navigation panel presence
|
||||
mp.should_be_navigation_panel()
|
||||
|
||||
# click to Configuration button in main navigation panel
|
||||
mp.click_main_navigation_panel_item("configuration")
|
||||
|
||||
# we are on configuration page
|
||||
cp = ConfigurationPage(browser)
|
||||
|
||||
# click to Users button in configuration navigation panel
|
||||
cp.click_configuration_navigation_panel_item("users")
|
||||
|
||||
# users tab has been opened
|
||||
ut = UsersTab(browser)
|
||||
|
||||
# open add new user page
|
||||
ut.open_add_user_page()
|
||||
|
||||
# create new user
|
||||
ut.add_new_user(user_data)
|
||||
|
||||
# click to Users button in configuration navigation panel to update users list (two times is bug?)
|
||||
cp.click_configuration_navigation_panel_item("users")
|
||||
cp.click_configuration_navigation_panel_item("users")
|
||||
|
||||
# check that new user has been added
|
||||
ut.should_be_user_in_table(user_data["name"], user_data["role"])
|
||||
|
||||
# open edit user page and delete user
|
||||
ut.open_edit_user_page_by_name(user_data["name"], user_data["role"])
|
||||
|
||||
new_user_data = {}
|
||||
new_user_data["role"] = "Контактное лицо"
|
||||
ut.edit_user(new_user_data)
|
||||
|
||||
# click to Users button in configuration navigation panel to update users list (two times is bug?)
|
||||
cp.click_configuration_navigation_panel_item("users")
|
||||
cp.click_configuration_navigation_panel_item("users")
|
||||
|
||||
# check that new user has been added
|
||||
ut.should_be_user_in_table(user_data["name"], new_user_data["role"])
|
||||
|
||||
# open edit user page and delete user
|
||||
ut.open_edit_user_page_by_name(user_data["name"], new_user_data["role"])
|
||||
ut.delete_user()
|
||||
|
||||
# click to Users button in configuration navigation panel to update users list (two times is bug?)
|
||||
cp.click_configuration_navigation_panel_item("users")
|
||||
cp.click_configuration_navigation_panel_item("users")
|
||||
|
||||
# check user abcense in users list
|
||||
ut.should_not_be_user_in_table(user_data["name"], new_user_data["role"])
|
||||
|
||||
Loading…
Reference in New Issue