Заморочки Playwright — waitForResponse

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

В фреймворку Playwright є зручна фіча «очікування» на Респонс від реквеста

waitForResponse — playwright.dev/...​ge#page-wait-for-response

Яка може допомогти в тих випадках, коли явних змін на WEB UI нема, а треба зробити перевірку що дійсно реквест пішов, сутність створилась успішно і замість того, щоб:

  • відкривати сторінку з тою сутністю та писати перевірки що всі дані вірні
  • або безпосередньо «дьоргати» певний ендпоінт та перевірити його поля

Можна реалізувати таке очікування, беремо з документації приклад:

1. Оголошуємо певне очікування, відповідно стартуємо очікування, робимо дію, потім чекаємо на респонс:

const responsePromise = page.waitForResponse('https://example.com/resource');
await page.getByText('trigger response').click();
const response = await responsePromise;

2. Оголошуємо предикат з очікуванням, робимо дію та «отримуємо» результат очікування

const responsePromise = page.waitForResponse(response =>
    response.url() === 'https://example.com' && response.status() === 200
    && response.request().method() === 'GET'
);
await page.getByText('trigger response').click();
const response = await responsePromise;
І нібито нам проміс, в цьому випадку, нам дає перевагу над іншим не асинхронними мовами

Юридично логіка яка описана вона є правильна та логічно коректна.
Спершу оголошуємо, що треба почекати коли буде респонс від бекенду, але ми не блокуємо виконання наступних дій
Далі ми робимо безпосередньо дію, але чекаємо коли вона виконається, браузер безпосередньо дає відповідь Playwright, що дія виконана, івент завершено, згрубше
І лише потім ми «отримуємо» результат очікування від асинхронного очікування яке ми оголосили браузеру.

Але тут є інший момент. Ваш бекенд не дає відповідь на фронтенд за 1 мілісекунду, дай бог дасть відповідь за 100 мілісекунд, звісно якщо ми не говоримо про gRPC, WebSocket.

Постає питання: А скільки часу проходить між завершенням промісу та «запуском» нового промісу
Відповідь: мікросекунди, це час JS івентлупа на опрацювання черги мікротасок

Тому можна ось так писати і буде компактніше, простіше:

await page.getByTestId('submit-button').click(); 
await page.waitForResponse('**/api/users');

Ви дуже малоймовірно отримаєте такий race condition коли клік, або філ буде стільки часу тримати проміс, що очікування на респонс буде марним.

Тому можете спробувати в вас на проєкті так само писати «синхронний» код, в мене працює і вас спрацює.

А для скептиків, я підготував приклад репозиторію з емуляцією такої поведінки на localhost коли в вас просто все локально ганяється і все успішно проходить.

github.com/...​l_service_for_experiments

Але звісно можуть бути всякі ситуації, які залежать від реалізації вашого фронтенда

👍ПодобаєтьсяСподобалось7
До обраногоВ обраному1
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

Стосовно рейс кондішена і переходу на синхронний код, щоб я на всіх TS + Playwright проектах роблю так:
const [response] = await Promise.all([
this.page.waitForResponse(...),
this.page.locator(...).click()
])

Жодного разу тест не впав, через те що була проблема з рейс кондішн :)

Хм, цікавий варіант використання
Не люблю я канєшно проміс ол, хочеться це все приховати /обгорнути

Ви дуже малоймовірно отримаєте такий race condition коли клік, або філ буде стільки часу тримати проміс, що очікування на респонс буде марним.

Your chances of getting killed by cow are low, but never zero.

Краще не закладати навіть теоретичної можливості отримати рейс кондішн, і спати спокійно. Бо це може дріфтанути боком в самий несподіваний момент, і якийсь джун який не сильно розібрався в промісах витратить весь день на дебаг.

Різниця в написанні незначна, а якщо вже сильно муляє можна зробили якийсь хелперок-враперок шось типу

await expect(page.locator(’button’)).toReceiveResponseWhenClicked(’**/api/users’)

Ось код з прикладом коли запропонований в статті варіант не спрацює (якщо клік ініціює навігацію):

github.com/...​ce_for_experiments/pull/1

Твій приклад дійсно прадає, я ще не можу пояснити чому том що по факту це дійсно реквест який надсилається, не можу пояснити точно поки що

АЛЕ якщо поміняти реквест якого ти чекаєш — то все працює
Бо по ідеї ти написав очікування на реквест що робить навігацію, а навігаційний респонс такє враження що плейрайт не перехоплює.
Я вдивився та можна зробити очікування на реквест що робить конкретно нова сторінка — і все ок працює в цьому випадку. ІМХО твій приклад тре переписати на те щоб робилось очікування не реквест/респонсу, а waitForURL

Ось конкретно як запрацює:
github.com/...​es-navigation.spec.ts#L80

Чудова стаття.
Як потрапити до вас у команду?

Це такий жарт?

дуже малоймовірно отримаєте такий race condition
просто все локально ганяється і все успішно проходить

Уявляю як нова людина приходить, додає моки на ці запити і починає отримувати race condition. Цікаво куди дивився ваш лід і як цей код потрапив у проект. Якщо дійшла справа до статті, тоді є велика ймовірність, що подібне використовувалось у реальному проекті

Моки скорше стосуватимуться компонентних тестів та інтеграційних, цей приклад стосується системних тестів, на реальному оточенні, але навіть на локалхості парцює безвідмовно
Склонуйте репозиторій та спробуйте домогтись такого рейс кондішену

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

