Як перестати боятись і почати автоматизувати з Playwright

Усі статті, обговорення, новини про тестування — в одному місці. Підписуйтеся на QA DOU!

Привіт друзі! Це Олексій Остапов з QA Mania! Минулого року я опублікував цілий курс «Автоматизація тестування з Playwright мовою Python». Курс не втратив актуальності, тож хто хоче почати, але не знає з чого — вперед!

Якщо ви не впевнені щодо Python — спробуйте інші мови програмування. На щастя, Playwright підтримує різні. Я пишу програми та автоматизую на Python — бо він мені банально подобається. Так, в нього є мінуси (як і в кожної мови), так само як і плюси. Але головне — мені просто приємно писати на Python❤️. Я отримую задоволення і вважаю, що чи не найголовніше в будь-якій роботі — отримувати задоволення від того, що робиш.

Я абсолютно впевнений, що Playwright — об’єктивно найкраще, що могло статись з автоматизацією web-тестування. Він — швидкий, точний, надійний і приємний в користуванні. А ще — активно оновлюється, баги фіксяться, спільнота — росте.

Давайте я облишу роздуми про плюси та мінуси автоматизації тестування на наступні статті, а зараз сфокусуємось на тому, що ж такого крутого може запропонувати вам Playwright. Тримайте мій особистий топ 5:

1. Можливість працювати з мережевими запитами браузера

Об’єктивно, це не найкрутіша фіча інструменту, але саме вона 2 роки тому «продала» мені Playwright, коли він ще навіть у бета-тестуванні не був (перший білд, що я тоді скачав — навіть не запустився). Тільки уявіть собі — автотест відкриває сайт, робить в ньому якусь дію, що викликає, наприклад, ajax-запит. І ви можете цей запит перехопити, проаналізувати, замінити, змінити відповідь! Який простір для тестування!

Раніше, щоб перевірити негативний тест, коли умовний бекенд повертає 400 чи 500 помилку, треба було сильно постаратись, підняти мок-сервер. Про автоматизацію такого сценарію не могло бути й мови. А зараз — це лише кілька рядків коду. Ба більше — якщо ви захочете відправити додатковий http-запит — просто зробіть відповідний виклик одразу в Playwright! Не має потреби у вашому коді створювати окремий http-клієнт, «костилями» передавати йому авторизаційні токени — інструмент змусить браузер відправити необхідний запит від імені тої ж браузерної сесії

# response fulfill
page.route("**/*", lambda route: route.fulfill(
   status=404,
   content_type="text/plain",
   body="not found!"))
page.click(".donetworkAction")

# send request
response = page.request.get("/response")
expect(response).to_be_ok()

Відео: як перехопити мережевий запит? Як відправити мережевий запит?

2. Селектори — прості і геніальні

Раніше я несвідомо мріяв про щось подібне, але навіть не міг чітко сформулювати, що ж не так з локалізацією складних елементів на вебсторінці. Розробники Playwright зробили все за мене і змусили полюбити пошук елементів. Окрім стандартного пошуку за xpath, css, id, та текстом на екрані, розробники:

  1. додали купу css псевдокласів, щоб зробити пошук зручнішим;
  2. зробили можливість будувати ланцюжки селекторів, змішуючи їх одне з одним. Хочете використати одразу xpath та css? Будь ласка;
  3. зробили можливість в ланцюжку селекторів обрати не фінальний елемент, а будь-який посередині. Раніше я в xpath використовував щось монструозне типу parent. Зараз достатньо поставити зірочку;
  4. зробили можливість знайти елемент за кількома можливими селекторами! Кнопка змінює клас чи текст? Ха! Перелічіть всі можливі, хоча б по одному, ми її вирахуємо;
  5. розробники сховали елементи в iframe? Не біда — вони підтримуються так само легко, як і контексти та вкладки браузера!
# pseudo class :has finds element which has elements
page.locator('tbody tr:has(.delete_1) .passBtn').click()

# selectors chain. * selects element in the middle
page.locator('xpath=//table >> *css=tr >> text="login"').click()

# Clicks a <button> that has either a "Log in" or "Sign in" text.
page.locator('button:has-text("Log in"), button:has-text("Sign in")').click()

# Locate element inside frame
# Get frame using any other selector
username = page.frame_locator('.frame-class').get_by_label('User Name')
username.fill('John')

Відео: Селектори, метод locator()

3. Робота з контекстом браузера

Раніше, якщо при кліку на посилання відкривалась друга вкладка браузера, це могло стати справжньою проблемою для автотестера. А якщо треба було провести тест з кількома різними користувачами, я часто відмовлявся від автоматизації таких тестів. Зараз же я можу створити скільки завгодно ізольованих контекстів браузера, одночасно, в кожному створити вкладку, авторизуватись різними користувачами та робити дії паралельно! Відкрилось більше вкладок — отримав їх список і можу дати команди кожній з них.

