🕵️♂️ Детектив: Баг, якого не бачить Cypress, або Як QA знайшов "тихого вбивцю" оперативки
Привіт, екіпаж! Сьогодні в рубриці Post-Mortem розбираємо інженерний горор. Це історія про те, як ідеально "зелені" автотести пропустили баг, що перетворював ноутбуки наших клієнтів на обігрівачі. ☕️
Зав'язка (Ідеальний реліз)
Розслідування (QA бере слід)
Що робить крутий QA:
Винуватець: Підписка-зомбі 🧟♂️
Як QA має тестувати це в майбутньому:
Кидати розробнику скріншот диспетчера завдань — це рівень джуна. Ось як ми це автоматизували:
🤖 Playwright Memory Test:
Висновок:
А ви перевіряєте фронтенд на витоки пам'яті, чи покладаєтесь на те, що у всіх юзерів зараз по 32 ГБ оперативки? 👇
🔥 — Обов'язково! Heap Snapshots і вкладка Performance — мої найкращі друзі.
👀 — Ми тестуємо тільки навантаження на бекенд, на клієнті якось не доводилось...
🤯 — Щойно написав скрипт, який клікає меню 100 разів. Здається, я знайшов баг на своєму проєкті!
Привіт, екіпаж! Сьогодні в рубриці Post-Mortem розбираємо інженерний горор. Це історія про те, як ідеально "зелені" автотести пропустили баг, що перетворював ноутбуки наших клієнтів на обігрівачі. ☕️
Зав'язка (Ідеальний реліз)
Ми викотили нову фічу (live-оновлення бейджа повідомлень у профілі). E2E тести в Playwright пройшли за 4 хвилини, API тести світяться зеленим, навантажувальне тестування бекенду (JMeter) показало ідеальні результати. Релізнули.
Через день у сапорт сипляться тікети: "Ваш сайт намертво зависає через півгодини роботи", "Chrome видає помилку Out of Memory".
Розслідування (QA бере слід)
Розробники розводять руками: "На моїй машині все літає, бекенд відповідає за 20 мс".
Тоді за справу береться QA. Ми знаємо, що звичайні автотести проклікують флоу за секунди і закривають браузер. Вони фізично не здатні зловити деградацію в часі.
Що робить крутий QA:
Відкриває Chrome Task Manager (Shift + Esc), запускає наш додаток і починає агресивно переходити між сторінками "Головна" -> "Профіль". Робить це 30 разів поспіль.
Результат: споживання пам'яті вкладки вилітає з 80 МБ до 2 ГБ. Браузер "лягає".
QA відкриває вкладку Memory в DevTools, робить Heap Snapshot (Знімок купи пам'яті) і знаходить винуватця.
Винуватець: Підписка-зомбі 🧟♂️
Виявилося, що фронтендер написав сервіс, який через RxJS кожні 5 секунд смикав бекенд. Але він забув додати одну життєво важливу річ — відписку (unsubscribe) при виході зі сторінки.
Кожен раз, коли юзер відкривав профіль, створювалася НОВА підписка. Юзер зайшов у профіль 50 разів? У фоні паралельно працюють 50 зомбі-процесів, які не дають Garbage Collector-у очистити пам'ять. Класичний Memory Leak.
Як QA має тестувати це в майбутньому:
Кидати розробнику скріншот диспетчера завдань — це рівень джуна. Ось як ми це автоматизували:
🤖 Playwright Memory Test:
Ми написали окремий автотест, який в циклі (100 разів) відкриває і закриває важкий компонент. В кінці циклу тест через page.evaluate() викликає window.performance.memory.usedJSHeapSize і перевіряє, чи не виросла пам'ять експоненційно порівняно з першим циклом. Якщо виросла більше ніж на 20% — пайплайн падає з помилкою Memory Leak Detected.
Висновок:
Функціональне тестування (чи працює кнопка) — це лише верхівка айсберга. Справжній QA-інженер тестує ще й те, як додаток поводиться з ресурсами клієнта.
А ви перевіряєте фронтенд на витоки пам'яті, чи покладаєтесь на те, що у всіх юзерів зараз по 32 ГБ оперативки? 👇
🔥 — Обов'язково! Heap Snapshots і вкладка Performance — мої найкращі друзі.
👀 — Ми тестуємо тільки навантаження на бекенд, на клієнті якось не доводилось...
🤯 — Щойно написав скрипт, який клікає меню 100 разів. Здається, я знайшов баг на своєму проєкті!
❤1
📋 Шпаргалка QA: 6 неочевидних перевірок API (Крім банального 200 OK)
Якщо ваше тестування API закінчується на тому, щоб відправити GET-запит, отримати статус 200 OK і перевірити, чи прийшов правильний JSON — ви просто виконуєте роботу базового скрипта-пінгатора. ☕️
Щоб знаходити баги рівня Senior і не пропускати критичні вразливості на продакшен, зберігайте цю ультимативну шпаргалку з тестування бекенду.
1️⃣ IDOR (або "Синдром чужої кишені")
2️⃣ Бомба Пагінації (Pagination Limit)
3️⃣ Мутація типів даних (Type Juggling)
4️⃣ Перевірка невідомих полів (Mass Assignment)
5️⃣ Жорстке Лімітування (Rate Limiting)
6️⃣ Заголовки (Headers) як зброя
Зберігайте в "Збережене" і проганяйте свої API через цей чек-ліст перед кожним релізом. Це база, яка врятує ваші нерви.
А на якому з цих пунктів найчастіше "сипляться" ваші бекендери? 👇
🔥 — IDOR! Вічно забувають перевірити права на чужі ресурси.
👀 — У нас завжди 500-ті помилки замість нормальної валідації.
🤯 — Пішов перевіряти size=100000, здається, я зараз покладу стейдж...
Якщо ваше тестування API закінчується на тому, щоб відправити GET-запит, отримати статус 200 OK і перевірити, чи прийшов правильний JSON — ви просто виконуєте роботу базового скрипта-пінгатора. ☕️
Щоб знаходити баги рівня Senior і не пропускати критичні вразливості на продакшен, зберігайте цю ультимативну шпаргалку з тестування бекенду.
1️⃣ IDOR (або "Синдром чужої кишені")
Що робити: Авторизуйтесь як Юзер А. Візьміть POST/PUT запит, який змінює профіль (або замовлення), і підмініть userId або orderId у тілі чи URL на ID Юзера Б.
Очікування: 403 Forbidden або 404 Not Found. Якщо бекенд повернув успіх і змінив чужі дані — ви щойно знайшли критичну діру в безпеці (Broken Object Level Authorization).
2️⃣ Бомба Пагінації (Pagination Limit)
Що робити: У GET-запитах зі списком товарів чи юзерів (наприклад, /api/users?page=1&size=20) змініть size на 100000, або page на -1 чи 0.
Очікування: Адекватна 400 Bad Request помилка або примусовий ліміт до умовних 100 записів. Якщо база "зависла", намагаючись дістати мільйон рядків — це пряма вразливість до DoS-атак.
3️⃣ Мутація типів даних (Type Juggling)
Що робити: Якщо API очікує число ("age": 25), надішліть рядок ("age": "25"), надішліть null, масив [] або взагалі порожній об'єкт {}.
Очікування: Чітка помилка валідації (400). Погано написаний бекенд може впасти з помилкою 500 Internal Server Error і залишити за собою "сміття" в базі. Неконтрольовані 500-ті помилки — це маркер поганої архітектури.
4️⃣ Перевірка невідомих полів (Mass Assignment)
Що робити: У POST-запит на реєстрацію або оновлення додайте поле, якого немає в документації. Наприклад: {"username": "Ivan", "role": "admin", "balance": 9999}.
Очікування: Бекенд має суворо ігнорувати невідомі поля (Sanitization) або віддавати 400. Якщо ваш фейковий баланс або адмінські права записалися в базу — це фатальна архітектурна помилка (наприклад, прямий мапінг DTO в Entity)
5️⃣ Жорстке Лімітування (Rate Limiting)
Що робити: Запустіть цикл у Postman (Runner) або через скрипт, який відправить 50 однакових запитів на створення ресурсу за 1 секунду.
Очікування: API має віддати статус 429 Too Many Requests. Якщо воно спокійно обробляє все підряд — вас заспамлять боти в перший же день релізу, а AWS/Google Cloud виставить космічний рахунок за сервери.
6️⃣ Заголовки (Headers) як зброя
Що робити: Видаліть заголовок Content-Type: application/json або змініть його на text/plain / application/xml. Передайте велетенський токен авторизації розміром у 10 мегабайт.
Очікування: Зрозуміла 415 Unsupported Media Type або 431 Request Header Fields Too Large. Якщо сервер просто падає без відповіді — налаштування вебсервера (Nginx/API Gateway) діряві.
Зберігайте в "Збережене" і проганяйте свої API через цей чек-ліст перед кожним релізом. Це база, яка врятує ваші нерви.
А на якому з цих пунктів найчастіше "сипляться" ваші бекендери? 👇
🔥 — IDOR! Вічно забувають перевірити права на чужі ресурси.
👀 — У нас завжди 500-ті помилки замість нормальної валідації.
🤯 — Пішов перевіряти size=100000, здається, я зараз покладу стейдж...
❤1
🛠 Прожарка: Чому "No-Code AI тестування" — це найбільша афера ринку (І пастка для бюджету)
Привіт, екіпаж! Відкриваємо нову рубрику «Прожарка інструментів», де ми безжально тестуємо хайпові технології на реальних задачах. І почнемо з найболючішого: "Розумних" No-Code платформ, які обіцяють назавжди замінити AQA-інженерів. ☕️
Реклама на кожному кроці кричить: "Просто проклікайте ваш сайт, а наш ШІ сам напише E2E тести, та ще й буде їх лагодити на льоту (Auto-Healing)". Бізнес у захваті, менеджери купують ліцензії по $1000/місяць і звільняють автоматизаторів. А потім починається пекло продакшену.
Ось чому ці тулзи — це милиці, які зроблять ваш проєкт інвалідом:
🤖 Смертельна галюцинація (Небезпека Auto-Healing)
🔒 Золота клітка (Рабство Vendor Lock-in)
🧩 Крах на реальній архітектурі
Вердикт: No-Code AI інструменти — це крута іграшка для лендінгів або MVP-стартапів. Але для серйозного продукту з мікросервісами та складною стейт-машиною — це архітектурне самогубство. Інвестуйте час у Playwright + TypeScript. А штучний інтелект (Cursor / Copilot) використовуйте як асистента для написання коду, який ви повністю контролюєте.
А ви вже пробували гратися з No-Code тестуванням? 👇
🔥 — Тільки хардкор, тільки чистий код у Playwright/Cypress!
👀 — Пробував(ла) записувати тести рекордерами, потім замучився(лась) їх підтримувати.
🤬 — Не згоден! AI-платформи економлять купу часу, ви просто не вмієте їх готувати!
Привіт, екіпаж! Відкриваємо нову рубрику «Прожарка інструментів», де ми безжально тестуємо хайпові технології на реальних задачах. І почнемо з найболючішого: "Розумних" No-Code платформ, які обіцяють назавжди замінити AQA-інженерів. ☕️
Реклама на кожному кроці кричить: "Просто проклікайте ваш сайт, а наш ШІ сам напише E2E тести, та ще й буде їх лагодити на льоту (Auto-Healing)". Бізнес у захваті, менеджери купують ліцензії по $1000/місяць і звільняють автоматизаторів. А потім починається пекло продакшену.
Ось чому ці тулзи — це милиці, які зроблять ваш проєкт інвалідом:
🤖 Смертельна галюцинація (Небезпека Auto-Healing)
Обіцянка: Якщо розробник змінив локатор (ID) кнопки або її дизайн, ШІ проаналізує DOM і знайде її за контекстом.
Реальність: AI працює як поганий студент на іспиті — намагається вгадати. У мене був кейс: кнопка "Підтвердити оплату" тимчасово зникла через баг фронтенду.
Що зробив ШІ? Він "дбайливо" знайшов сусідню кнопку "Скасувати замовлення" і клікнув її. Тест радісно засвітився зеленим (Passed!). ШІ авто-зцілив тест, але приховав критичний баг бізнес-логіки. Ви більше не можете довіряти власним репортам.
🔒 Золота клітка (Рабство Vendor Lock-in)
Обіцянка: Швидкий старт, не треба налаштовувати CI/CD та фреймворки.
Реальність: Ваші тести вам не належать. Вони існують лише всередині закритої хмарної платформи (SaaS). Ви не можете закинути їх у свій Git. Коли через рік цей стартап закриється або підніме ціну втричі (а вони це роблять регулярно), ви не зможете просто експортувати код і запустити його в себе. Вам доведеться переписувати річну роботу з нуля на Playwright.
🧩 Крах на реальній архітектурі
Обіцянка: Покриття 90% сценаріїв без жодного рядка коду.
Реальність: Це ідеально працює для тестування "Форми зворотного зв'язку". Але спробуйте протестувати реальний флоу: згенерувати токен через API, покласти його в базу (щоб обійти 2FA), авторизуватися, перехопити iframe від платіжної системи (Stripe) і почекати на WebSocket подію про успішну транзакцію. No-Code платформи на цьому етапі просто вмирають. І вам доводиться писати жахливі милиці на чистому JS у їхньому кривому вбудованому текстовому редакторі.
Вердикт: No-Code AI інструменти — це крута іграшка для лендінгів або MVP-стартапів. Але для серйозного продукту з мікросервісами та складною стейт-машиною — це архітектурне самогубство. Інвестуйте час у Playwright + TypeScript. А штучний інтелект (Cursor / Copilot) використовуйте як асистента для написання коду, який ви повністю контролюєте.
А ви вже пробували гратися з No-Code тестуванням? 👇
🔥 — Тільки хардкор, тільки чистий код у Playwright/Cypress!
👀 — Пробував(ла) записувати тести рекордерами, потім замучився(лась) їх підтримувати.
🤬 — Не згоден! AI-платформи економлять купу часу, ви просто не вмієте їх готувати!
🎙 Рентген співбесіди: "Чорний ящик", або Питання, яке валить 80% Middle QA
Запускаємо нову рубрику «Рентген співбесіди», де ми розбираємо каверзні питання з технічних інтерв'ю та аналізуємо, що насправді хочуть почути від вас ліди. ☕️
Сьогодні на операційному столі класична пастка для перевірки архітектурного мислення.
Питання від інтерв'юера:
❌ Як відповідає Junior / Слабкий Middle (Червоний прапорець):
Ліду не потрібен тестувальник, який боїться системи. Йому потрібен інженер, який вміє ізолювати систему.
✅ Як відповідає Senior QA (Ідеальна відповідь):
Далі ви добиваєте інтерв'юера трьома кроками:
Висновок: Цим питанням ліди перевіряють, чи розумієте ви різницю між клієнтськими моками (на фронті) та інфраструктурними моками (на рівні бекенду). Senior QA — це ілюзіоніст, який може створити для бекенду ідеально контрольовану віртуальну реальність.
А як би ви відповіли на це питання до прочитання поста? 👇
🔥 — WireMock — наше все, завжди ізолюю сторонні API!
👀 — Я б сказав про моки на фронтенді... Тепер зрозумів помилку.
🤯 — Я б просто тестував на проді. Гуляти так гуляти!
Запускаємо нову рубрику «Рентген співбесіди», де ми розбираємо каверзні питання з технічних інтерв'ю та аналізуємо, що насправді хочуть почути від вас ліди. ☕️
Сьогодні на операційному столі класична пастка для перевірки архітектурного мислення.
Питання від інтерв'юера:
"Ви тестуєте наш бекенд. Він розраховує вартість доставки, звертаючись до стороннього API (наприклад, FedEx або Нової Пошти). Доступу до їхньої бази у вас немає, тестового середовища у них теж немає, а кожен ваш запит до їхнього API коштує бізнесу реальних грошей. Ваші дії?"
❌ Як відповідає Junior / Слабкий Middle (Червоний прапорець):
1️⃣ "Ну, я попрошу розробників щось придумати або зробити мені тестовий енв." (Перекладання відповідальності).
2️⃣ "Буду тестувати обережно, щоб не витратити багато грошей." (Відсутність розуміння автоматизації та навантаження).
3️⃣ "Замокаю запити на фронтенді (в Cypress/Playwright), щоб фронт не смикав бекенд." (Катастрофа! Ви залишили бекенд узагалі без тестування).
Ліду не потрібен тестувальник, який боїться системи. Йому потрібен інженер, який вміє ізолювати систему.
✅ Як відповідає Senior QA (Ідеальна відповідь):
"Я не буду чіпати фронтенд. Я ізолюю наш бекенд від зовнішнього світу за допомогою Mock-сервера (наприклад, WireMock або Mountebank)."
Далі ви добиваєте інтерв'юера трьома кроками:
1️⃣ Підміна реальності (Stubbing): Я попрошу DevOps (або сам через Docker) підняти локальний WireMock. Скажу бекенду: "Тепер ти ходиш не на api.fedex.com, а на localhost:8080". І на цьому локальному сервері я налаштую заглушки: якщо бекенд питає ціну для Києва — повертай JSON із цифрою 100.
2️⃣ Тестування хаосу (Fault Injection):
Реальне API може "впасти". Я налаштую свій WireMock так, щоб він повертав 500 Internal Server Error або, ще краще, робив затримку (Delay) у 15 секунд. І я перевірю, чи не "ляже" наш власний бекенд через таймаути і чи не заблокується наша база даних в очікуванні відповіді.
3️⃣ Контрактне тестування:
Щоб мої заглушки не застаріли, я ініціюю написання Contract Tests. Ми будемо раз на добу перевіряти структуру реального API постачальника, щоб переконатися, що вони не змінили поле price на cost без попередження.
Висновок: Цим питанням ліди перевіряють, чи розумієте ви різницю між клієнтськими моками (на фронті) та інфраструктурними моками (на рівні бекенду). Senior QA — це ілюзіоніст, який може створити для бекенду ідеально контрольовану віртуальну реальність.
А як би ви відповіли на це питання до прочитання поста? 👇
🔥 — WireMock — наше все, завжди ізолюю сторонні API!
👀 — Я б сказав про моки на фронтенді... Тепер зрозумів помилку.
🤯 — Я б просто тестував на проді. Гуляти так гуляти!
❤1
💩 Код з душком: Асинхронна м'ясорубка, або Чому ваші тести "успішно" проходять за 0.1 секунди
Привіт, екіпаж! Рубрика «Код з душком» на зв'язку. Сьогодні препаруємо одну з найпідступніших пасток у TypeScript/JavaScript, у яку регулярно потрапляють як розробники, так і AQA-інженери при написанні API чи E2E тестів. ☕️
Подивіться на цей фрагмент коду (наприклад, у Playwright або Jest). Знайдіть причину, чому цей тест — це міна уповільненої дії:
Здається, все логічно: біжимо по масиву, чекаємо створення кожного юзера, перевіряємо статус.
Чому цей код тхне:
✅ Як виглядає код після рев'ю Senior-інженера:
Варіант 1: Послідовне виконання (Безпечно):
Варіант 2: Паралельне виконання (Швидко і правильно)
Висновок для QA:
Якщо ваш API-тест, який має створити 10 сутностей у базі даних, виконується за долю секунди — ви не написали найшвидший фреймворк у світі. Ви написали мовчазну галюцинацію. Ніколи не використовуйте forEach разом із асинхронними операціями.
А вас колись кусав forEach з промісами? 👇
🔥 — О так, класика! Витратив години, поки зрозумів, чому тест "зелений" при мертвому бекенді.
👀 — Тільки for...of або Promise.all, я цю школу життя вже пройшов.
🤯 — Чекайте, я щойно зрозумів, чому мій скрипт для генерації тестових даних працює через раз... Пішов переписувати!
Привіт, екіпаж! Рубрика «Код з душком» на зв'язку. Сьогодні препаруємо одну з найпідступніших пасток у TypeScript/JavaScript, у яку регулярно потрапляють як розробники, так і AQA-інженери при написанні API чи E2E тестів. ☕️
Подивіться на цей фрагмент коду (наприклад, у Playwright або Jest). Знайдіть причину, чому цей тест — це міна уповільненої дії:
// ❌ Як часто пишуть (Антипатерн "Сліпий цикл")
test('Повинен створити трьох користувачів', async () => {
const users = ['Ivan', 'Petro', 'Anna'];
users.forEach(async (user) => {
const response = await api.createUser(user);
expect(response.status).toBe(200);
});
console.log('✅ Всі юзери успішно перевірені!');
});
Здається, все логічно: біжимо по масиву, чекаємо створення кожного юзера, перевіряємо статус.
Чому цей код тхне:
Ви запускаєте тест, і він проходить за феноменальні 50 мілісекунд. Ви відчуваєте себе генієм оптимізації. Але насправді тест взагалі нічого не перевірив.
Метод масиву forEach за своєю природою — синхронний. Він абсолютно ігнорує ключове слово await всередині свого колбеку. Він просто вистрілює три мережеві запити в порожнечу один за одним і миттєво йде далі. Тест завершується і світиться зеленим ЩЕ ДО ТОГО, як бекенд встигає відповісти.
А якщо через секунду бекенд поверне помилку 500? Ваші expect впадуть у фоні, викликавши Unhandled Promise Rejection, що зробить пайплайн нестабільним (flaky), але сам тест формально залишиться "зеленим".
✅ Як виглядає код після рев'ю Senior-інженера:
Варіант 1: Послідовне виконання (Безпечно):
test('Повинен створити трьох користувачів', async () => {
const users = ['Ivan', 'Petro', 'Anna'];
// Цикл for...of поважає await і чекає завершення кожної ітерації
for (const user of users) {
const response = await api.createUser(user);
expect(response.status).toBe(200);
}
});Варіант 2: Паралельне виконання (Швидко і правильно)
test('Повинен створити трьох користувачів', async () => {
const users = ['Ivan', 'Petro', 'Anna'];
// Запускаємо всі запити одночасно і чекаємо на їх РЕАЛЬНЕ завершення
await Promise.all(
users.map(async (user) => {
const response = await api.createUser(user);
expect(response.status).toBe(200);
})
);
});Висновок для QA:
Якщо ваш API-тест, який має створити 10 сутностей у базі даних, виконується за долю секунди — ви не написали найшвидший фреймворк у світі. Ви написали мовчазну галюцинацію. Ніколи не використовуйте forEach разом із асинхронними операціями.
А вас колись кусав forEach з промісами? 👇
🔥 — О так, класика! Витратив години, поки зрозумів, чому тест "зелений" при мертвому бекенді.
👀 — Тільки for...of або Promise.all, я цю школу життя вже пройшов.
🤯 — Чекайте, я щойно зрозумів, чому мій скрипт для генерації тестових даних працює через раз... Пішов переписувати!
❤1
⚔️ Битва підходів: Junior vs. QA Architect (Як ми готуємо тестові дані)
Сьогодні в нашій "Битві підходів" розбираємо найдорожчий і найповільніший етап будь-якого E2E тестування — підготовку тестових даних (Data Setup або Preconditions). ☕️
Уявімо задачу: нам треба протестувати видалення користувача з таблиці.
❌ Підхід Junior-автоматизатора (Через UI)
Чому це архітектурна катастрофа:
✅ Підхід QA Architect (Через API)
Чому це шедевр:
Золоте правило: Інтерфейс користувача (UI) створений для тестування самого UI. Використовувати UI для підготовки даних (Preconditions) — це як забивати цвяхи мікроскопом. Для цього є API та прямі запити до бази даних.
А як у вас на проєкті генеруються дані перед E2E тестами? 👇
🔥 — Тільки API / База даних! Наші тести летять як ракета.
👀 — Робимо через UI... Так, тести йдуть по 2 години, але в нас "повна імітація юзера"!
🤬 — У нас взагалі один юзер admin@test.com на всю команду, хто перший зайшов, той і тестує!
Сьогодні в нашій "Битві підходів" розбираємо найдорожчий і найповільніший етап будь-якого E2E тестування — підготовку тестових даних (Data Setup або Preconditions). ☕️
Уявімо задачу: нам треба протестувати видалення користувача з таблиці.
❌ Підхід Junior-автоматизатора (Через UI)
test('Повинен видаляти користувача', async ({ page }) => {
// 1. Спочатку створюємо юзера через інтерфейс (марнуємо 10 секунд)
await page.locator('#add-btn').click();
await page.locator('#name').fill('Test QA');
await page.locator('#save').click();
await expect(page.locator('.toast')).toHaveText('Створено!');
// 2. І тільки тепер починаємо сам тест на ВИДАЛЕННЯ
await page.locator('#delete-btn-Test-QA').click();
await expect(page.locator('.row')).not.toContainText('Test QA');
});Чому це архітектурна катастрофа:
По-перше, ви спалюєте гроші компанії на інфраструктуру. Цей тест йтиме 15 секунд замість трьох.
По-друге, ви створюєте Каскадні падіння (Cascading Failures). Якщо завтра фронтендер випадково зламає форму створення користувача, у вас впаде тест на видалення! Ваш репорт покаже 50 червоних тестів, хоча насправді баг тільки в одному місці.
✅ Підхід QA Architect (Через API)
test('Повинен видаляти користувача', async ({ page, request }) => {
// 1. Б'ємо напряму в бекенд. Створюємо юзера за 50 мілісекунд
const res = await request.post('/api/users', { data: { name: 'Test QA' } });
const user = await res.json();
// 2. Ізольовано тестуємо ТІЛЬКИ видалення через UI
await page.goto(`/users/${user.id}`);
await page.locator(`#delete-btn-${user.id}`).click();
await expect(page.locator('.row')).not.toContainText('Test QA');
});Чому це шедевр:
Тест атомарний. Він перевіряє рівно одну фічу — видалення. Підготовка даних займає мілісекунди. Якщо форма створення зламана, цей тест все одно пройде і доведе, що механізм видалення працює ідеально.
Золоте правило: Інтерфейс користувача (UI) створений для тестування самого UI. Використовувати UI для підготовки даних (Preconditions) — це як забивати цвяхи мікроскопом. Для цього є API та прямі запити до бази даних.
А як у вас на проєкті генеруються дані перед E2E тестами? 👇
🔥 — Тільки API / База даних! Наші тести летять як ракета.
👀 — Робимо через UI... Так, тести йдуть по 2 години, але в нас "повна імітація юзера"!
🤬 — У нас взагалі один юзер admin@test.com на всю команду, хто перший зайшов, той і тестує!
❤1
📡 Tech Radar: Головне за тиждень без води (Випуск #2)
Привіт, QA Co-pilots! Понеділок — час тримати руку на пульсі. Ось що гриміло в IT минулого тижня 🔍
🔐 Масштабний злам Canvas LMS
🤖 Cloudflare скорочує 20% команди через AI
🧩 Alumnium — open-source AI-шар поверх Selenium і Playwright
⚡️ Новий стандарт для GPU-кластерів
🕵️ Критична вразливість у Palo Alto PAN-OS
💡 Думка тижня
А яка новина для вас найбільш резонує? 👇
#TechRadar #QACopilot #AITesting #Security #2026
Привіт, QA Co-pilots! Понеділок — час тримати руку на пульсі. Ось що гриміло в IT минулого тижня 🔍
🔐 Масштабний злам Canvas LMS
Група ShinyHunters зламала Instructure — компанію, що стоїть за популярною платформою для навчання Canvas.
Постраждало до 275 мільйонів записів: імена студентів, ID, емейли та повідомлення. Платформа впала якраз під час фінальних іспитів у сотнях університетів та шкіл. Для QA-спільноти — черговий сигнал, що security testing — це не "потім", а "завжди".
🤖 Cloudflare скорочує 20% команди через AI
Cloudflare оголосила про скорочення понад
1 100 людей — 20% від усього штату.
Причина: внутрішнє використання AI зросло на 600% лише за три місяці. Того ж тижня Coinbase, Upwork та BILL анонсували аналогічні скорочення.
Тренд очевидний: AI-аугментація команд прискорюється. Питання до нас: як ми адаптуємо QA-процеси, якщо генерують код вже не тільки люди?
🧩 Alumnium — open-source AI-шар поверх Selenium і Playwright
8 травня вийшов Alumnium — open-source AI-інструмент, який працює одночасно з Selenium та Playwright.
Цікавий підхід: не замінювати фреймворки, а додати AI-шар зверху. Варто поглянути.
⚡️ Новий стандарт для GPU-кластерів
OpenAI, AMD, Broadcom, Intel, Microsoft та Nvidia спільно випустили специфікацію Multipath Reliable Connection (MRC) через Open Compute Project.
Відкритий протокол підвищує стійкість та продуктивність GPU-кластерів при масштабних AI-тренуваннях. Чим більше стандартизації — тим стабільніші середовища для тестування AI-систем.
🕵️ Критична вразливість у Palo Alto PAN-OS
CVE-2026-0300 — критична вразливість у PAN-OS від Palo Alto Networks. Дозволяє виконати код віддалено з правами root без жодної авторизації через компонент User-ID Authentication Portal. Якщо у вашій інфраструктурі є Palo Alto — апдейт поза чергою.
💡 Думка тижня
Головний бар'єр у тестуванні 2026 — не швидкість виконання, а якість сигналу. AI пришвидшує генерацію тестів, але нові помилки вже важче інтерпретувати. Більше тестів ≠ більше впевненості. Наша роль як QA — не просто запускати, а розуміти, що результат означає
А яка новина для вас найбільш резонує? 👇
#TechRadar #QACopilot #AITesting #Security #2026
👍2
⚔️ Битва підходів: Junior vs. QA Architect (Page Object Model — правильна архітектура)
Сьогодні розбираємо тему, яку всі "знають", але мало хто робить правильно — Page Object Model. Різниця між Junior і Architect тут не в тому, чи використовувати POM. А в тому, що саме ховати всередині. ☕️
❌ Підхід Junior-автоматизатора (POM як "папка для локаторів")
Чому це антипатерн:
✅ Підхід QA Architect (POM як сервісний шар)
Чому це шедевр:
Золоте правило: Page Object — це не папка для локаторів. Це публічний API вашої сторінки. Якщо ваш тест досі знає про #submit або .dashboard-title — у вас не POM, у вас ілюзія абстракції.
А який рівень POM у вас на проєкті?
🔥 — Повна інкапсуляція: тести не знають жодного локатора, тільки методи
👀 — Десь між: локатори в POM є, але логіка частково тече в тести
🤬 — POM є у назві папки, але по суті — просто locator() обгорнутий в клас
Сьогодні розбираємо тему, яку всі "знають", але мало хто робить правильно — Page Object Model. Різниця між Junior і Architect тут не в тому, чи використовувати POM. А в тому, що саме ховати всередині. ☕️
❌ Підхід Junior-автоматизатора (POM як "папка для локаторів")
// pages/LoginPage.ts
export class LoginPage {
readonly page: Page;
constructor(page: Page) {
this.page = page;
}
async fillEmail(email: string) {
await this.page.locator('#email').fill(email);
}
async fillPassword(password: string) {
await this.page.locator('#password').fill(password);
}
async clickSubmit() {
await this.page.locator('#submit').click();
}
}
// tests/login.spec.ts
test('Логін з валідними даними', async ({ page }) => {
const loginPage = new LoginPage(page);
await loginPage.fillEmail('user@test.com');
await loginPage.fillPassword('qwerty123');
await loginPage.clickSubmit();
await expect(page.locator('.dashboard-title')).toBeVisible();
});
Чому це антипатерн:
По-перше: Page Object перетворився на тонку обгортку над локаторами — і нічого більше. Вся логіка взаємодії досі живе в тесті.
По-друге, тест знає забагато: він знає послідовність дій, знає що перевіряти, знає як влаштована сторінка. Якщо завтра #submit стане [data-testid="login-btn"] — йдеш шукати всі місця в тестах руками.
По-третє: такий POM не дає жодної ізоляції — це просто перейменовані page.locator() виклики.
✅ Підхід QA Architect (POM як сервісний шар)
// pages/LoginPage.ts
export class LoginPage {
private readonly emailInput = this.page.getByLabel('Email');
private readonly passwordInput = this.page.getByLabel('Password');
private readonly submitButton = this.page.getByRole('button', { name: 'Sign in' });
private readonly errorMessage = this.page.getByTestId('auth-error');
constructor(private readonly page: Page) {}
// Публічний API сторінки — одна дія, один метод
async login(email: string, password: string): Promise<void> {
await this.emailInput.fill(email);
await this.passwordInput.fill(password);
await this.submitButton.click();
}
async expectErrorMessage(text: string): Promise<void> {
await expect(this.errorMessage).toHaveText(text);
}
}
// pages/DashboardPage.ts
export class DashboardPage {
private readonly title = this.page.getByRole('heading', { name: 'Dashboard' });
constructor(private readonly page: Page) {}
async expectLoaded(): Promise<void> {
await expect(this.title).toBeVisible();
}
}
// tests/login.spec.ts
test('Логін з валідними даними', async ({ page }) => {
const loginPage = new LoginPage(page);
const dashboardPage = new DashboardPage(page);
await loginPage.login('user@test.com', 'qwerty123');
await dashboardPage.expectLoaded();
});
test('Логін з невалідним паролем', async ({ page }) => {
const loginPage = new LoginPage(page);
await loginPage.login('user@test.com', 'wrongpass');
await loginPage.expectErrorMessage('Invalid credentials');
});
Чому це шедевр:
Тест читається як специфікація, а не як інструкція для браузера. Page Object інкапсулює всю логіку взаємодії — тест не знає жодного локатора.
Локатори побудовані на семантиці (getByRole, getByLabel) — стійкі до рефакторингу верстки. Assertions теж живуть у Page Object — тест перевіряє поведінку, а не деталі реалізації. Зміна UI = правка в одному файлі, а не хірургія по всьому репозиторію.
Золоте правило: Page Object — це не папка для локаторів. Це публічний API вашої сторінки. Якщо ваш тест досі знає про #submit або .dashboard-title — у вас не POM, у вас ілюзія абстракції.
А який рівень POM у вас на проєкті?
🔥 — Повна інкапсуляція: тести не знають жодного локатора, тільки методи
👀 — Десь між: локатори в POM є, але логіка частково тече в тести
🤬 — POM є у назві папки, але по суті — просто locator() обгорнутий в клас
🧨 Руйнівники IT-міфів #1 МІФ: "QA гальмує розробку"
Привіт, екіпаж! Сьогодні беремо найпопулярніше виправдання для скорочення QA-команд і кладемо його на стіл розтину. Не думки, не відчуття — тільки цифри. ☕️
🧠 Звідки міф?
🔬 Що кажуть дані
📐 Математика для скептиків
💡 Як змінити фрейм в голові у стейкхолдера
А як у вас реагують на QA в команді?
🔥 — QA — повноцінні партнери, нас залучають з першого дня спринту
👀 — "Ну давайте швиденько протестуємо перед релізом"
🤯 — "Нащо QA, у нас розробники самі тестують"
Привіт, екіпаж! Сьогодні беремо найпопулярніше виправдання для скорочення QA-команд і кладемо його на стіл розтину. Не думки, не відчуття — тільки цифри. ☕️
🧠 Звідки міф?
Продакт дивиться на спринт: розробники кодять, QA "знаходить проблеми" і повертає задачі назад. Здається, що QA — це та ланка, яка сповільнює потік. Логіка зрозуміла. Логіка хибна.
🔬 Що кажуть дані
1️⃣ Правило ×100 (IBM Systems Sciences Institute):
Виправлення дефекту на стадії дизайну коштує в 6 разів дешевше, ніж під час імплементації. Той самий баг, знайдений після релізу в продакшені — у 100 разів дорожче, ніж на стадії підтримки.
2️⃣ Простими числами: баг вартістю $100 на етапі планування → $10 000 у продакшені — бо він тягне за собою каскадні ефекти в суміжних системах, потребує координації між командами і затримує наступні релізи.
3️⃣ Вартість простою:
Для enterprise-компаній середня вартість однієї години критичного даунтайму перевищує $300 000. Деякі інциденти легко перетинають позначку $1 млн на годину.
4️⃣Реальний кейс з фінтеху:
Баг у заокругленні, знайдений QA на стадії тестування, обійшовся у 4 години роботи ($400). Той самий тип помилки, що потрапила у прод, зачепила 12 000 транзакцій — і потягнула за собою екстрений патч, звірку даних і регуляторне розкриття.
5️⃣ Де насправді губиться час розробників:
Dev-команди витрачають у середньому 30–50% свого часу на виправлення багів і незапланований rework. Це не QA гальмує — це баги без QA з'їдають половину capacity команди.
📐 Математика для скептиків
Правильно побудована QA-програма для команди з 20 розробників коштує $120 000–180 000 на рік. Математика зазвичай виправдовує себе вже в перший квартал.
Один інцидент з checkout-сторінкою на e-commerce з трафіком $500K/день при 2% відмов — це $10 000 на день прямих втрат. Тиждень без виявлення — $70 000.
Висновок: QA не уповільнює розробку. QA уповільнює потрапляння дефектів у прод — а це принципово різні речі.
💡 Як змінити фрейм в голові у стейкхолдера
Не "QA знайшов 12 багів і повернув задачу".
А — "QA зекономив команді 3 тижні рефакторингу і $200K потенційних втрат".
QA — це не гальмо. Це страховий поліс, який окупається щоразу, коли ти його не використовуєш. 🛡
А як у вас реагують на QA в команді?
🔥 — QA — повноцінні партнери, нас залучають з першого дня спринту
👀 — "Ну давайте швиденько протестуємо перед релізом"
🤯 — "Нащо QA, у нас розробники самі тестують"
🧩 Задачка з Senior-співбесіди: Мандрівки в часі ⏳
Сьогодні говоримо про фічі, які змушують нас чекати. Час — наш головний ворог у CI/CD, особливо коли бізнес-логіка жорстко зав'язана на таймери, календарі або терміни дії токенів. ☕️
Умова задачі:
Питання:
Голосуйте нижче! А розгорнуте пояснення, чому перші два варіанти гарантовано призведуть до "почервоніння" сусідніх тестів або витоків пам'яті, я залишу в коментарях ввечері. 👇
Сьогодні говоримо про фічі, які змушують нас чекати. Час — наш головний ворог у CI/CD, особливо коли бізнес-логіка жорстко зав'язана на таймери, календарі або терміни дії токенів. ☕️
Умова задачі:
Маємо Angular-додаток зі сторінкою акцій.
Бізнес-вимога: "Користувач бачить банер 'Знижка 50%', який діє рівно 24 години з моменту реєстрації".
Логіка відліку реалізована на фронтенді — компонент звіряє поточний час браузера з датою закінчення акції. Якщо минуло 24 години і 1 секунда — банер має зникнути.
Питання:
Як перевірити зникнення банера через 24 години в E2E-тесті на Playwright, щоб тест пройшов за секунду, був стабільним і не зламав інфраструктуру?
Голосуйте нижче! А розгорнуте пояснення, чому перші два варіанти гарантовано призведуть до "почервоніння" сусідніх тестів або витоків пам'яті, я залишу в коментарях ввечері. 👇
Як перевірити зникнення банера через 24 години в E2E-тесті на Playwright, щоб тест пройшов за секунду, був стабільним і не зламав інфраструктуру?
Anonymous Quiz
20%
1️⃣ Змінити системний час на самій віртуальній машині в CI/CD
10%
2️⃣ Заінжектити кастомний JS-мок для window.Date через addInitScript
70%
3️⃣ Використати нативний API Playwright: page.clock.advance()
🕵️♂️ Інженерний детектив: Справа про прозорий бар'єр (або Гріх force: true)
Привіт, екіпаж! Середа — час нашої рубрики «Інженерний детектив». Сьогодні ми розслідуємо "злочин", через який автоматизатори втрачають нерви, а девелопери божаться, що «на локалці все працює ідеально». ☕️
Сцена злочину (Симптоми):
❌ Хибний слід (Як робить Джун):
🔍 Хід розслідування (Що сталося насправді):
Ось він, вбивця! Фронтендер зробив плавне зникнення лоадера. Візуально він став повністю прозорим
Коли джун використав force: true, він змусив Playwright проігнорувати закони фізики і відправити JavaScript-івент click напряму в кнопку крізь скло. Але реальний користувач пальцем чи курсором так не зможе — він клікатиме по прозорому лоадеру.
✅ Вирок та Рішення:
Золоте правило: Якщо Playwright не може кудись клікнути — у 99% випадків реальний юзер теж не зможе. Автотест знайшов реальний баг UI/UX, а ви ледь не сховали його за force: true.
Зізнавайтесь, часто грішили форсованими кліками, щоб "швидко пофіксити" падаючий тест? 👇
🔥 — Було діло, грішний.
👀 — Тільки toBeHidden(), я за чистий код!
🤯 — Пішов перевіряти свої тести, здається, я пропустив прозорий банер на проді...
Привіт, екіпаж! Середа — час нашої рубрики «Інженерний детектив». Сьогодні ми розслідуємо "злочин", через який автоматизатори втрачають нерви, а девелопери божаться, що «на локалці все працює ідеально». ☕️
Сцена злочину (Симптоми):
Ви написали базовий тест на авторизацію. У вас локально все літає. Закидаєте в CI/CD — тест періодично падає на елементарному кроці:
Error: locator.click(): Element <button id="submit">Login</button> is intercepted by <div class="spinner-overlay"></div>
Ви відкриваєте Playwright Trace Viewer, дивитесь на скріншот у момент падіння... і не розумієте. Екран абсолютно чистий. Кнопка Login ідеально видима, ніякого лоадера (spinner-overlay) поверх неї немає. Містика?
❌ Хибний слід (Як робить Джун):
"Дурний фреймворк" — думає джун і вписує магічну пігулку:
await page.locator('#submit').click({ force: true }).
Тест миттєво стає зеленим. Джун задоволено закриває таску. А через тиждень сапорт розривається від скарг реальних користувачів, які не можуть натиснути кнопку логіну.
🔍 Хід розслідування (Що сталося насправді):
Playwright ніколи не бреше. На відміну від старого Selenium, він намагається діяти як жива людина з реальною мишкою. Якщо він каже, що клік перехоплено, значить кнопка накрита чимось фізичним.
Ми йдемо у вихідний код фронтенду (у наш улюблений Angular) і дивимось на CSS цього лоадера. Знаходимо там такий код:
.spinner-overlay.hidden {
opacity: 0;
transition: opacity 0.5s ease;
}Ось він, вбивця! Фронтендер зробив плавне зникнення лоадера. Візуально він став повністю прозорим
(opacity: 0), але фізично він залишився висіти в DOM-дереві, перекриваючи весь екран як невидиме броньоване скло!Коли джун використав force: true, він змусив Playwright проігнорувати закони фізики і відправити JavaScript-івент click напряму в кнопку крізь скло. Але реальний користувач пальцем чи курсором так не зможе — він клікатиме по прозорому лоадеру.
✅ Вирок та Рішення:
1️⃣ Лікуємо фронтенд: Йдемо до розробника і просимо додати класу .hidden властивість pointer-events: none; (щоб кліки проходили крізь нього) або взагалі прибирати лоадер з DOM за допомогою *ngIf.
2️⃣ Лікуємо тести: Ніколи не використовуйте force: true, щоб обійти помилку intercepted. Замість цього явно дочекайтеся, поки оверлей зникне фізично:
await expect(page.locator('.spinner-overlay')).toBeHidden();
Золоте правило: Якщо Playwright не може кудись клікнути — у 99% випадків реальний юзер теж не зможе. Автотест знайшов реальний баг UI/UX, а ви ледь не сховали його за force: true.
Зізнавайтесь, часто грішили форсованими кліками, щоб "швидко пофіксити" падаючий тест? 👇
🔥 — Було діло, грішний.
👀 — Тільки toBeHidden(), я за чистий код!
🤯 — Пішов перевіряти свої тести, здається, я пропустив прозорий банер на проді...
❤1
🗂 Ультимативна шпаргалка: Локатори Playwright (2018 vs 2026)
Коротка шпаргалка про те, як відучити себе писати "крихкі" тести. Зберігайте в обране і кидайте на код-рев'ю. ☕️
❌ Застарілий підхід (CSS / XPath) ✅ Сучасний підхід (User-Facing API)
1️⃣ Кнопки та посилання
Чому: Перевіряє не лише текст, а й доступність (Accessibility). Якщо розробник випадково зробить кнопку div-ом, тест впаде.
2️⃣ Пошук статичного тексту
Чому: Працює незалежно від того, як фронтендер перетасує div та span у компоненті.
3️⃣ Специфічні блоки (картки, аватари)
Чому: CSS-класи належать дизайнерам (вони їх змінюють). Атрибути data-testid належать QA — їх ніхто не чіпає.
4️⃣ Точковий пошук у списках/таблицях (Chaining)
Чому: Читається як звичайна англійська мова, нуль магії.
Золоте правило: Шукайте елементи так, як їх шукає реальний юзер (за текстом та роллю), а не так, як їх бачить браузер (за селекторами).
А на чому сидите ви? 👇
🔥 — Тільки getByRole та getByText, класика.
👀 — Мій бестфренд — це data-testid.
🤬 — Я фанат XPath, мене вже не перевчити!
Коротка шпаргалка про те, як відучити себе писати "крихкі" тести. Зберігайте в обране і кидайте на код-рев'ю. ☕️
❌ Застарілий підхід (CSS / XPath) ✅ Сучасний підхід (User-Facing API)
1️⃣ Кнопки та посилання
❌ page.locator('.btn-primary.submit')
✅ page.getByRole('button', { name: 'Зберегти' })
Чому: Перевіряє не лише текст, а й доступність (Accessibility). Якщо розробник випадково зробить кнопку div-ом, тест впаде.
2️⃣ Пошук статичного тексту
❌ page.locator('//div/span[contains(text(), "Успіх")]')
✅ page.getByText('Успіх', { exact: true })
Чому: Працює незалежно від того, як фронтендер перетасує div та span у компоненті.
3️⃣ Специфічні блоки (картки, аватари)
❌ page.locator('.user-card .avatar-img')
✅ page.getByTestId('user-avatar')
Чому: CSS-класи належать дизайнерам (вони їх змінюють). Атрибути data-testid належать QA — їх ніхто не чіпає.
4️⃣ Точковий пошук у списках/таблицях (Chaining)
❌ page.locator('.table-row:has-text("Ivan") >> .delete-btn')
✅ page.getByRole('row', { name: 'Ivan' }).getByRole('button', { name: 'Видалити' })
Чому: Читається як звичайна англійська мова, нуль магії.
Золоте правило: Шукайте елементи так, як їх шукає реальний юзер (за текстом та роллю), а не так, як їх бачить браузер (за селекторами).
А на чому сидите ви? 👇
🔥 — Тільки getByRole та getByText, класика.
👀 — Мій бестфренд — це data-testid.
🤬 — Я фанат XPath, мене вже не перевчити!
🔥 Прожарка інструментів: Cucumber (і казки про BDD)
Привіт, екіпаж! Четвер — час нашої безжальної прожарки. Сьогодні кидаємо на гриль інструмент, який обіцяв нам ідеальний світ, де нетехнічні менеджери самі пишуть автотести зрозумілою мовою. Зустрічайте головного пожирача часу — Cucumber (Gherkin). ☕️
🟢 Як нам це продавали (Очікування):
"Ви пишете тести у форматі Given / When / Then. Бізнес-аналітики, мануальники та клієнти читають їх, як книгу, і всі щасливі!"
🥩 Прожарка (Сувора реальність):
⚖️ Вердикт QA Co-pilot:
А ви були в секті BDD? 👇
🔥 — На жаль, так... Пишу Given/When/Then і плачу.
👀 — Випиляли Cucumber рік тому, пайплайни стали літати!
🤬 — Не згоден, у нас замовник РЕАЛЬНО сам читає тести! (Ви взагалі існуєте?)
Привіт, екіпаж! Четвер — час нашої безжальної прожарки. Сьогодні кидаємо на гриль інструмент, який обіцяв нам ідеальний світ, де нетехнічні менеджери самі пишуть автотести зрозумілою мовою. Зустрічайте головного пожирача часу — Cucumber (Gherkin). ☕️
🟢 Як нам це продавали (Очікування):
"Ви пишете тести у форматі Given / When / Then. Бізнес-аналітики, мануальники та клієнти читають їх, як книгу, і всі щасливі!"
🥩 Прожарка (Сувора реальність):
Бізнесу байдуже: Давайте чесно. Жоден продакт-менеджер у здоровому глузді не відкриває ваш репозиторій на GitHub. Їм потрібен зелений статус у пайплайні, а не ваші поеми.
Подвійний податок на підтримку: Щоб клікнути одну кнопку, ви пишете текст у .feature файлі. Потім пишете регулярний вираз (@When("^I click...$")), щоб зв'язати текст із кодом. І лише потім — сам код кліку. Змінився дизайн? Переписуйте всі три шари.
Жах зі складними даними: Спробуйте передати багаторівневий JSON або масив динамічних об'єктів через текстовий Gherkin-файл. Ваш код перетвориться на гігантські милиці з нечитабельними таблицями.
⚖️ Вердикт QA Co-pilot:
Якщо ви стартуєте проєкт у 2026-му — залиште Cucumber в епосі 2015-го. Хочете, щоб бізнес розумів, що перевіряє тест? Використовуйте test.step() у Playwright та прикрутіть Allure Report. Пишіть код кодом, а документацію залиште для Confluence.
А ви були в секті BDD? 👇
🔥 — На жаль, так... Пишу Given/When/Then і плачу.
👀 — Випиляли Cucumber рік тому, пайплайни стали літати!
🤬 — Не згоден, у нас замовник РЕАЛЬНО сам читає тести! (Ви взагалі існуєте?)
💯1
🔍 Рентген співбесіди: «Ми вам передзвонимо» або що насправді шукає рекрутер
Буває так: ти розклав по поличках роботу Playwright, пояснив різницю між Promise.all та Promise.allSettled, і навіть задизайнив фреймворк на ходу. Але в кінці отримуєш стандартне «дякуємо, ми на зв'язку».
Давайте «просвітимо» рентгеном, які приховані патології в софт-скілах або технічних відповідях найчастіше стають причиною відмови.
🦴 «Скелет в шафі» технічного боргу
🧪 «Магічне» тестування (No-Code ілюзія)
🧬 Ізоляція замість інтеграції
🚩 Red Flags на знімку:
Порада дня: Співбесіда — це не допит, а перевірка сумісності твого «коду» з культурою команди. Будь як той архітектор з майбутнього: спокійним, впевненим і завжди з чітким планом автоматизації.
А які «діагнози» ставили вам на співбесідах? Пишіть у коментарях! 👇
#QA #AQA #Testing #Interview #Career #Playwright #Angular
Буває так: ти розклав по поличках роботу Playwright, пояснив різницю між Promise.all та Promise.allSettled, і навіть задизайнив фреймворк на ходу. Але в кінці отримуєш стандартне «дякуємо, ми на зв'язку».
Давайте «просвітимо» рентгеном, які приховані патології в софт-скілах або технічних відповідях найчастіше стають причиною відмови.
🦴 «Скелет в шафі» технічного боргу
Коли тебе питають про архітектуру, а ти розповідаєш лише про те, як писати селектори. Рекрутер бачить не Middle AQA, а людину, яка просто автоматизує ручні кейси без розуміння стратегії.
🔹Діагноз: Відсутність системного мислення.
🔹Лікування: Говори про CI/CD, звіти, інтеграцію з Test IT та обробку флекі-тестів за допомогою ретраїв.
🧪 «Магічне» тестування (No-Code ілюзія)
Якщо ти занадто сильно покладаєшся на ШІ-інструменти або no-code рішення, не розуміючи, як вони працюють «під капотом», на рентгені це виглядає як купа іржавих шестерень, заклеєних синьою ізолентою.
🔹Діагноз: Низька технічна експертиза.
🔹Лікування: Покажи, що ти знаєш DOM-дерево Angular краще за будь-який дрон, і можеш написати чистий код навіть на серветці.
🧬 Ізоляція замість інтеграції
Кандидат ідеально знає свій «чорний ящик» API, але поняття не має, як дані потрапляють з фронтенда в БД або як працює аутентифікація через Bearer токени.
🔹Діагноз: Обмежений кругозір.
🔹Лікування: Вивчай DevTools як свої п'ять пальців — від нетворк-графів до спуфінгу геолокації.
🚩 Red Flags на знімку:
🔹Хардкод таймаути: Якщо на питання про очікування ти кажеш await page.waitForTimeout(5000), десь у світі сумує один лід.
🔹Ігнорування витоків пам'яті: Тести проходять, але браузер «зжирає» всю RAM на сервері? Рентген покаже це як «цифрових привидів», що душать твоє залізо.
Порада дня: Співбесіда — це не допит, а перевірка сумісності твого «коду» з культурою команди. Будь як той архітектор з майбутнього: спокійним, впевненим і завжди з чітким планом автоматизації.
А які «діагнози» ставили вам на співбесідах? Пишіть у коментарях! 👇
#QA #AQA #Testing #Interview #Career #Playwright #Angular
💯2
💩 Код з душком: Перехресне запилення, або Чому ваші тести падають у CI/CD
Привіт, екіпаж! П'ятниця — час для генерального прибирання у ваших репозиторіях. Сьогодні ми препаруємо одну з найнебезпечніших інженерних хвороб — sharing state (обмін станом) між тестами. Це той випадок, коли ви використовуєте глобальні змінні для передачі даних від одного тесту до іншого. ☕️
Знайдіть проблему в цьому коді:
Чому цей код тхне:
✅ Як це виглядає після код-рев'ю Senior-інженера:
Золоте правило: Кожен тест має бути повністю атомарним. Тест має сам створювати потрібні дані, виконувати дію і сам за собою прибирати (якщо це необхідно). Жодних глобальних змінних для передачі даних!
А ваші тести бігають у паралель, чи ви боїтесь, що вони "перепиляться" даними? 👇
🔥 — Тільки атомарні тести, тільки паралельний запуск!
👀 — Грішимо глобальними змінними, тому запускаємо по одному...
🤯 — Мої тести впали вчора, тепер я знаю чому!
Привіт, екіпаж! П'ятниця — час для генерального прибирання у ваших репозиторіях. Сьогодні ми препаруємо одну з найнебезпечніших інженерних хвороб — sharing state (обмін станом) між тестами. Це той випадок, коли ви використовуєте глобальні змінні для передачі даних від одного тесту до іншого. ☕️
Знайдіть проблему в цьому коді:
// ❌ Як пишуть джуни (Антипатерн "Глобальний наркоман")
// Десь у глобальному скоупі файлу
let lastCreatedUserId: string;
test('Тест 1: Створити юзера', async ({ request }) => {
const newUser = await request.post('/api/users', { data: { name: 'Bro' } });
// Зберігаємо ID у глобальну змінну для наступного тесту
lastCreatedUserId = (await newUser.json()).id;
});
test('Тест 2: Видалити створеного юзера', async ({ request }) => {
// Використовуємо ID, який створив ПОПЕРЕДНІЙ тест
await request.delete(`/api/users/${lastCreatedUserId}`);
});
Чому цей код тхне:
На вашій локальній машині це може працювати. Але в CI/CD Playwright за замовчуванням запускає тести паралельно (в різних воркерах/процесах).
Коли воркер №2 почне виконувати «Тест 2», глобальна змінна lastCreatedUserId у його процесі буде порожньою (undefined), бо «Тест 1» виконувався в іншому воркері №1. У вас "червоний" пайплайн, а ви витрачаєте пів дня, намагаючись зрозуміти, чому тест на видалення не бачить ID.
✅ Як це виглядає після код-рев'ю Senior-інженера:
// Ідеально чистий код (Повна атомарність)
test('Повинен видаляти користувача', async ({ request }) => {
// 1. Створюємо юзера ІЗОЛЬОВАНО всередині одного тесту
const newUser = await request.post('/api/users', { data: { name: 'IsolatedBro' } });
const userId = (await newUser.json()).id;
// 2. Використовуємо ID тут же
await request.delete(`/api/users/${userId}`);
});
Золоте правило: Кожен тест має бути повністю атомарним. Тест має сам створювати потрібні дані, виконувати дію і сам за собою прибирати (якщо це необхідно). Жодних глобальних змінних для передачі даних!
А ваші тести бігають у паралель, чи ви боїтесь, що вони "перепиляться" даними? 👇
🔥 — Тільки атомарні тести, тільки паралельний запуск!
👀 — Грішимо глобальними змінними, тому запускаємо по одному...
🤯 — Мої тести впали вчора, тепер я знаю чому!
🔥2❤1
П'ятниця: Час деплоїти... себе в паб! 🍻
Робочий тиждень офіційно переходить у статус «Done». Реліз-кандидат тижня готовий, баги дбайливо перенесені в беклог на понеділок, а це значить — час для справжнього офлайн-нетворкінгу. ☕️
Якраз до п'ятниці я випустив трек про легендарний Портер Паб — місце, де було випито тисячі літрів пива під обговорення архітектури та падаючих пайплайнів. 🎸
Слухаємо, заряджаємось і йдемо відпочивати. Зустрінемось за баром!
https://youtu.be/95i7fPiNaZE?si=n4TCjaD4swKUqEeK
Робочий тиждень офіційно переходить у статус «Done». Реліз-кандидат тижня готовий, баги дбайливо перенесені в беклог на понеділок, а це значить — час для справжнього офлайн-нетворкінгу. ☕️
Якраз до п'ятниці я випустив трек про легендарний Портер Паб — місце, де було випито тисячі літрів пива під обговорення архітектури та падаючих пайплайнів. 🎸
Слухаємо, заряджаємось і йдемо відпочивати. Зустрінемось за баром!
https://youtu.be/95i7fPiNaZE?si=n4TCjaD4swKUqEeK
YouTube
VEYMIR — Портер Паб (Official Audio) | Український Рок 2026
Офіційна аудіо-прем'єра треку «Портер Паб» від VEYMIR! 🎸🍻
Цей трек — гімн для всіх, хто втомився від пафосу і гламуру. Це пісня про те саме місце, де можна просто сісти за дерев'яний стіл, замовити кухоль пива і видихнути після важкого тижня. Окремий респект…
Цей трек — гімн для всіх, хто втомився від пафосу і гламуру. Це пісня про те саме місце, де можна просто сісти за дерев'яний стіл, замовити кухоль пива і видихнути після важкого тижня. Окремий респект…
🧨 Руйнівники IT-міфів: "Покриємо все E2E тестами і будемо спати спокійно"
Привіт, екіпаж! Сьогодні розбираємо найдорожчу ілюзію, яку часто намагаються продати бізнесу, або в яку вірять автоматизатори на початку кар'єри. ☕️
❌ Міф: "Нам треба стовідсоткове покриття! Давайте напишемо автотести на Playwright/Cypress для всіх можливих сценаріїв: кожну валідацію поля, кожну помилку сервера, кожен тултип. Чим більше UI-тестів, тим якісніший продукт!"
💥 Реальність (Бум!):
Вітаю, ви щойно побудували антипатерн «Ріжок морозива» (Ice Cream Cone) замість Піраміди тестування. Це інфраструктурне самогубство.
✅ Як має бути (Підхід Архітектора):
Золоте правило: E2E тестування створене не для глибокого пошуку багів у логіці, а лише для перевірки того, чи правильно "склеїлися" фронтенд і бекенд.
А як виглядає ваша стратегія тестування? 👇
🔥 — Тільки критичні флоу в UI, решта — на API/Unit!
👀 — У нас "ріжок морозива", пайплайн іде дві години...
🤯 — Але ж тільки UI тестує так, як бачить реальний юзер!
Привіт, екіпаж! Сьогодні розбираємо найдорожчу ілюзію, яку часто намагаються продати бізнесу, або в яку вірять автоматизатори на початку кар'єри. ☕️
❌ Міф: "Нам треба стовідсоткове покриття! Давайте напишемо автотести на Playwright/Cypress для всіх можливих сценаріїв: кожну валідацію поля, кожну помилку сервера, кожен тултип. Чим більше UI-тестів, тим якісніший продукт!"
💥 Реальність (Бум!):
Вітаю, ви щойно побудували антипатерн «Ріжок морозива» (Ice Cream Cone) замість Піраміди тестування. Це інфраструктурне самогубство.
Повільність: 500 важких UI-тестів будуть крутитися в CI/CD годинами, блокуючи релізи та з'їдаючи гроші на сервери.
Крихкість: UI — це найнестабільніший шар. Дизайнер змінив відступ, фронтендер переписав компонент — і у вас «почервоніло» 50 тестів, хоча бізнес-логіка працює.
Пекельна підтримка: Ви будете витрачати 80% часу на лагодження старих тестів, а не на покриття нових фіч.
✅ Як має бути (Підхід Архітектора):
E2E (UI) тести — це снайперська гвинтівка, а не кулемет. Через UI покриваються тільки критичні бізнес-шляхи (Happy Paths): реєстрація, чекаут, оплата.
Усі перевірки граничних значень (50 варіантів невалідного пароля, розрахунки знижок чи статуси помилок) мають тестуватися на рівнях API та Unit-тестів. Вони надійні і виконуються за мілісекунди.
Золоте правило: E2E тестування створене не для глибокого пошуку багів у логіці, а лише для перевірки того, чи правильно "склеїлися" фронтенд і бекенд.
А як виглядає ваша стратегія тестування? 👇
🔥 — Тільки критичні флоу в UI, решта — на API/Unit!
👀 — У нас "ріжок морозива", пайплайн іде дві години...
🤯 — Але ж тільки UI тестує так, як бачить реальний юзер!
❤1
🕵️♂️ Інженерний детектив: Справа про "Баг Попелюшки" (або Тести, що перетворюються на гарбуз)
Привіт, екіпаж! Сьогодні розслідуємо містику найвищого рівня. Це баг, через який сивіють навіть досвідчені ліди, бо він ламає всі закони логіки і змушує сумніватися у власній адекватності. ☕️
Сцена злочину (Симптоми):
❌ Хибний слід (Як робить Джун):
🔍 Що сталося насправді (Timezone Mismatch):
✅ Вирок та Рішення:
Альтернатива: Перевести і локальні тести, і CI/CD у суворий UTC. Головне — синхронізація.
А ваші тести вже ставали "гарбузом" опівночі? 👇
🔥 — Давно захардкодив таймзону в конфігу, сплю спокійно!
👀 — Було таке... Довго не міг зрозуміти, чому падає тільки вночі.
🤯 — Пішов перевіряти свій playwright.config.ts від гріха подалі.
Привіт, екіпаж! Сьогодні розслідуємо містику найвищого рівня. Це баг, через який сивіють навіть досвідчені ліди, бо він ламає всі закони логіки і змушує сумніватися у власній адекватності. ☕️
Сцена злочину (Симптоми):
Ви написали автотест, який перевіряє створення звіту за "сьогодні" або дату народження у профілі. Запускаєте локально — працює ідеально.
Пушите в репозиторій, CI/CD світиться зеленим. Ви спокійно йдете спати.
Але о 23:00 (чи о 01:00 ночі) пайплайн раптом починає горіти червоним! А наступного ранку ви запускаєте його знову без жодної зміни в коді — і він знову стає зеленим. Що за полтергейст?
❌ Хибний слід (Як робить Джун):
Джун дивиться в логи і бачить:
Expected: "20-05-2026", Received: "19-05-2026".
Він вирішує, що бекенд просто лагає при зміні діб, додає в Playwright retries: 3 або, що ще гірше, хардкодить +1 день у розрахунок дати, сподіваючись, що "тепер точно зійдеться". Спойлер: вдень тест впаде знову.
🔍 Що сталося насправді (Timezone Mismatch):
Ваші тести стали жертвою часових поясів. Ви сидите за ноутом і ваш локальний час — за Києвом (EEST, UTC+3). Ваша функція new Date() бере поточну дату вашої машини.
Але ваш CI/CD сервер (наприклад, GitHub Actions) за замовчуванням крутиться в UTC+0!
Коли у вас 01:00 ночі 20 травня, на сервері ще тільки 22:00 попереднього дня (19 травня).
Сервер генерує вчорашню дату, а UI-додаток (який часто бере локаль браузера) намагається порівняти її з сьогоднішньою. Відбувається розсинхрон, і тест падає.
✅ Вирок та Рішення:
Автотести не повинні залежати від того, де фізично запущений браузер — у Києві, Лондоні чи Токіо.
Часовий пояс має бути захардкоджений на рівні всього фреймворку.
Йдемо в playwright.config.ts і жорстко фіксуємо таймзону та локаль:
use: {
// Тепер ваш браузер у CI/CD завжди "думатиме", що він у Києві
timezoneId: 'Europe/Kyiv',
locale: 'uk-UA',
}Альтернатива: Перевести і локальні тести, і CI/CD у суворий UTC. Головне — синхронізація.
А ваші тести вже ставали "гарбузом" опівночі? 👇
🔥 — Давно захардкодив таймзону в конфігу, сплю спокійно!
👀 — Було таке... Довго не міг зрозуміти, чому падає тільки вночі.
🤯 — Пішов перевіряти свій playwright.config.ts від гріха подалі.
❤1
🔥 Прожарка інструментів: Cypress (або Життя в одній вкладці)
Привіт, екіпаж! Четвер — час розпалювати гриль. Сьогодні на нашій решітці інструмент, який колись врятував нас від жахіть старого Selenium, але у 2026 році сам поступово перетворюється на неповоротке легасі. Зустрічайте — Cypress. ☕️
🟢 Як нам це продавали (Очікування):
"Ми працюємо прямо всередині браузера! Більше ніяких WebDriver-ів! У нас найзручніший синтаксис та красивий Dashboard. Автоматизація тепер — це суцільне свято!"
🥩 Прожарка (Сувора реальність):
⚖️ Вердикт QA Co-pilot:
Зізнавайтесь, як у вас стосунки з "Кіпарисом"? 👇
🔥 — Давно мігрував на Playwright, вільно дихаю у багатьох вкладках!
👀 — У нас гігантський фреймворк на Cypress, переписати це вже нереально...
🤬 — Не чіпайте Cypress, його .then() — це мистецтво!
Привіт, екіпаж! Четвер — час розпалювати гриль. Сьогодні на нашій решітці інструмент, який колись врятував нас від жахіть старого Selenium, але у 2026 році сам поступово перетворюється на неповоротке легасі. Зустрічайте — Cypress. ☕️
🟢 Як нам це продавали (Очікування):
"Ми працюємо прямо всередині браузера! Більше ніяких WebDriver-ів! У нас найзручніший синтаксис та красивий Dashboard. Автоматизація тепер — це суцільне свято!"
🥩 Прожарка (Сувора реальність):
🔹Ілюзія асинхронності: Ви дивитесь на код і бачите cy.get(). Хочете просто витягнути текст у змінну через сучасний await? Забудьте. Cypress використовує власну "магічну" чергу команд. Замість чистого TypeScript ви отримуєте "Callback-пекло" з нескінченними .then(), які неможливо нормально дебажити нативними засобами вашої IDE.
🔹Браузерна клаустрофобія: Ваш юзер клікає на посилання, яке відкриває платіжний шлюз у новій вкладці? Cypress каже: "Вибач, я живу тільки в одній табі. Просто видали атрибут target="_blank" через JS і роби вигляд, що все нормально". А тестування складних крос-доменних iframe досі нагадує шаманські обряди.
🔹Монетизація повітря: Хочете паралельний запуск тестів (sharding) у CI/CD, щоб пайплайн не йшов годину? Cypress Cloud виставить вам такий рахунок за інфраструктуру, що бізнес заплаче. І це в той час, коли Playwright шардить тести безкоштовно "з коробки".
⚖️ Вердикт QA Co-pilot:
Cypress був справжньою революцією 5 років тому і зробив багато хорошого для індустрії. Він досі може бути зручним для компонентного тестування (наприклад, якщо розробники пишуть тести прямо поруч зі своїм Angular-кодом).
Але для складного E2E-тестування сучасних додатків його архітектурні обмеження — це зашморг на шиї вашого CI/CD.
Зізнавайтесь, як у вас стосунки з "Кіпарисом"? 👇
🔥 — Давно мігрував на Playwright, вільно дихаю у багатьох вкладках!
👀 — У нас гігантський фреймворк на Cypress, переписати це вже нереально...
🤬 — Не чіпайте Cypress, його .then() — це мистецтво!
👍1
💩 Код з душком: If/Else у тестах (або Тест із роздвоєнням особистості)
Привіт, екіпаж! П'ятниця — традиційний час вивітрювати "смердючий" код з репозиторіїв. Сьогодні препаруємо гріх, який перетворює ваші автотести на непередбачуваний хаос. Поговоримо про умовну логіку (Conditional Testing). ☕️
Знайдіть проблему в цьому тесті:
Чому цей код тхне:
✅ Як це виглядає після код-рев'ю Senior-інженера:
Тест має бути прямою лінією. Якщо банер можна відключити (через cookie або API-мок) — відключаємо. Якщо ж це неконтрольований поп-ап, використовуємо нативну "магію" Playwright 1.42+:
Золоте правило: Ніколи не використовуйте if / else для синхронізації UI чи обробки випадкових елементів на сторінці. Автотест — це не алгоритм пошуку шляху, це жорсткий сценарій. Контролюйте стан додатка, а для асинхронних перешкод делегуйте роботу фреймворку.
А скільки if'ів зараз заховано у вашому фреймворку? 👇
🔥 — Використовую addLocatorHandler, мої тести прямі як стріла!
👀 — Грішу іф-елсами, бо на проді постійно лізуть рандомні банери...
🤯 — Тепер я зрозумів, чому мої тести періодично падають на кліках!
Привіт, екіпаж! П'ятниця — традиційний час вивітрювати "смердючий" код з репозиторіїв. Сьогодні препаруємо гріх, який перетворює ваші автотести на непередбачуваний хаос. Поговоримо про умовну логіку (Conditional Testing). ☕️
Знайдіть проблему в цьому тесті:
// ❌ Як пишуть джуни (Антипатерн "Ворожка")
test('Повинен додати товар у кошик', async ({ page }) => {
await page.goto('/product/123');
// "Якщо раптом вилізе промо-банер, то закриємо його..."
if (await page.locator('.promo-popup').isVisible()) {
await page.locator('.close-promo').click();
}
await page.locator('.add-to-cart').click();
});
Чому цей код тхне:
Ви щойно вбили детермінованість тесту (його передбачуваність). Метод isVisible() у Playwright не чекає! Він стріляє миттєво.
Якщо ваш фронтенд на Angular рендерить цей поп-ап за 300 мілісекунд, на момент перевірки isVisible() поверне false. Тест проігнорує блок if і піде клікати на кнопку кошика. АЛЕ саме в цю мілісекунду поп-ап з'являється на екрані, перекриває кнопку, і ваш тест падає з помилкою Element is intercepted.
Ви перезапускаєте тест — сервер відповідає швидше, поп-ап з'являється миттєво, if спрацьовує, тест "зелений". Вітаю, ви створили еталонний Flaky-тест!
✅ Як це виглядає після код-рев'ю Senior-інженера:
Тест має бути прямою лінією. Якщо банер можна відключити (через cookie або API-мок) — відключаємо. Якщо ж це неконтрольований поп-ап, використовуємо нативну "магію" Playwright 1.42+:
// Ідеально чистий код (Playwright addLocatorHandler)
test('Повинен додати товар у кошик', async ({ page }) => {
// 1. Вчимо Playwright автоматично реагувати на перешкоду, ЯКЩО вона з'явиться
await page.addLocatorHandler(
page.locator('.promo-popup'),
async () => {
await page.locator('.close-promo').click();
}
);
await page.goto('/product/123');
// 2. Тест залишається абсолютно лінійним, ніяких if/else!
await page.locator('.add-to-cart').click();
});
Золоте правило: Ніколи не використовуйте if / else для синхронізації UI чи обробки випадкових елементів на сторінці. Автотест — це не алгоритм пошуку шляху, це жорсткий сценарій. Контролюйте стан додатка, а для асинхронних перешкод делегуйте роботу фреймворку.
А скільки if'ів зараз заховано у вашому фреймворку? 👇
🔥 — Використовую addLocatorHandler, мої тести прямі як стріла!
👀 — Грішу іф-елсами, бо на проді постійно лізуть рандомні банери...
🤯 — Тепер я зрозумів, чому мої тести періодично падають на кліках!
👍1