211

     # UI | 09 | Playwright: рефакторинг кода, оптимизация работы с локаторами

Сказанное в предыдущей статье в какой-то мере относится и к локаторам.

Да, в случае необходимости повторного обращения нами использовался трюк в виде записи локатора в переменную, но всё равно не так удобно читать код построчно, пытаясь понять, что это за элемент и за что он отвечает.

# открытие меню
main_menu = page.locator('//li[4]//img')
main_menu.click()
...
# закрытие меню
main_menu.click()

Для повторного использования того же локатора нам придётся:

  • либо бегать по коду и искать, создавался ли он ранее
  • либо повторно создавать тот же самый, забыв или не заметив, что он уже имеется.
page.locator("#ul_mainmenu div").get_by_role("img").click()

Отсюда вытекает проблема:

  • если на какой-то html-странице по каким-либо причинам изменится локатор, нам придётся искать его повсюда в коде и тоже повсеместно менять.

Более того:

  • мы могли в одном случае создать его через xpath
  • в другом - через css
  • в третьем - с использованием внутренних методов Plawright

Что не позволит нам легко обнаружить его с помощью простого текстового поиска.

Именно поэтому при рефакторинге мы обратим внимание также и на локаторы, переместив их "в отдельное место".

import random

from playwright.sync_api import sync_playwright, expect

def on_error(func):
    def wrapper(name):
        try:
            func(name)
            print(f"{name}: Тест-кейс успешно выполнен")
        except Exception as exc:
            print(f"{name}: Тест-кейс упал")
            print(f"{name}: {exc.with_traceback}")
            page.screenshot(path=f"{name}.png")

    return wrapper

@on_error
def launch_smoke_1(name):
    print(f"\n{name}: старт")

    print("[DO] Проверка главного меню")
    expect(top_menu_children).to_be_attached(timeout=local_timeout)
    print("[OK] Проверка главного меню")

    print("[DO] Проверка элементов главного меню")
    expect(top_menu_options).to_have_count(4)
    print("[OK] Проверка элементов главного меню")

    print("[DO] Проверка видимости элементов главного меню")
    for elem in top_menu_options_as_list:
        expect(elem).to_be_visible()
    print("[OK] Проверка видимости элементов главного меню")

@on_error
def launch_smoke_2(name):
    print(f"\n{name}: старт")

    print("[DO] Открытие меню статей")
    top_menu_articles.click()
    print("[OK] Открытие меню статей")

    print("[DO] Проверка верхнеуровневых статей")
    # кол-во верхнеуровневых статей
    assert top_menu_articles_chapters.count() >= 5
    print("[OK] Проверка верхнеуровневых статей")

    print("[DO] Проверка видимости первой статьи")
    # проверка на видимость кнопки первой статьи
    expect(top_menu_articles_chapters.first).to_be_visible()
    print("[OK] Проверка видимости первой статьи")

    print("[DO] Закрытие меню статей")
    top_menu_articles.click()
    print("[OK] Закрытие меню статей")

    print("[DO] Проверка закрытия статей")
    # проверка, что меню больше не видно
    expect(top_menu_articles_chapters.first).not_to_be_visible()
    print("[OK] Проверка закрытия статей")

@on_error
def launch_smoke_3(name):
    print(f"\n{name}: старт")

    print("[DO] Проверка надписи")
    # Проверка надписи
    expect(body_title).to_be_visible()
    print("[OK] Проверка надписи")

    print("[DO] Проверка количества статей")
    # Проверка количества статей
    expect(body_all_articles).to_have_count(10)
    print("[OK] Проверка количества статей")

    print("[DO] Проверка количества кнопок")
    # Проверка количества кнопок
    expect(body_all_articles_btn_open).to_have_count(10)
    print("[OK] Проверка количества кнопок")

    # функция, проверяющая, что html-элемент в списке не пустой
    def check_element_not_empty(elem_list_to_check):
        for elem in elem_list_to_check:
            expect(elem).not_to_be_empty()
            print(f"{elem} не пустой")

    # получаем объекты всех категорий в виде списка
    print("[DO] Проверка, что элементы не пусты")
    # обходим список и проверяем, что элемент не пустой
    check_element_not_empty(body_all_articles_title_list)
    check_element_not_empty(body_all_articles_description_list)
    check_element_not_empty(body_all_articles_date_list)
    check_element_not_empty(body_all_articles_view_list)
    check_element_not_empty(body_all_articles_like_list)
    print("[OK] Проверка, что элементы не пусты")

