e-nms_qa_automation/pages/service_status_tab.py

347 lines
14 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

"""Модуль вкладки 'Статус обслуживания'.
Содержит класс ServiceStatusTab для работы с таблицей сервисов.
Позволяет проверять состояние и взаимодействовать с элементами вкладки.
"""
import math
from playwright.sync_api import Page, Locator, expect
from elements.text_element import Text
from elements.button_element import Button
from components.table_component import TableComponent
from components.expand_button_component import ExpandButton
from pages.base_page import BasePage
class ServiceStatusTab(BasePage):
"""Класс для работы с вкладкой 'Статус обслуживания'.
Предоставляет методы для взаимодействия с таблицей сервисов и проверки
её состояния.
Args:
page: Экземпляр страницы Playwright.
"""
def __init__(self, page: Page) -> None:
"""Инициализирует компоненты вкладки 'Статус обслуживания'."""
super().__init__(page)
self.iframe_container_locator = page.locator("div.container.iframe-wrapper")
self.iframe_locator = page.frame_locator("//iframe[@class='iframe-class']")
self.table_locator = self.iframe_locator.locator("div.MuiBox-root > div > table")
self.tab_title_locator = self.iframe_locator.locator("//h5[text()='Состояние контейнеров']")
self.update_button_locator = self.iframe_locator.get_by_role("button", name='Обновить')
self.analyzer_open_button_locator = self.iframe_locator.get_by_role("button", name='открыть анализатор')
self.tab_title = Text(page,
self.tab_title_locator,
"tab_title")
self.update_button = Button(page,
self.update_button_locator,
"update_button")
self.analyzer_open_button = Button(page,
self.analyzer_open_button_locator,
"analyzer_open_button")
self.expand_work_area_button = ExpandButton(page)
self.services_table = TableComponent(page)
# Действия:
def calculate_coordinates(self, locator: Locator) -> dict:
"""Вычисление координат элемента для манипуляции с ним мышкой"""
coordinates = {}
offsets_scales = self.get_offsets_scales()
bounding_box = locator.evaluate("el => el.getBoundingClientRect()")
assert bounding_box, "Required element is not visible"
offset_x = offsets_scales["offset_x"]
offset_y = offsets_scales["offset_y"]
scale_x = offsets_scales["scale_x"]
scale_y = offsets_scales["scale_y"]
coordinates["center_x"] = (bounding_box["x"] + bounding_box["width"] / 2) * scale_x + offset_x
coordinates["center_y"] = (bounding_box["y"] + bounding_box["height"] / 2) * scale_y + offset_y
return coordinates
def get_offsets_scales(self) -> dict:
"""Возвращает словарь, содержащий смещения контейнера фрейма и его коэффициенты"""
offsets_scales = {}
iframe_container_bounding_box = self.iframe_container_locator.\
evaluate("el => el.getBoundingClientRect()")
assert iframe_container_bounding_box, "Iframe container is not visible"
iframe_bounding_box = self.iframe_locator.locator("div#root > div"). \
evaluate("el => el.getBoundingClientRect()")
assert iframe_bounding_box, "Iframe content is not visible"
offsets_scales["offset_x"] = iframe_container_bounding_box["x"]
offsets_scales["offset_y"] = iframe_container_bounding_box["y"]
offsets_scales["scale_x"] = iframe_container_bounding_box["width"]/iframe_bounding_box["width"]
offsets_scales["scale_y"] = iframe_container_bounding_box["height"]/iframe_bounding_box["height"]
return offsets_scales
def datetime2timestamp(self, date_column: str) -> list[float]:
""" Конвертация строкового представления даты и времени в Unix timestamp
"""
converted = []
for date in date_column:
timestamp = self.services_table.datetime2timestamp(date,format_string="%d-%m-%y %H:%M:%S")
assert timestamp, f"Error conversation to timestamp for {date}"
converted.append(timestamp)
return converted
def click_update_button(self) -> None:
"""Нажатие кнопки 'Обновить'"""
coordinates = self.calculate_coordinates(self.update_button_locator)
self.page.mouse.click(math.ceil(coordinates["center_x"]),
math.ceil(coordinates["center_y"]), delay=300)
def get_column(self, index: int) -> list[str]:
"""Возвращает столбец таблицы по индексу.
Returns:
list[str]: Столбец таблицы по индексу.
Raises:
AssertionError: Если таблица пуста или столбца с таким индексом в таблице нет.
"""
return self.services_table.get_column(self.table_locator, index)
def get_rows_count(self) -> int:
"""Возвращает количество строк в таблице (без заголовка).
Returns:
int: Количество строк с данными.
Raises:
AssertionError: Если таблица пуста.
"""
return self.services_table.get_rows_count(self.table_locator)
def expand_tab(self) -> None:
"""Расширяет рабочую область складки."""
iframe_container_bounding_box = self.iframe_container_locator.\
evaluate("el => el.getBoundingClientRect()")
widht_before = iframe_container_bounding_box["width"]
self.expand_work_area_button.expand()
iframe_container_bounding_box = self.iframe_container_locator.\
evaluate("el => el.getBoundingClientRect()")
widht_after = iframe_container_bounding_box["width"]
assert widht_before < widht_after,"Services statuses tab should be expanded"
def reduce_tab(self) -> None:
"""Сжимает рабочую область складки."""
iframe_container_bounding_box = self.iframe_container_locator.\
evaluate("el => el.getBoundingClientRect()")
widht_before = iframe_container_bounding_box["width"]
self.expand_work_area_button.reduce()
iframe_container_bounding_box = self.iframe_container_locator.\
evaluate("el => el.getBoundingClientRect()")
widht_after = iframe_container_bounding_box["width"]
assert widht_before > widht_after,"Services statuses tab should be reduced"
def scroll_services_tab_up(self) -> None:
"""Прокручивает содержимое вкладки вверх."""
self.tab_title_locator.scroll_into_view_if_needed()
def scroll_services_tab_down(self) -> None:
"""Прокручивает содержимое вкладки вниз."""
nrows = self.get_rows_count()
last_row = self.services_table.get_row_locator(self.table_locator, nrows-1)
last_row.scroll_into_view_if_needed()
# Проверки:
def check_services_table_content(self) -> None:
"""Проверяет содержимое таблицы сервисов.
Проверяет заголовки и наличие данных в таблице.
Raises:
AssertionError: Если таблица пуста или заголовки неверны.
"""
expected_headers = [
'СТЕК',
'КОНТЕЙНЕР',
'ТЭГ',
'СТАТУС',
'ВРЕМЯ СОЗДАНИЯ',
'ЦЕЛОСТНОСТЬ',
'ДЕЙСТВИЯ'
]
self.services_table.check_content(self.table_locator, expected_headers)
# Проверяем наличие кнопок и тултипов в последней ячейке строки
rows_count = self.services_table.get_rows_count(self.table_locator)
for i in range(rows_count):
row_locator = self.services_table.get_row_locator(self.table_locator, i)
layers_button = row_locator.get_by_role("button", name="Слои")
expect(layers_button).to_be_visible(), f"Layers button is missing in {i} row"
self.check_tooltip(layers_button, "Слои")
lounch_button = row_locator.get_by_role("button", name="Запуск", exact=True)
expect(lounch_button).to_be_visible(), f"Lounch button is missing in {i} row"
self.check_tooltip(lounch_button, "Запуск")
stop_button = row_locator.get_by_role("button", name="Остановка")
expect(stop_button).to_be_visible(), f"Stop button is missing in {i} row"
self.check_tooltip(stop_button, "Остановка")
restart_button = row_locator.get_by_role("button", name="Перезапуск", exact=True)
expect(restart_button).to_be_visible(), f"Restart button is missing in {i} row"
self.check_tooltip(restart_button, "Перезапуск")
def check_tooltip(self, button_locator: Locator, expected_text: str) -> None:
"""Проверка текста тултипа кнопки в последней ячейке строки"""
# Наведение на элемент для отображения подсказки
coordinates = self.calculate_coordinates(button_locator)
self.page.mouse.move(math.ceil(coordinates["center_x"]),
math.ceil(coordinates["center_y"]), steps=3)
# Получение элемента подсказки и ее текста
tooltip = self.iframe_locator.get_by_role("tooltip").locator("div.MuiTooltip-tooltip").first
tooltip.wait_for(state="visible", timeout=5000)
actual_text = tooltip.text_content().strip()
assert expected_text==actual_text, f"Should be tooltip with text: {expected_text}, got: {actual_text}"
def check_services_table_verticall_scrolling(self) -> bool:
"""Проверяет возможность вертикальной прокрутки таблицы.
Returns:
bool: True если прокрутка возможна, иначе False.
"""
loc = self.iframe_locator.locator("div.MuiBox-root > div > div").first
return loc.evaluate("el => el.scrollHeight > el.clientHeight")
def check_services_tab_title_visibility(self) -> None:
"""Проверяет видимость заголовка вкладки.
Raises:
AssertionError: Если строка не видна.
"""
self.tab_title.check_visibility("The services tab title is not visible")
# def check_services_table_first_row_visibility(self) -> None:
# """Проверяет видимость первой строки таблицы.
# Raises:
# AssertionError: Если строка не видна.
# """
# self.services_table.check_first_row_visibility(self.table_locator)
def check_services_table_last_row_visibility(self) -> None:
"""Проверяет видимость последней строки таблицы.
Raises:
AssertionError: Если строка не видна.
"""
self.services_table.check_last_row_visibility(self.table_locator)
def check_services_table_row_highlighting(self, row_index: int) -> None:
"""Проверяет выделение указанной строки таблицы.
Args:
row_index: Индекс проверяемой строки.
Raises:
AssertionError: Если строка не выделена.
"""
offsets_scales = self.get_offsets_scales()
self.services_table.check_mui_table_row_highlighting(
self.table_locator,
row_index,
offsets_scales["offset_x"],
offsets_scales["offset_y"],
offsets_scales["scale_x"],
offsets_scales["scale_y"]
)
def should_be_tab_title(self) -> None:
"""Проверяет наличие заголовка вкладки.
Raises:
AssertionError: Если заголовок отсутствует.
"""
self.tab_title.check_visibility(
"Title of service statuses tab is missing"
)
def should_be_services_table(self) -> None:
"""Проверяет наличие таблицы сервисов.
Raises:
AssertionError: Если таблица отсутствует.
"""
self.services_table.check_visibility(
self.table_locator,
"Service statuses table is missing"
)
def should_be_analyzer_open_button(self) -> None:
"""Проверяет наличие кнопки 'navigate_before/navigate_next'.
Raises:
AssertionError: Если кнопка отсутствует.
"""
self.analyzer_open_button.check_visibility(
"Analyzer open button on bottom of service statuses tab is missing"
)
def should_be_expand_work_area_button(self) -> None:
"""Проверяет наличие кнопки расширения/сжатия рабочей области вкладки.
Raises:
AssertionError: Если кнопка отсутствует.
"""
self.expand_work_area_button.should_be_button()
def should_be_update_button(self) -> None:
"""Проверяет наличие кнопки 'Обновить'.
Raises:
AssertionError: Если кнопка отсутствует.
"""
self.update_button.check_visibility(
"Update button on top of service statuses tab is missing"
)