context1 = chromium.new_context()
page1 = context1.new_page()
page1.fill('#username', 'alice')
page1.fill('#password', 'alice')
page1.click('text="Login"')
context2 = chromium.new_context()
page2 = context1.new_page()
page2.fill('#username', 'bob')
page2.fill('#password', 'bob')
page2.click('text="Login"')
page1.click(".button")
page2.click(".button")

Відео: робота з контекстом

4. Відсутність очікувань

Як приємно описувати кодом, що ти хочеш від браузера, і він саме це робить. Коли не треба на кожному кроці писати перевірки на ElementNotFoundException, бо ви вирішили пошукати елемент за селектором на пів секунди раніше, ніж він з’явився в DOM’і сторінки. Зараз я просто вказую селектор, і як тільки він буде знайдений, тест спробує провести з ним необхідні операції. І лише якщо елемент не буде знайдено протягом 30 секунд стандартного очікування (що можна змінити одним рядком коду), лише тоді тест «впаде» і скаже, що щось пішло не так.

5. Headless режим з коробки

Раніше автоматизація була для мене візуальним процесом — запускався драйвер браузера, я шукав в ньому елементи і прописував взаємодію з ними в коді. Тому я був дуже здивований, що Playwright за замовчанням — headless. Зараз я намічаю селектори заздалегідь і просто пишу код. Кількість ситуацій, коли мені потрібно включити UI і подивитись, чому тест не проходить та якого біса він там не може знайти — звелась до мінімуму.

Додатково не можу не написати про асинхронний режим роботи Playwright. В 99% випадків він буде вам не потрібний, бо типові тести — синхронні. Коду треба писати менше і сам він читабельніший. Але був в мої практиці випадок, коли треба було зробити тестування навантаження справжніми браузерами, і тут це стало в пригоді! Ідея все ще погана, не робіть так ніколи. Але можливість це зробити — просто супер.

Посилання на статтю та відео — Найбожевільніше тестування навантаження.

Всі круті приклади — зібрані на Github тут.

Такий от мій топ! Напишіть, що вас зацікавило настільки, щоб вже спробувати завантажити та запустити Playwright. А якщо ви вже користуєтесь, то який топ 5 у вас?

👍ПодобаєтьсяСподобалось19
До обраногоВ обраному2
LinkedIn
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter

Крутяк! Дякую за статю і ютубчик)

Привіт, цікава і легка для читання стаття) А де можна знайти курс?

Так як перестати боятись? :) Я думав, що прочитаю якісь рекомендації по написанню перших тестів, найочевидніших сценаріїв, або приклади як же виглядає продакшн-тест.

я робив фокус на playwright — який вій простий і кльовий. а рекомендації по написанню тестів типові і прості:
«пишіть гарний код, не пишіть поганий код» 😁

Думаю, можна було б змінити назву статті на «Чому у 2023 вже не круто обирати Selenium як основний фреймоврк для автоматизації UI. Тестуємо з Plywright». І клікбейтно :) і більше передає суть.

Кто-то знает способ, как можно плейрайтом отменять запросы, которые не были плерайтом же и перехвачены? Условно 9 запросов замокали, 10-ый провтыкали. Чтобы точно 10-ый запрос не пошел дальше.

1. перехоплювати URL запиту через regex, якщо є хитрі варіанти
2. писати команду на перехоплення через метод .on(), що перехоплювати всі запити, а не лише наступний

1. Не очень понимаю, чем тут regex поможет. Исключать в нем перехваченные запросы?
2. Имеете ввиду playwright.dev/...​s-page#page-event-request ? В нем нельзя обрабатывать запросы.

точно, переплутав, там route()
тим не менше, не розумію, в чому проблема 10й запит перехопити та заблокувати?

Поясніть, що значить ’не буде потрібен асинхронний режим’?
Я навіть трохи перелякавсь)
Зайшов подивитись на API даного фреймворку.
Бачу, що скрізь запропонований асинхронний код.

Також цікаво, чим даний фреймворк кращий за webdriverio?
Може хтось працював з обома і може поділитись думками.

для пайтону є 2 види апі — синхронні та асинхронні.
і здебільшого всі вибирають синхронні, щоб не писати в кожній строці async і в кожному методі await. Та і тести у 90% тестерів — синхронні.

колись хотів

webdriverio

опанувати, але він тільки JS.
наскільки бачу з доки — він не вміє в кіллер фічу — перехоплення запитів ¯\_(ツ)_/¯

Підписатись на коментарі