@on_error
def launch_smoke_4(name):
    print(f"\n{name}: старт")

    print("[DO] Проверка количества кнопок")
    expect(footer_btn_children).to_have_count(4)
    print("[OK] Проверка количества кнопок")

    # Проверка цвета кнопок
    print("[DO] Проверка цвета кнопок")

    assert "background: lightgray" in footer_btn_prev_page.get_attribute("style")
    print("[OK] Кнопка previous_page")
    assert "background: lightgray" in footer_btn_prev_pages.get_attribute("style")
    print("[OK] Кнопка previous_pages")
    assert "background: #315d6a" in footer_btn_next_page.get_attribute("style")
    print("[OK] Кнопка next_page")

    print("[DO] Проверка значения поля")
    # Значение по умолчанию = 1
    expect(footer_btn_pagination_field).to_have_attribute("value", "1")
    print("[OK] Проверка значения поля")

    print("[DO] Проверка редактируемости поля")
    # поле редактируемое
    expect(footer_btn_pagination_field).to_be_editable()
    print("[OK] Проверка редактируемости поля")

@on_error
def launch_smoke_5(name):
    print(f"\n{name}: старт")

    print("[DO] Проверка недопустимого минимального значения")

    footer_btn_pagination_field.scroll_into_view_if_needed()
    footer_btn_pagination_field.fill("0")
    assert "background: red" in footer_btn_pagination_field.get_attribute("style")
    print("[OK] Проверка недопустимого минимального значения")

    print("[DO] Проверка недопустимого пустого значения")
    footer_btn_pagination_field.clear()
    assert "background: red" in footer_btn_pagination_field.get_attribute("style")
    print("[OK] Проверка недопустимого пустого значения")

    print("[DO] Проверка ввода букв")
    footer_btn_pagination_field.fill("1abc")
    assert "background: red" in footer_btn_pagination_field.get_attribute("style")
    print("[OK] Проверка ввода букв")

    print("[DO] Проверка ввода символов")
    footer_btn_pagination_field.fill("#")
    assert "background: red" in footer_btn_pagination_field.get_attribute("style")
    print("[OK] Проверка ввода символов")

    # получение максимального значения

    print("[DO] Проверка допустимого макс. значения")
    # проверка корректного ввода
    allowed_random_data = random.randint(1, footer_btn_pagination_field_max_value)
    footer_btn_pagination_field.fill(str(allowed_random_data))
    assert "background: lightgreen" in footer_btn_pagination_field.get_attribute("style")
    print("[OK] Проверка допустимого макс. значения")

    print("[DO] Проверка недопустимого макс. значения")
    # проверка недопустимого максимального значения
    footer_btn_pagination_field.fill(str(footer_btn_pagination_field_max_value+1))
    assert "background: red" in footer_btn_pagination_field.get_attribute("style")
    print("[OK] Проверка недопустимого макс. значения")


playwright = sync_playwright().start()

browser = playwright.chromium.launch(headless=False)
page = browser.new_page()

#do_the_test()
page.goto("https://g-oak.ru")

local_timeout = 5000

# Test 1
top_menu_children = page.locator("#ul_mainmenu")
top_menu_options = page.locator("#ul_mainmenu li")
top_menu_options_as_list = top_menu_options.all()
top_menu_articles = page.locator("#ul_mainmenu div").get_by_role("img")
top_menu_articles_chapters = page.locator('//btn[text()="# > "]')

# Test 2
body_title = page.get_by_role("heading", name="Что новенького")
body_all_articles = page.locator('//li[@class="article_entry"]')
body_all_articles_btn_open = page.locator('//label[text()="Читать полностью"]')

# Test 3
body_all_articles_title_list = page.locator("//label[@id='index_title']").all()
body_all_articles_description_list = page.locator("//p[@class='annonce']").all()
body_all_articles_date_list = page.locator("//div[2]/label").all()
body_all_articles_view_list = page.locator('//strong[text()="Просмотры"]/../following-sibling::*').all()
body_all_articles_like_list = page.locator('//strong[text()="Лайки"]/../following-sibling::*').all()

# Tests 4, 5
footer_btn_children = page.locator('//*[@id="index_footer"]//td//strong')
footer_btn_prev_page = page.locator("#previous_page")
footer_btn_prev_pages = page.locator("#previous_pages")
footer_btn_next_page = page.locator("#next_page")
footer_btn_pagination_field = page.locator("#current_page")
footer_btn_pagination_field_max_value = int(page.locator('//label[@id="max_page"]').inner_text().replace("/", "").strip())

launch_smoke_1("тест 1")
launch_smoke_2("тест 2")
launch_smoke_3("тест 3")
launch_smoke_4("тест 4")
launch_smoke_5("тест 5")

browser.close()
playwright.stop()