логіка яка описана вона є правильна та логічно коректна

людина створила свідомо ситуацію

малоймовірно отримаєте такий race condition

Вам лід вкаже на двері. Самостійно задумайтесь над тим що за шкоду проекту можуть попросити відповісти. Я розумію джунам весело пробувати різні штуки, але якщо побачать, що хтось розважається ціною проекту. Тоді реакція може не сподобатись

Ніхто не оцінить того, що коду на два рядки менше стало. Оцінять те, з якою легкістю хтось грається на реальному проекті

По перше я і є лід, я наймаю людей в стеках java, python, ts, c#
По друге, якщо згрубше глянемо що відбувається пілся кліку
— клік івент передається по сокету в dev tools браузера
— подія в домі діспатчиться
— жс хендлери перехоплюють подію
— запит ініціалізується, не блокуючі, без очікування на завершення. Тобто просто надсилається
— проміс коіка резолвиться

Це тривати може біля 1-3 мілісекунд

Потім що із запитом відбувається(якщо не закешовано)
— Днс лукап
— Хендшейк
— лоад балансер отримує запит
— гейтвей
— аус чек
— мікросервіс отримує запит
— валідує
— бізнес логіка певна трігериться
— база даних кверяєттся
— бд респонс
— формується відповідь сервісу
— апі гейтвей процесить запит
— лоад балансер
— респонс повертається назад
— браузер отримує респонс
— waitForResponse резолвиться

І цей увесь шлях в найкращому випадку відбуваєть за 150 мілісекунд. В гіршому і секунду

Але притому всьому, проміс кліку завершується тоді коли івент в браузері просто ініціалізовано, навряд хтось зробить івент блокуючім.
Проміс резолвиться та наступна стрічка починає свою роботу за 1 мікро секунду.

Навіть якщо конекшн закешовано, то з кешом запит довше йде від браузера дотлоадбалансера ніж починається новий проміс

Я дуже добре розумію що відбувається, ба більше навіть якщо замокати запит плейратом — то все ідеально відпрацьовує

Я трохи глибше копаю як щось працює, ніж на рівні документації зупиняюсь

Просто склоньте репозиторій та спробуйте поламати, але навіть на локальхості це не вийде в вас

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

Лід це людина котра повинна зупиняти джунів і пояснювати які наслідки будуть, якщо використовувати інструменти не так як задумано авторами. Лід повинен захищати проект від речей для котрих потрібно використовувати слово «малоймовірно». І від речей котрі джун не зможе зрозуміти прочитавши документацію. Це не круто, що для розуміння комусь також доведеться копати.

Схоже на класичну проблему, коли людину з технічними скілами поставили на посаду ліда, але сама людина лідом так і не стала, а продовжує займатись розвагами. Тільки тепер у неї є повна свобода і ніхто її не зупинить

Бачу кліше на кліше без розуміння ширшого контексту, просто «прилетіли» написати аби написати комент, хто мій лід я і є лід, чим має займатись лід, як хто має працювати
А що якщо скажу, що це мій менті таку знахідку зробив, а я цю знахідку дослідив розвинув та показав, що він правий і дійсно так можна.

прийшли просто потоксичити в коменти, а потім кажуть «а вот українською нема ніц почитати, все фігня та поверхневе, а вот англійською, (або взагалі руснявою, прости боже) — там є шо почитати». Із-за тиких не конструктивних дискусій, тому і є така мала кількість бажання щось робити

Не бачу сенсу продовжувати дискусію без конкретних технічних аргументів

Обʼєктивно ця ідея це абсурд
— зайва складність (самі підтвердили необхідність копатись) без практичної вигоди
— порушення дизайну інструменту. Непередбачуваність логіки через декілька років

Банально можна взяти опис обовʼязків ліда. Те про що він повинен думати і які фактори враховувати. І побачиш що базові речі відверто порушуються. Без переходу на особистості: автор статті не виконує обоʼязки ліда, навіть якщо його назначили на цю посаду

Тут ще можна додати невміння реагувати на власні помилки, навіть якщо вони очевидні. Обовʼязки ліда не вчора були придумані. Можна самостійно оцінити себе і побачити проблеми

Хочеш англійське комʼюніті? Окей, візьми і подивись популярні речі англійського комʼюніті
The Worst Kind Of Programmer
www.youtube.com/watch?v=ea9reHDIrOo

І спостерігай як тебе так описують. Як вказують наскільки неприємні люди на проекті котрі керуються такими ідеями як у тебе

PS: на рахунок комʼюніті. Тут більше проблема що українці це переважно самоучки. Профільна освіта дає якійсь обʼєктивні критерії оцінки. Самоучки часто керуються просто власними смаками. І коли сперечаються дві самоучки, то вони сперечаються про смаки. От я пишу про обовʼязки ліда, а ти продовжуєш писати які цікаві технічні деталі. При цьому не розуміючи що твій інтерес до технічних деталей у цьому випадку є проблемою

І нібито нам проміс, в цьому випадку, нам дає перевагу над іншим не асинхронними мовами

Яка перевага у цьому випадку?

так само писати «синхронний» код

Ви await використовуєте. Навіщо? Щоб кожен рядок коду починати з зайвого слова?

1. Зайвої стрічки коду не потрібно
2. Я б залюбки писав без авейта, але це можливо лише на інших мовах

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