🕵️♂️ Інженерний детектив: "Невидима перешкода" (або Z-Index пастка)
Привіт, екіпаж! Середа — час розслідувань.
Симптоми: Користувачі скаржаться, що кнопка "Купити" не натискається. Ви запускаєте Cypress/Playwright — тест клікає кнопку і світиться зеленим. Ви відкриваєте руками — кнопка реально не реагує на мишку!
🔍 Що сталося:
✅ Вирок:
Привіт, екіпаж! Середа — час розслідувань.
Симптоми: Користувачі скаржаться, що кнопка "Купити" не натискається. Ви запускаєте Cypress/Playwright — тест клікає кнопку і світиться зеленим. Ви відкриваєте руками — кнопка реально не реагує на мишку!
🔍 Що сталося:
Playwright за замовчуванням має механізм "Actionability", але іноді він хибить. Фронтендер випадково розтягнув прозорий <div> (наприклад, невидимий тултип) поверх кнопки.
Візуально кнопка є. В DOM вона є. Але фізично курсор клікає по прозорому <div>, який лежить вище по z-index!
✅ Вирок:
У Playwright іноді використовують force: true для кліку. Це змушує фреймворк пробити DOM і клікнути елемент, ігноруючи перешкоди. Ніколи цього не робіть.
Якщо тест падає через "element intercepts pointer events" — це не нестабільний тест, це реальний баг UI, який блокує ваших живих користувачів.
📝 Ультимативна Шпаргалка: HTTP Status Codes (Версія для QA)
Ми всі знаємо 200 (OK) та 404 (Not Found). Але на співбесідах (і під час тестування NestJS бекендів) постійно плутають помилки клієнта. Зберігайте:
Перевіряйте не просто факт помилки, а її ТОЧНИЙ код у ваших API тестах!
Ми всі знаємо 200 (OK) та 404 (Not Found). Але на співбесідах (і під час тестування NestJS бекендів) постійно плутають помилки клієнта. Зберігайте:
401 Unauthorized: "Я не знаю, хто ти". (Ти забув передати токен авторизації, або він прострочений).
403 Forbidden: "Я знаю, хто ти, але тобі туди не можна". (Ти залогінений як звичайний юзер, а намагаєшся видалити проєкт як Адмін).
400 Bad Request: "Ти відправив технічну діч". (Синтаксична помилка, не валідний JSON, бракує обов'язкового поля).
422 Unprocessable Entity: "Формат правильний, але бізнес-логіка проти". (Ти відправив ідеальний JSON з полем email, але цей email вже зайнятий у PostgreSQL).
Перевіряйте не просто факт помилки, а її ТОЧНИЙ код у ваших API тестах!
🔥 Прожарка інструментів: Selenium WebDriver (Легенда, якій час на пенсію)
Привіт, екіпаж! Сьогодні смажимо прабатька всієї UI-автоматизації.
🟢 Як нам це продають: "Це стандарт! Він підтримує навіть Internet Explorer 8 і будь-які мови програмування!"
🥩 Прожарка:
Вердикт: Якщо ви стартуєте новий проєкт у 2026 році — Selenium є найгіршим вибором з точки зору швидкості розробки (DX). Залиште його для підтримки легасі.
Привіт, екіпаж! Сьогодні смажимо прабатька всієї UI-автоматизації.
🟢 Як нам це продають: "Це стандарт! Він підтримує навіть Internet Explorer 8 і будь-які мови програмування!"
🥩 Прожарка:
1️⃣ Пекло версій: Скільки життів згоріло через помилку SessionNotCreatedException: This version of ChromeDriver only supports Chrome version X. Ви оновили браузер — тести впали. Потрібно постійно менеджити драйвери (так, є WebDriverManager, але це ще один костиль).
2️⃣ Архітектура: Selenium працює через HTTP-запити до драйвера. Він фізично не може зазирнути всередину браузера, перехопити мережу чи працювати з LocalStorage так само елегантно і швидко, як Playwright чи Cypress (які спілкуються через CDP протокол).
Вердикт: Якщо ви стартуєте новий проєкт у 2026 році — Selenium є найгіршим вибором з точки зору швидкості розробки (DX). Залиште його для підтримки легасі.
🩻 Рентген співбесіди: "Тестування Webhooks"
Продовжуємо четвер питанням для мідлів+.
Питання: "Ваш додаток інтегровано з платіжною системою. Коли оплата проходить, стороння система відправляє Webhook (асинхронний POST запит) на ваш бекенд. Як це протестувати?"
❌ Відповідь Джуна: "Я оплачу на UI і буду робити sleep(10000) або постійно оновлювати сторінку, поки баланс не зміниться."
✅ Відповідь Сеньйора:
Продовжуємо четвер питанням для мідлів+.
Питання: "Ваш додаток інтегровано з платіжною системою. Коли оплата проходить, стороння система відправляє Webhook (асинхронний POST запит) на ваш бекенд. Як це протестувати?"
❌ Відповідь Джуна: "Я оплачу на UI і буду робити sleep(10000) або постійно оновлювати сторінку, поки баланс не зміниться."
✅ Відповідь Сеньйора:
Я взагалі не буду чіпати сторонню систему. Я використаю API-клієнт в автотестах і сам відправлю POST-запит на наш ендпоінт вебхука (наприклад, /api/webhooks/stripe), імітуючи payload від платіжки з правильними signature-заголовками.
Або, якщо треба протестувати реальний флоу, підніму локальний тунель через Ngrok у CI/CD, щоб стороння система могла "достукатися" до мого тестового оточення.
💩 Код з душком: Магічні числа (або "Чому саме 5?")
Привіт, екіпаж! П'ятниця — вивітрюємо антипатерни.
Знайдіть проблему:
Чому це тхне:
Що таке 5? Це хардкод. Якщо хтось додасть нову статтю в базу даних — тест впаде, хоча функціонал працює. Вам доведеться йти в код і міняти 5 на 6. Це перетворює підтримку тестів на рутину.
✅ Як має бути:
Завжди спирайтеся на динамічні дані. Якщо ви мокаєте мережу — беріть довжину з моку. Якщо берете з бази — робіть запит:
Додали елемент у масив? Тест адаптується автоматично.
Привіт, екіпаж! П'ятниця — вивітрюємо антипатерни.
Знайдіть проблему:
test('Відображення списку статей', async ({ page }) => {
await expect(page.locator('.article-card')).toHaveCount(5);
});Чому це тхне:
Що таке 5? Це хардкод. Якщо хтось додасть нову статтю в базу даних — тест впаде, хоча функціонал працює. Вам доведеться йти в код і міняти 5 на 6. Це перетворює підтримку тестів на рутину.
✅ Як має бути:
Завжди спирайтеся на динамічні дані. Якщо ви мокаєте мережу — беріть довжину з моку. Якщо берете з бази — робіть запит:
// 🚀 Ідеально
const articlesMock = [{id: 1}, {id: 2}];
await page.route('**/api/articles', route => route.fulfill({ json: articlesMock }));
await expect(page.locator('.article-card')).toHaveCount(articlesMock.length);
Додали елемент у масив? Тест адаптується автоматично.
⚔️ Битва підходів: Page Object Model (POM) проти Custom Fixtures
Завершуємо тиждень класичною битвою архітектур у Playwright.
🥊 Підхід 1: Page Object Model (Класика)
🥊 Підхід 2: Playwright Fixtures (Сучасність)
Вердикт: POM все ще крутий для опису селекторів (аби не дублювати locator), але для складних флоу переходьте на кастомні Fixtures — це робить ваші тести чистими як сльоза.
Завершуємо тиждень класичною битвою архітектур у Playwright.
🥊 Підхід 1: Page Object Model (Класика)
Ви створюєте клас LoginPage з методами fillEmail() та clickSubmit().
Проблема: З часом класи стають гігантськими ("Божественний об'єкт"), вимагають постійного new LoginPage(page) і засмічують пам'ять.
🥊 Підхід 2: Playwright Fixtures (Сучасність)
Ви інкапсулюєте кроки прямо в інфраструктуру тесту. Тест просто просить те, що йому треба у параметрах:
test('buy item', async ({ loggedInUser, cartInfo }) => { ... })
Перевага: loggedInUser сам під капотом відкриє сторінку, залогіниться, перевірить сесію і віддасть готовий стан. Жодних new, максимальна ізоляція та перевикористання.
Вердикт: POM все ще крутий для опису селекторів (аби не дублювати locator), але для складних флоу переходьте на кастомні Fixtures — це робить ваші тести чистими як сльоза.
🛰 Екіпаж, на зв'язку твій Ко-пілот.
Привіт! Сьогодні без технічних новин та розбору тест-кейсів. Сьогодні ми про головне. ☕️
Хочеться просто підтримати один одного і нагадати, як ми дорожимо кожним, хто з нами в цьому екіпажі. Цей канал — не про політичний шум, він про взаємодію та підтримку.
Сьогоднішня ніч для Києва та області була складною. Твій Ко-пілот на зв’язку, ми разом в цьому штормі. Маю надію, що кожен з вас цілий. Пам'ятайте головне: після темряви завжди приходить світло.
Якщо вам потрібна моральна підтримка або просто хочете з кимось поспілкуватись — пишіть в коментарях. Ми разом проживемо ці емоції. Хто в безпеці — підтримайте своїх. Просто зателефонуйте друзям, перевірте зв'язок.
Ми все переживемо і будемо рухатись далі! Разом.
Привіт! Сьогодні без технічних новин та розбору тест-кейсів. Сьогодні ми про головне. ☕️
Хочеться просто підтримати один одного і нагадати, як ми дорожимо кожним, хто з нами в цьому екіпажі. Цей канал — не про політичний шум, він про взаємодію та підтримку.
Сьогоднішня ніч для Києва та області була складною. Твій Ко-пілот на зв’язку, ми разом в цьому штормі. Маю надію, що кожен з вас цілий. Пам'ятайте головне: після темряви завжди приходить світло.
Якщо вам потрібна моральна підтримка або просто хочете з кимось поспілкуватись — пишіть в коментарях. Ми разом проживемо ці емоції. Хто в безпеці — підтримайте своїх. Просто зателефонуйте друзям, перевірте зв'язок.
Ми все переживемо і будемо рухатись далі! Разом.
❤2
🧨 Руйнівники IT-міфів: "100% Code Coverage означає відсутність багів"
Привіт, екіпаж! Сьогодні б'ємо по найпопулярнішому менеджерському міфу, який змушує команди писати тести заради галочки. ☕️
❌ Міф: "Наш SonarQube показує 100% покриття коду тестами. Ми можемо спокійно релізити, багів немає!"
💥 Реальність (Бум!):
✅ Як має бути (Підхід Архітектора):
А ви ганяєтесь за відсотками покриття? 👇
🔥 — Ні, фокусуємось на критичних бізнес-сценаріях!
👀 — У нас KPI на 80% покриття, іноді пишемо тести заради цифри...
🤯 — Стоп, тобто тести можуть проходити, навіть якщо логіка зламана?!
Привіт, екіпаж! Сьогодні б'ємо по найпопулярнішому менеджерському міфу, який змушує команди писати тести заради галочки. ☕️
❌ Міф: "Наш SonarQube показує 100% покриття коду тестами. Ми можемо спокійно релізити, багів немає!"
💥 Реальність (Бум!):
Code Coverage показує лише те, які рядки коду виконувалися під час прогону тестів. Але він абсолютно НЕ гарантує, що ви перевірили результат!
Ви можете написати автотест, який викликає функцію calculateSalary(), і не написати жодного expect(). Рядки коду виконаються, покриття буде 100%, а функція насправді може повертати null і ламати продакшен.
✅ Як має бути (Підхід Архітектора):
Справжній показник надійності — це Mutation Testing (Мутаційне тестування, наприклад, через інструмент Stryker).
Цей інструмент штучно вносить баги у ваш код (міняє + на -, видаляє виклики функцій) і перевіряє, чи впадуть ваші автотести. Якщо тести залишилися зеленими — вони сліпі, і ваші 100% покриття не варті нічого.
А ви ганяєтесь за відсотками покриття? 👇
🔥 — Ні, фокусуємось на критичних бізнес-сценаріях!
👀 — У нас KPI на 80% покриття, іноді пишемо тести заради цифри...
🤯 — Стоп, тобто тести можуть проходити, навіть якщо логіка зламана?!
🧠 Задача з Senior співбесіди: "Невловимі WebSockets"
Привіт, екіпаж! Другий пост на сьогодні. Беремо задачу з лайв-кодингу, на якій часто "пливуть" кандидати, коли мова заходить про сучасні real-time додатки. ☕️
Умови задачі:
❌ Відповідь рівня Junior (Хибний шлях):
✅ Відповідь рівня Senior (Підхід Архітектора):
Ми не будемо покладатися на сліпі таймери. Ми будемо "слухати" сам WebSocket-канал на рівні браузера!
У Playwright є можливість перехоплювати не тільки HTTP, але й фрейми всередині WS-з'єднань:
Результат: Тест працює зі швидкістю світла. Ніяких "блимаючих" падінь через нестабільність мережі.
А ви вже автоматизували WebSockets? 👇
🔥 — Звісно, перехоплюємо фрейми як профі!
👀 — Поки тестуємо тільки звичайні HTTP (REST) запити...
🤯 — Чекайте, Playwright вміє читати дані всередині відкритого сокета?!
Привіт, екіпаж! Другий пост на сьогодні. Беремо задачу з лайв-кодингу, на якій часто "пливуть" кандидати, коли мова заходить про сучасні real-time додатки. ☕️
Умови задачі:
Ви тестуєте систему живих сповіщень. Додаток тримає постійне з'єднання через WebSockets (стандартна історія для NestJS бекендів).
Коли статус вашого замовлення змінюється, бекенд пушить івент у сокет, і на фронтенді миттєво вискакує тост: "Замовлення відправлено".
Питання: Як надійно автоматизувати цей флоу в E2E-тесті, враховуючи, що повідомлення може прилетіти через 10 мілісекунд, а може затриматися на 2 секунди через мережу?
❌ Відповідь рівня Junior (Хибний шлях):
"Я тригерну зміну статусу через API, поставлю жорсткий sleep(3000) про всяк випадок, і перевірю, чи з'явився тост у DOM".
Чому це провал: Якщо сокет затримається на 3.1 секунди, тест впаде. А якщо прийде миттєво — ви просто так спалите час у CI/CD.
✅ Відповідь рівня Senior (Підхід Архітектора):
Ми не будемо покладатися на сліпі таймери. Ми будемо "слухати" сам WebSocket-канал на рівні браузера!
У Playwright є можливість перехоплювати не тільки HTTP, але й фрейми всередині WS-з'єднань:
// 1. Створюємо "пастку" для конкретного WebSocket повідомлення
const wsMessagePromise = page.waitForEvent('websocket', ws => {
return ws.url().includes('/notifications');
}).then(ws => ws.waitForEvent('framereceived', frame =>
frame.payload.includes('order_shipped')
));
// 2. Тригеримо зміну статусу через API
await api.changeOrderStatus('shipped');
// 3. Тест піде далі ТІЛЬКИ в ту мілісекунду, коли прилетить потрібний фрейм
await wsMessagePromise;
// 4. Тільки тепер перевіряємо UI
await expect(page.locator('.toast')).toBeVisible();
Результат: Тест працює зі швидкістю світла. Ніяких "блимаючих" падінь через нестабільність мережі.
А ви вже автоматизували WebSockets? 👇
🔥 — Звісно, перехоплюємо фрейми як профі!
👀 — Поки тестуємо тільки звичайні HTTP (REST) запити...
🤯 — Чекайте, Playwright вміє читати дані всередині відкритого сокета?!
📝 Ультимативна Шпаргалка: Стан елемента в DOM (Visible vs Attached)
Привіт, екіпаж! Скільки разів ви ловили помилку
У сучасних інструментах (Playwright, Cypress) елемент перед кліком проходить 4 стадії зрілості. Знати їх — обов'язок QA.
👻 Attached (Прикріплений)
👁Visible (Видимий)
🟢Enabled (Активний)
🛑 Stable (Стабільний)
Золоте правило перевірок (Asserts):
Якщо ж елемент просто ховається через CSS — він залишається Attached, але перестає бути Visible. Перевіряємо так:
await expect(locator).toBeHidden().
А ви плутали Attached і Visible? 👇
🔥 — Знаю цю базу, мої тести надійні як швейцарський годинник!
👀 — Постійно ліплю .toBeVisible() на все підряд і страждаю...
🤯 — Чекайте, тобто елемент може бути в DOM, але не бути Visible?!
Привіт, екіпаж! Скільки разів ви ловили помилку
Element is not visible, хоча в DevTools його чітко видно в HTML-коді? Сьогодні розбираємо життєвий цикл елемента на сторінці. Це база, без якої ваші асерти (перевірки) завжди будуть нестабільними. ☕️У сучасних інструментах (Playwright, Cypress) елемент перед кліком проходить 4 стадії зрілості. Знати їх — обов'язок QA.
👻 Attached (Прикріплений)
Елемент фізично існує в DOM-дереві.
Пастка: Він може бути повністю прозорим (opacity: 0), мати display: none або нульовий розмір (0x0). Ви бачите його код у DevTools, але юзер на екрані його не бачить.
(В Angular це зазвичай відбувається при використанні [hidden]="true").
👁Visible (Видимий)
Елемент прикріплений (Attached), має реальні розміри (bounding box не нульовий) і не захований стилями.
Пастка: Він видимий, але може бути перекритий іншим елементом зверху (наприклад, напівпрозорим лоадером або невидимим тултипом).
🟢Enabled (Активний)
Елемент видимий, не перекритий, і на ньому немає атрибута disabled. Тільки на цій стадії з ним можна взаємодіяти.
🛑 Stable (Стабільний)
Елемент повністю завершив свою CSS-анімацію. Він більше не летить через половину екрану. Якщо фреймворк спробує клікнути до цієї стадії — він просто клікне в порожнечу.
Золоте правило перевірок (Asserts):
Тестуючи зникнення елемента, завжди питайте розробників, ЯК він зникає.
Якщо використовується умовний рендеринг (наприклад, новий синтаксис @if або старий *ngIf в Angular) — елемент ПОВНІСТЮ видаляється з DOM. Перевіряємо так:
await expect(locator).toHaveCount(0) або toBeAttached({ attached: false }).
Якщо ж елемент просто ховається через CSS — він залишається Attached, але перестає бути Visible. Перевіряємо так:
await expect(locator).toBeHidden().
А ви плутали Attached і Visible? 👇
🔥 — Знаю цю базу, мої тести надійні як швейцарський годинник!
👀 — Постійно ліплю .toBeVisible() на все підряд і страждаю...
🤯 — Чекайте, тобто елемент може бути в DOM, але не бути Visible?!
🤖 Навіщо нам ШІ-інтерв'юєр, якщо вже є ChatGPT?
Екіпаж, зв'язок відновлено. Останні два тижні в ефірі була тиша, бо я пішов копати одну думку. Зараз з кожної праски кричать про ШІ. Сотні обгорток над GPT, які обіцяють зробити з вас Senior QA за три дні.
Але давайте чесно: ви пробували пройти технічну співбесіду з базовим ChatGPT або Claude?
Це жахливо. Вони занадто "добрі" і поверхневі.
Ти кидаєш йому кривий локатор з прив'язкою до тексту, а він відповідає: "Ви на правильному шляху, який ви молодець, але можливо варто подивитись на...".
Справжній лід на співбесіді так не робить. Справжній лід запитає, чому ти не використав кастомні атрибути і як твій тест витримає асинхронний ререндеринг компонентів. Загальні ШІ працюють як Вікіпедія — вони видають довідку. А на співбесіді потрібен стрес, контекст і глибокі питання по архітектурі, патернах та CI/CD.
Справжній симулятор співбесід не має бути просто діалоговим вікном. Це має бути повноцінний апп (наприклад, швидкий Telegram Mini App з нормальною архітектурою під капотом), який пам'ятає твої слабкі місця, не дає підказок і безжально "робить рев'ю" твоєму коду.
Як ви думаєте, чи є сенс у такому вузькоспеціалізованому, хардкорному ШІ-менторі саме для QA? Чи базової підписки на ChatGPT вистачає з головою? Пишіть ваші думки 👇
Екіпаж, зв'язок відновлено. Останні два тижні в ефірі була тиша, бо я пішов копати одну думку. Зараз з кожної праски кричать про ШІ. Сотні обгорток над GPT, які обіцяють зробити з вас Senior QA за три дні.
Але давайте чесно: ви пробували пройти технічну співбесіду з базовим ChatGPT або Claude?
Це жахливо. Вони занадто "добрі" і поверхневі.
Ти кидаєш йому кривий локатор з прив'язкою до тексту, а він відповідає: "Ви на правильному шляху, який ви молодець, але можливо варто подивитись на...".
Справжній лід на співбесіді так не робить. Справжній лід запитає, чому ти не використав кастомні атрибути і як твій тест витримає асинхронний ререндеринг компонентів. Загальні ШІ працюють як Вікіпедія — вони видають довідку. А на співбесіді потрібен стрес, контекст і глибокі питання по архітектурі, патернах та CI/CD.
Справжній симулятор співбесід не має бути просто діалоговим вікном. Це має бути повноцінний апп (наприклад, швидкий Telegram Mini App з нормальною архітектурою під капотом), який пам'ятає твої слабкі місця, не дає підказок і безжально "робить рев'ю" твоєму коду.
Як ви думаєте, чи є сенс у такому вузькоспеціалізованому, хардкорному ШІ-менторі саме для QA? Чи базової підписки на ChatGPT вистачає з головою? Пишіть ваші думки 👇
🕵️♂️ Code Review: Знайди вбивцю CI/CD
Екіпаж, розімнемо мізки. Уявіть ситуацію: Junior QA приносить вам такий код на Playwright.
Він клянеться, що на його потужному макбуці тест працює ідеально в 100% випадків. Але щойно цей код потрапляє в CI/CD пайплайн, тест періодично намертво зависає на кілька хвилин і падає по таймауту.
Де тут закладена бомба уповільненої дії? Виберіть правильний варіант в опитуванні нижче 👇
Екіпаж, розімнемо мізки. Уявіть ситуацію: Junior QA приносить вам такий код на Playwright.
Він клянеться, що на його потужному макбуці тест працює ідеально в 100% випадків. Але щойно цей код потрапляє в CI/CD пайплайн, тест періодично намертво зависає на кілька хвилин і падає по таймауту.
// Зберігаємо профіль користувача
await page.getByRole('button', { name: 'Save Profile' }).click();
// Чекаємо, поки бекенд відповість успішним статусом
await page.waitForResponse(res =>
res.url().includes('/api/users/profile') && res.status() === 200
);
// Перевіряємо, що з'явився тост про успіх
await expect(page.locator('.toast-success')).toBeVisible();
Де тут закладена бомба уповільненої дії? Виберіть правильний варіант в опитуванні нижче 👇
Чому тест зависає в CI/CD?
Anonymous Quiz
33%
Локатор .toast-success не встигає відрендеритись в Angular/React.
8%
Треба додати await page.waitForTimeout(1000) після кліку для стабільності.
58%
Стан гонитви (Race condition): бекенд відповідає швидше, ніж Playwright починає його чекати.
0%
Неправильно написаний URL в перевірці регулярним виразом.
⚙️ Хардкорний розбір: Як не зламати базу в тестах (Angular + NestJS + Prisma)
Екіпаж, забуваємо про абстрактні задачки. Сьогодні розбираємо реальну архітектуру.
Маємо сучасний стек: важкий Angular на фронтенді, NestJS під капотом, який спілкується з PostgreSQL через Prisma ORM.
Головний біль (State Leakage):
❌ Як роблять мідли (Милиці):
✅ Як будують архітектори (Hardcore QA):
Ми не чіпаємо UI для очищення. Ми використовуємо силу самої Prisma та кастомні фікстури Playwright!
Крок 1: Back-door у NestJS (Тільки для тестового середовища)
Крок 2: Автоматизація в Playwright (Fixtures)
Результат:
Кожен ваш тест (навіть якщо ви запустили їх 100 паралельно) починається з абсолютно чистої таблиці PostgreSQL. Ніяких конфліктів даних, ніяких "моргаючих" (flaky) тестів. Angular отримує чистий бекенд, Playwright літає.
А як ви менеджите тестові дані у своїх базах? 👇
🔥 — Тільки хардкор, тільки ізольовані транзакції в БД!
👀 — Пишу унікальні email-и через Date.now() і не парюсь...
🤯 — Зачекайте, Playwright вміє робити auto: true фікстури?!
Екіпаж, забуваємо про абстрактні задачки. Сьогодні розбираємо реальну архітектуру.
Маємо сучасний стек: важкий Angular на фронтенді, NestJS під капотом, який спілкується з PostgreSQL через Prisma ORM.
Головний біль (State Leakage):
Ви пишете E2E тест на Playwright, який реєструє юзера.
Перший прогін — ідеально (зелений).
Другий прогін — тест падає, бо NestJS віддає помилку 400: User with this email already exists. Стан бази "забруднився".
❌ Як роблять мідли (Милиці):
Пишуть в кінці тесту крок "Видалити акаунт" через UI. Але якщо тест впав посередині — видалення не спрацює, і база залишиться брудною.
Або ще гірше — намагаються мокати Prisma прямо в NestJS. Але тоді це вже не E2E тест, а фікція.
✅ Як будують архітектори (Hardcore QA):
Ми не чіпаємо UI для очищення. Ми використовуємо силу самої Prisma та кастомні фікстури Playwright!
Крок 1: Back-door у NestJS (Тільки для тестового середовища)
Створюємо прихований контролер у NestJS, який буде доступний ТІЛЬКИ коли змінна оточення NODE_ENV=testing. Цей контролер має один ендпоінт, який жорстко зачищає базу через транзакцію Prisma.
// testing.controller.ts (NestJS)
@Post('/teardown')
async cleanDatabase() {
// Prisma $transaction гарантує, що все видалиться або нічого
await this.prisma.$transaction([
this.prisma.user.deleteMany(),
this.prisma.order.deleteMany(),
// ...інші таблиці
]);
return { status: 'cleaned' };
}
Крок 2: Автоматизація в Playwright (Fixtures)
Замість того, щоб у кожному тесті писати beforeEach, ми створюємо кастомну фікстуру. Вона буде автоматично смикати наш NestJS ендпоінт ПЕРЕД кожним тестом.
// fixtures.ts (Playwright)
import { test as base } from '@playwright/test';
export const test = base.extend({
cleanDb: [async ({ request }, use) => {
// Дія ДО тесту: смикаємо Prisma через бекенд
await request.post('http://localhost:3000/api/testing/teardown');
await use(); // Тут виконується сам тест
}, { auto: true }], // auto: true означає, що це відпрацює для ВСІХ тестів
});
Результат:
Кожен ваш тест (навіть якщо ви запустили їх 100 паралельно) починається з абсолютно чистої таблиці PostgreSQL. Ніяких конфліктів даних, ніяких "моргаючих" (flaky) тестів. Angular отримує чистий бекенд, Playwright літає.
А як ви менеджите тестові дані у своїх базах? 👇
🔥 — Тільки хардкор, тільки ізольовані транзакції в БД!
👀 — Пишу унікальні email-и через Date.now() і не парюсь...
🤯 — Зачекайте, Playwright вміє робити auto: true фікстури?!
🗣 Soft Skills: Чому твій ідеальний код нікого не хвилює (якщо ти мямлиш)
Екіпаж, сьогодні відійдемо від Playwright та баз даних. Поговоримо про зброю, яку більшість QA ігнорує — ваш голос.
Ви можете написати геніальну архітектуру автотестів або знайти критичний Memory Leak. Але якщо на демо перед замовником ви ковтаєте закінчення, невпевнено бубоните або не можете чітко пояснити розробнику, в чому суть бага — ваша експертиза множиться на нуль. Впевнена комунікація продавлює тікети швидше за будь-які лог-файли.
Як прокачати артикуляцію (Хардкорний метод)
Спочатку ви будете звучати кумедно, а м'язи обличчя почнуть горіти вже через дві хвилини. Але коли ви витягнете корок і просто скажете "Доброго ранку, команда", ваш голос звучатиме настільки чисто, об'ємно і впевнено, що розробники самі підуть фіксити баги без зайвих суперечок.
Челлендж для сміливих:
Хто не посоромиться і скине найчіткіше войс-повідомлення — отримає від мене персональний респект. Погнали! 👇
Екіпаж, сьогодні відійдемо від Playwright та баз даних. Поговоримо про зброю, яку більшість QA ігнорує — ваш голос.
Ви можете написати геніальну архітектуру автотестів або знайти критичний Memory Leak. Але якщо на демо перед замовником ви ковтаєте закінчення, невпевнено бубоните або не можете чітко пояснити розробнику, в чому суть бага — ваша експертиза множиться на нуль. Впевнена комунікація продавлює тікети швидше за будь-які лог-файли.
Як прокачати артикуляцію (Хардкорний метод)
Не обов'язково йти на дорогі курси ораторської майстерності. Є один жорсткий, але максимально дієвий інструмент, який я сам регулярно використовую.
Вам знадобиться звичайний винний корок і 10 хвилин часу.
1️⃣ Затискаєте корок між передніми зубами (не дуже глибоко, просто щоб зафіксувати).
2️⃣ Відкриваєте будь-яку складну технічну документацію або набір важких скоромовок.
3️⃣ Починаєте читати вголос, намагаючись максимально чітко та гіпертрофовано вимовляти кожен звук крізь цю перешкоду.
Спочатку ви будете звучати кумедно, а м'язи обличчя почнуть горіти вже через дві хвилини. Але коли ви витягнете корок і просто скажете "Доброго ранку, команда", ваш голос звучатиме настільки чисто, об'ємно і впевнено, що розробники самі підуть фіксити баги без зайвих суперечок.
Челлендж для сміливих:
Готові перевірити свою дикцію прямо зараз? Записуйте голосове повідомлення в коментарі під цим постом і прочитайте на одному диханні цю QA-скоромовку:
"Сеньйор-тестувальник тестив-тестив рест-апі, та не витестував, бо флоу бекенду флудив фіктивними фікстурами".
Хто не посоромиться і скине найчіткіше войс-повідомлення — отримає від мене персональний респект. Погнали! 👇
❤2
🏋️♂️ "Сушка" для автотестів: Як скинути зайву вагу з вашого CI/CD
Екіпаж, сьогодні поговоримо про фітнес для вашого коду.
Коли ми тільки починаємо писати E2E-тести, наш фреймворк стрункий і швидкий. Але минає півроку, тестів стає сотні, і наш CI/CD пайплайн перетворюється на неповороткого важковаговика. Прогін займає 40 хвилин, тести "задихаються" і падають через нестачу пам'яті.
Фреймворку потрібна жорстка сушка і правильні спортивні добавки.
🍔 Що таке "жир" у ваших тестах?
💊 Спортивне харчування для Playwright:
Проведіть аудит свого фреймворку. Скільки "зайвої ваги" тягнуть ваші автотести на кожному прогоні?
А скільки хвилин зараз займає фулл-прогін ваших тестів? 👇
🔥 — До 5 хвилин, мій фреймворк — атлет!
👀 — Десь 15-20 хвилин, є над чим працювати.
🤯 — Більше години... ми запускаємо їх тільки на ніч.
Екіпаж, сьогодні поговоримо про фітнес для вашого коду.
Коли ми тільки починаємо писати E2E-тести, наш фреймворк стрункий і швидкий. Але минає півроку, тестів стає сотні, і наш CI/CD пайплайн перетворюється на неповороткого важковаговика. Прогін займає 40 хвилин, тести "задихаються" і падають через нестачу пам'яті.
Фреймворку потрібна жорстка сушка і правильні спортивні добавки.
🍔 Що таке "жир" у ваших тестах?
Це хардкоджені sleep(5000), дублювання коду в beforeEach (коли кожен тест заново логіниться через UI) та використання важких локаторів. Це порожні калорії, які сповільнюють виконання.
💊 Спортивне харчування для Playwright:
Щоб ваш фреймворк став рельєфним і швидким, йому потрібні правильні інструменти:
🔹API-логін замість UI (L-карнітин для тестів): Навіщо кожного разу клікати форму авторизації? Отримуйте токен через бекенд за мілісекунди і "згодовуйте" його браузеру. Це спалює десятки хвилин часу в CI/CD.
🔹Паралелізація та Шардінг (Креатин для CI/CD): Дайте вашим тестам вибухову силу. Розбивайте виконання на кілька потоків (workers) у GitHub Actions або GitLab CI. Нехай тести біжать одночасно на різних машинах, як під час інтенсивного спліту.
🔹Гнучкі очікування (Правильна розминка): Використовуйте waitForResponse або waitForSelector замість фіксованих пауз. Тест має діяти рівно тоді, коли система готова, не витрачаючи зайвої енергії.
Проведіть аудит свого фреймворку. Скільки "зайвої ваги" тягнуть ваші автотести на кожному прогоні?
А скільки хвилин зараз займає фулл-прогін ваших тестів? 👇
🔥 — До 5 хвилин, мій фреймворк — атлет!
👀 — Десь 15-20 хвилин, є над чим працювати.
🤯 — Більше години... ми запускаємо їх тільки на ніч.
❤1
🤖 ШІ не напише за тебе автотести (якщо ти не вмієш давати йому контекст)
Всі вже пробували генерувати тести через ChatGPT або Claude. Зазвичай запит виглядає так:
"Напиши мені E2E тест на Playwright для форми реєстрації".
Що ми отримуємо? Нейромережа видає шаблонний код із документації, який розіб'ється на першому ж кастомному компоненті Angular і поняття не має, як працює ваш бекенд. ШІ — це не магія. Це просто дуже швидкий джун, якому потрібне чітке ТЗ.
Щоб отримувати робочий код, а не галюцинації, промпт має бути архітектурним. Ось формула, якою користуюся я:
1️⃣ Задаємо роль і точний стек:
2️⃣ Даємо контекст середовища і бази даних:
3️⃣ Ставимо точкову задачу (з фокусом на API, а не тільки UI):
З таким запитом ви отримуєте не абстрактну кашу, а готовий скелет із правильним перехопленням запитів та підготовкою даних. Залишається лише прописати ваші реальні локатори.
А як у вас стосунки з ШІ на проєктах? 👇
🔥 — Пишу промпти на 3 сторінки, щоб отримати ідеальний скрипт.
👀 — Використовую суто як Google на максималках (пошук помилок).
🤯 — ШІ генерує маячню, пишу всі локатори руками.
Всі вже пробували генерувати тести через ChatGPT або Claude. Зазвичай запит виглядає так:
"Напиши мені E2E тест на Playwright для форми реєстрації".
Що ми отримуємо? Нейромережа видає шаблонний код із документації, який розіб'ється на першому ж кастомному компоненті Angular і поняття не має, як працює ваш бекенд. ШІ — це не магія. Це просто дуже швидкий джун, якому потрібне чітке ТЗ.
Щоб отримувати робочий код, а не галюцинації, промпт має бути архітектурним. Ось формула, якою користуюся я:
1️⃣ Задаємо роль і точний стек:
"Дій як Senior QA Automation. Твій стек: Playwright + TypeScript. Ми тестуємо важкий Angular-додаток, який спілкується з NestJS бекендом."
2️⃣ Даємо контекст середовища і бази даних:
"Враховуй, що авторизація працює через JWT-токен у LocalStorage. База даних — PostgreSQL, ми працюємо з нею через Prisma ORM. Тести мають бути повністю незалежними."
3️⃣ Ставимо точкову задачу (з фокусом на API, а не тільки UI):
"Згенеруй структуру E2E тесту для флоу 'Блокування юзера'. Включи в код: 1) генерацію тестових даних через API перед тестом, 2) перехоплення (mock) відповіді від POST /api/users/block, щоб не чекати реальної відповіді бази. Напиши код з використанням Page Object Model."
З таким запитом ви отримуєте не абстрактну кашу, а готовий скелет із правильним перехопленням запитів та підготовкою даних. Залишається лише прописати ваші реальні локатори.
А як у вас стосунки з ШІ на проєктах? 👇
🔥 — Пишу промпти на 3 сторінки, щоб отримати ідеальний скрипт.
👀 — Використовую суто як Google на максималках (пошук помилок).
🤯 — ШІ генерує маячню, пишу всі локатори руками.
👌1
🚀 Як прискорити прогін Playwright у 10 разів (без смс та реєстрації)
Екіпаж, зв'язок відновлено. Досить чекати годинами на результати тестів у CI/CD. Сьогодні розбираємо, як зробити ваш фреймворк на Playwright по-справжньому швидким.
Більшість автоматизаторів запускають тести послідовно. Це шлях в нікуди, коли тестів стає більше 50. Є два основні архітектурні інструменти для масштабування: паралелізація та шардінг.
1️⃣ Workers (Паралелізація на одній машині)
Як налаштувати: У файлі playwright.config.ts:
Пастка: Ваша база даних або бекенд мають бути готові до того, що 4 тести одночасно будуть створювати юзерів або робити замовлення. Використовуйте унікальні дані для кожного тесту.
2️⃣ Sharding (Масштабування на кілька серверів)
Як налаштувати: При запуску тестів у CI/CD додаємо прапорець:
Результат: Тести виконуються одночасно на 3-х незалежних серверах. Замість 30 хвилин ви отримуєте результати за 10. Потім Playwright просто збирає всі звіти (Reports) в один.
А як ви масштабуєте свої тести? 👇
🔥 — Тільки воркери, база не витримує більше 4-х потоків.
👀 — Шардінг у GitHub Actions, CI/CD літає!
🤯 — Чекаю годину послідовного прогону і медитую...
Екіпаж, зв'язок відновлено. Досить чекати годинами на результати тестів у CI/CD. Сьогодні розбираємо, як зробити ваш фреймворк на Playwright по-справжньому швидким.
Більшість автоматизаторів запускають тести послідовно. Це шлях в нікуди, коли тестів стає більше 50. Є два основні архітектурні інструменти для масштабування: паралелізація та шардінг.
1️⃣ Workers (Паралелізація на одній машині)
Це база. Playwright вміє запускати тести одночасно в різних вкладках браузера на одному сервері. Кількість цих вкладок регулюється параметром workers.
Як налаштувати: У файлі playwright.config.ts:
use: {
// Запускає тести в 4 паралельних потоках
workers: 4,
// Або автоматично на основі кількості ядер процесора
// workers: process.env.CI ? 2 : undefined,
},Пастка: Ваша база даних або бекенд мають бути готові до того, що 4 тести одночасно будуть створювати юзерів або робити замовлення. Використовуйте унікальні дані для кожного тесту.
2️⃣ Sharding (Масштабування на кілька серверів)
Це рівень сеньйора. Якщо навіть 10 воркерів на одній машині задихаються, ви розбиваєте набір тестів на кілька частин (шардів) і запускаєте їх на різних серверах у CI/CD (наприклад, у GitHub Actions).
Як налаштувати: При запуску тестів у CI/CD додаємо прапорець:
# Ділимо тести на 3 машини і запускаємо першу частину
npx playwright test --shard=1/3
# На іншій машині запускаємо:
npx playwright test --shard=2/3
# І на третій:
npx playwright test --shard=3/3
Результат: Тести виконуються одночасно на 3-х незалежних серверах. Замість 30 хвилин ви отримуєте результати за 10. Потім Playwright просто збирає всі звіти (Reports) в один.
А як ви масштабуєте свої тести? 👇
🔥 — Тільки воркери, база не витримує більше 4-х потоків.
👀 — Шардінг у GitHub Actions, CI/CD літає!
🤯 — Чекаю годину послідовного прогону і медитую...
🤖 Відмовляємося від класичних Assert'ів: Як тестувати ШІ-додатки (AI Assertions)
Ми всі звикли писати класичні перевірки в Playwright:
expect(element).toHaveText('Успішна реєстрація').
Це працює ідеально для статичних систем. Але як ви протестуєте чат-бота, генератор текстів або ШІ-помічника?
ШІ щоразу віддає різний текст. Сьогодні це "Привіт, чим можу допомогти?", а завтра "Вітаю, яке у вас питання?". Класичний E2E тест тут же впаде, хоча система працює коректно.
Рішення: AI Assertions (ШІ замість expect)
Чому це майбутнє:
Ваші тести стають "розумними". Вони більше не ламаються через змінену кому чи перефразування. Ви тестуєте зміст та бізнес-логіку, а не жорсткі пікселі та символи. Це і є справжній підхід QA Co-pilot.
А як ви зараз валідуєте динамічні або згенеровані дані у своїх проєктах? 👇
🔥 — Вже підкрутив OpenAI API до своїх E2E тестів!
👀 — Пишу регулярні вирази (RegEx) на пів сторінки...
🤯 — Навіть не думав, що ШІ можна використовувати як Assert!
Ми всі звикли писати класичні перевірки в Playwright:
expect(element).toHaveText('Успішна реєстрація').
Це працює ідеально для статичних систем. Але як ви протестуєте чат-бота, генератор текстів або ШІ-помічника?
ШІ щоразу віддає різний текст. Сьогодні це "Привіт, чим можу допомогти?", а завтра "Вітаю, яке у вас питання?". Класичний E2E тест тут же впаде, хоча система працює коректно.
Рішення: AI Assertions (ШІ замість expect)
Замість того, щоб порівнювати рядки посимвольно, ми просимо іншу нейромережу (наприклад, OpenAI API) оцінити результат нашого тесту!
Як це виглядає на практиці (Playwright + OpenAI):
1️⃣ Виконуємо дію в UI (наприклад, просимо бота згенерувати summary статті).
2️⃣ Витягуємо отриманий текст через Playwright.
3️⃣ Відправляємо цей текст через API до GPT-4 з промптом-валідатором.
// Приклад кастомного AI Assert
async function expectToMatchContext(actualText: string, expectedMeaning: string) {
const response = await openai.chat.completions.create({
model: "gpt-4-turbo",
messages: [
{
role: "system",
content: "Ти суворий QA-валідтор. Дай відповідь тільки 'true' або 'false'. Чи несе отриманий текст такий самий зміст, що і очікуваний?"
},
{
role: "user",
content: `Очікуваний зміст: "${expectedMeaning}". Отриманий текст: "${actualText}"`
}
]
});
const isMatch = response.choices[0].message.content === 'true';
expect(isMatch).toBeTruthy();
}
// Використання в тесті:
const botReply = await page.locator('.chat-message').innerText();
await expectToMatchContext(botReply, "Бот має привітатися та запропонувати допомогу");
Чому це майбутнє:
Ваші тести стають "розумними". Вони більше не ламаються через змінену кому чи перефразування. Ви тестуєте зміст та бізнес-логіку, а не жорсткі пікселі та символи. Це і є справжній підхід QA Co-pilot.
А як ви зараз валідуєте динамічні або згенеровані дані у своїх проєктах? 👇
🔥 — Вже підкрутив OpenAI API до своїх E2E тестів!
👀 — Пишу регулярні вирази (RegEx) на пів сторінки...
🤯 — Навіть не думав, що ШІ можна використовувати як Assert!
💸 Як тестувати AI-фічі і не збанкрутувати на API-ключах OpenAI
Уявіть: у вас є Angular-фронтенд, який через NestJS бекенд стукає до GPT-4, щоб згенерувати користувачу звіт.
Ви пишете E2E тест. Він працює. Але коли ваш CI/CD починає ганяти цей тест 50 разів на день, ви отримуєте три проблеми:
Рішення: Жорсткий Mocking AI-запитів у Playwright
Щоб перевірити, як ваш UI рендерить відповідь від ШІ, чи правильно працює markdown-розмітка та як обробляються помилки, вам не потрібен реальний ШІ.
Ми перехоплюємо запит від фронтенду до нашого бекенду і підсовуємо йому заздалегідь підготовлену "фейкову" відповідь нейромережі.
Як це реалізувати (Playwright Network Interception):
Що ми отримали?
А як ви тестуєте функціонал, зав'язаний на платних API? 👇
🔥 — Мокаю все, що рухається, через page.route!
👀 — Ганяю реальні запити, компанія платить за API.
🤯 — Чекаю по 20 секунд у кожному тесті...
Уявіть: у вас є Angular-фронтенд, який через NestJS бекенд стукає до GPT-4, щоб згенерувати користувачу звіт.
Ви пишете E2E тест. Він працює. Але коли ваш CI/CD починає ганяти цей тест 50 разів на день, ви отримуєте три проблеми:
1️⃣ Гроші: Кожен запуск спалює ваш бюджет на OpenAI API.
2️⃣ Швидкість: Відповідь від LLM може займати 10-20 секунд. Тести стають нестерпно довгими.
3️⃣ Flakiness (нестабільність): Сервери OpenAI іноді лягають або віддають 500-ту помилку. Ваш тест падає, хоча ваш власний код працює ідеально.
Рішення: Жорсткий Mocking AI-запитів у Playwright
Щоб перевірити, як ваш UI рендерить відповідь від ШІ, чи правильно працює markdown-розмітка та як обробляються помилки, вам не потрібен реальний ШІ.
Ми перехоплюємо запит від фронтенду до нашого бекенду і підсовуємо йому заздалегідь підготовлену "фейкову" відповідь нейромережі.
Як це реалізувати (Playwright Network Interception):
test('UI коректно рендерить згенерований AI звіт', async ({ page }) => {
// 1. Перехоплюємо запит до нашого NestJS API
await page.route('**/api/v1/generate-report', async route => {
// 2. Імітуємо ідеальну відповідь від AI без звернення до реального OpenAI
const mockAiResponse = {
status: 'success',
data: {
content: '## Ваш звіт готовий\n\n- Знайдено 3 проблеми.\n- Оптимізація можлива.',
tokensUsed: 150
}
};
// 3. Віддаємо мок назад у браузер
await route.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify(mockAiResponse)
});
});
// 4. Тригеримо генерацію в UI
await page.getByRole('button', { name: 'Згенерувати звіт' }).click();
// 5. Перевіряємо, чи Angular правильно відрендерив markdown (відповідь прийде миттєво!)
await expect(page.locator('h2')).toHaveText('Ваш звіт готовий');
});Що ми отримали?
Час виконання тесту впав з 15 секунд до 0.5 секунди. Вартість прогону — $0. Ви ізолювали свою систему від нестабільності стороннього AI-провайдера. Реальне підключення до OpenAI залишається тільки для одного-двох інтеграційних тестів, а весь E2E шар покривається моками.
А як ви тестуєте функціонал, зав'язаний на платних API? 👇
🔥 — Мокаю все, що рухається, через page.route!
👀 — Ганяю реальні запити, компанія платить за API.
🤯 — Чекаю по 20 секунд у кожному тесті...
🔥 Екіпаж, я повертаюсь. І приніс дещо, що зекономить вам години рутини.
Останнім часом я випав з ефіру — був глибоко занурений у ресерч та побудову нових процесів. І сьогодні ми розберемо найнуднішу частину роботи будь-якого автоматизатора: аналіз падінь у CI/CD (Test Triage).
Уявіть: нічний прогін на 500 E2E тестів, 15 із них червоні. Замість того, щоб спокійно пити каву, ви йдете читати логи, відкривати Playwright Traces і шукати, де саме відвалився NestJS бекенд, а де просто Angular-компонент не встиг відрендеритись.
Що, якби ШІ робив цей первинний аналіз за вас?
Ось концепт AI Test Triage, який перетворює ШІ на вашого молодшого інженера. Ми інтегруємо легкий скрипт у пайплайн. Якщо тест падає, скрипт автоматично бере stderr та останні 20 рядків логів і відправляє їх в OpenAI API з чітким архітектурним промптом.
Промпт для ШІ-аналітика:
Результат:
У ваш робочий месенджер приходить не просто сухе сповіщення "15 тестів впало", а готовий звіт:
Ви одразу знаєте: перші 3 тікети треба віддати бекенд-команді, а решту — фіксити самому. Ніякого ручного копання в смітті. ШІ бере на себе брудну роботу, залишаючи вам чисту інженерію.
А скільки часу ви зазвичай витрачаєте на розбір репортів щоранку? 👇
🔥 — До 15 хвилин, усе стабільно.
👀 — Близько години, це мій сумний ранковий ритуал.
🤯 — Пів дня копаюсь у трейсах...
Останнім часом я випав з ефіру — був глибоко занурений у ресерч та побудову нових процесів. І сьогодні ми розберемо найнуднішу частину роботи будь-якого автоматизатора: аналіз падінь у CI/CD (Test Triage).
Уявіть: нічний прогін на 500 E2E тестів, 15 із них червоні. Замість того, щоб спокійно пити каву, ви йдете читати логи, відкривати Playwright Traces і шукати, де саме відвалився NestJS бекенд, а де просто Angular-компонент не встиг відрендеритись.
Що, якби ШІ робив цей первинний аналіз за вас?
Ось концепт AI Test Triage, який перетворює ШІ на вашого молодшого інженера. Ми інтегруємо легкий скрипт у пайплайн. Якщо тест падає, скрипт автоматично бере stderr та останні 20 рядків логів і відправляє їх в OpenAI API з чітким архітектурним промптом.
Промпт для ШІ-аналітика:
"Ти — Senior QA. Проаналізуй лог помилки Playwright. Визнач причину падіння і поверни ТІЛЬКИ одну з трьох категорій:
ENVIRONMENT (впав бекенд, відпала база даних, 500/502 помилка).
FLAKY (елемент не знайдено по таймауту, проблема з локатором, UI не завантажився).
BUG (логічна помилка, очікуваний результат не співпав з фактичним).
Додай 1 речення пояснення."
Результат:
У ваш робочий месенджер приходить не просто сухе сповіщення "15 тестів впало", а готовий звіт:
🔴 3 тести — ENVIRONMENT (NestJS повернув 502 Bad Gateway).
🟡 12 тестів — FLAKY (Angular hydration timeout на сторінці дашборду).
Ви одразу знаєте: перші 3 тікети треба віддати бекенд-команді, а решту — фіксити самому. Ніякого ручного копання в смітті. ШІ бере на себе брудну роботу, залишаючи вам чисту інженерію.
А скільки часу ви зазвичай витрачаєте на розбір репортів щоранку? 👇
🔥 — До 15 хвилин, усе стабільно.
👀 — Близько години, це мій сумний ранковий ритуал.
🤯 — Пів дня копаюсь у трейсах...