QA Co-pilot
91 subscribers
266 photos
1 video
44 links
QA Co-pilot 🚀

Ваш другий пілот у світі тестування.

👨‍💻 Для кого: Для тестувальників-практиків, які хочуть рости.
🎯 Про що: Делегуємо рутину нейромережам, прискорюємо роботу та звільняємо час на головне.
Чого тут немає: Нудної теорії та води.
Download Telegram
🔍 Рентген співбесіди: «Ми вам передзвонимо» або що насправді шукає рекрутер

Буває так: ти розклав по поличках роботу 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 (обмін станом) між тестами. Це той випадок, коли ви використовуєте глобальні змінні для передачі даних від одного тесту до іншого. ☕️

Знайдіть проблему в цьому коді:
//  Як пишуть джуни (Антипатерн "Глобальний наркоман")

// Десь у глобальному скоупі файлу
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}`);
});


Золоте правило: Кожен тест має бути повністю атомарним. Тест має сам створювати потрібні дані, виконувати дію і сам за собою прибирати (якщо це необхідно). Жодних глобальних змінних для передачі даних!

А ваші тести бігають у паралель, чи ви боїтесь, що вони "перепиляться" даними? 👇
🔥 — Тільки атомарні тести, тільки паралельний запуск!
👀 — Грішимо глобальними змінними, тому запускаємо по одному...
🤯 — Мої тести впали вчора, тепер я знаю чому!
🔥21
П'ятниця: Час деплоїти... себе в паб! 🍻

Робочий тиждень офіційно переходить у статус «Done». Реліз-кандидат тижня готовий, баги дбайливо перенесені в беклог на понеділок, а це значить — час для справжнього офлайн-нетворкінгу. ☕️

Якраз до п'ятниці я випустив трек про легендарний Портер Паб — місце, де було випито тисячі літрів пива під обговорення архітектури та падаючих пайплайнів. 🎸

Слухаємо, заряджаємось і йдемо відпочивати. Зустрінемось за баром!

https://youtu.be/95i7fPiNaZE?si=n4TCjaD4swKUqEeK
🧨 Руйнівники IT-міфів: "Покриємо все E2E тестами і будемо спати спокійно"

Привіт, екіпаж! Сьогодні розбираємо найдорожчу ілюзію, яку часто намагаються продати бізнесу, або в яку вірять автоматизатори на початку кар'єри. ☕️

Міф: "Нам треба стовідсоткове покриття! Давайте напишемо автотести на 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
🕵️‍♂️ Інженерний детектив: Справа про "Баг Попелюшки" (або Тести, що перетворюються на гарбуз)

Привіт, екіпаж! Сьогодні розслідуємо містику найвищого рівня. Це баг, через який сивіють навіть досвідчені ліди, бо він ламає всі закони логіки і змушує сумніватися у власній адекватності. ☕️

Сцена злочину (Симптоми):
Ви написали автотест, який перевіряє створення звіту за "сьогодні" або дату народження у профілі. Запускаєте локально — працює ідеально.

Пушите в репозиторій, 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. Автоматизація тепер — це суцільне свято!"

🥩 Прожарка (Сувора реальність):
🔹Ілюзія асинхронності: Ви дивитесь на код і бачите 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). ☕️

Знайдіть проблему в цьому тесті:
//  Як пишуть джуни (Антипатерн "Ворожка")
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
📡 Tech Radar: Головне за тиждень (18.05 – 24.05.2026) від QA Co-pilot

Привіт, екіпаж! Новий тиждень — нові виклики. Минулого тижня індустрія видала кілька потужних релізів, які прямо зараз змушують команди переглядати свої пайплайни. Зібрали для вас найважливіше без води і маркетингового шуму. ☕️

🅰️ Реліз Angular 22: Прощання з Zone.js
Минулого тижня сталася епохальна подія для фронтенду — офіційний вихід Angular 22. Фреймворк остаточно перейшов на повністю Zoneless архітектуру за замовчуванням (реактивність тепер тримається виключно на Signals).

Як це вплине на QA: Додатки почнуть рендеритися кардинально швидше. Але є нюанс: якщо ваші старі E2E-тести під капотом покладалися на очікування стабілізації Zone.js (або ви використовували специфічні бібліотеки-хелпери), вони можуть почати "сипатися" через мікро-гонки станів (race conditions). Час провести ревізію ваших waitFor та API-перехоплень!


📱 Telegram викотив пісочницю для E2E тестування Mini Apps (TMA)
Довгоочікувана новина для всіх, хто розробляє та тестує екосистему в Telegram. Нарешті з'явився офіційний інструментарій (tma-test-utils), який дозволяє ізольовано монтувати Telegram Web Apps у Playwright.

Як це вплине на нас: Більше жодного болю з авторизацією через реальні телефонні номери, 2FA та милиці з iframe! Тепер можна легко мокувати об'єкт Telegram.WebApp (теми, юзер-дані, initData) і проганяти повноцінні UI-тести ваших ботів та міні-додатків у CI/CD за лічені секунди.


🤖 Playwright 1.60 Beta: Перші кроки до Self-Healing локаторів
Команда Microsoft тихо викотила бету 1.60, де засвітився експериментальний підхід до пошуку елементів — інтеграція легких LLM безпосередньо у рушій (page.getByPrompt()).

Суть: якщо ваш жорсткий локатор ламається через редизайн, ШІ "на льоту" аналізує DOM і намагається врятувати клік, знаходячи потрібний елемент за контекстом.

Як це вплине на нас: Це крутий зсув парадигми, але впроваджувати треба обережно. ШІ-локатори повільніші за нативні і можуть додати тестам непередбачуваності. Поки що це інструмент для "м'якого" fallback-у, а не повної заміни getByRole.


Що з цього апдейту випробуєте першим? 👇
🔥 — Telegram Mini Apps пісочниця! Нарешті покрию свого бота нормальними тестами.
👀 — Angular 22: Пішов перевіряти, чи не "почервоніли" мої пайплайни.
🤯 — Self-healing у Playwright: звучить хайпово, але я поки ШІ в DOM не пущу!
⚔️ Битва підходів: Junior vs. QA Architect (Цикли проти Нативних ассертів)

Сьогодні розберемо класичну ситуацію: вам треба перевірити масив елементів на сторінці (наприклад, список повідомлень у чаті або таблицю). Як витягнути та перевірити дані, не змусивши ваш тест "гальмувати"? ☕️

Підхід Junior-автоматизатора
const texts = [];
const messages = page.locator('.chat-message');
const count = await messages.count();

for (let i = 0; i < count; i++) {
// Повільно витягуємо текст по одному...
texts.push(await messages.nth(i).textContent());
}

expect(texts).toContain('Замовлення успішне');

Чому це антипатерн: Це повільно і крихко. По-перше, count() стріляє миттєво і не чекає на рендер (часто повертає 0). По-друге, кожна ітерація циклу for робить окремий асинхронний запит до браузера. Якщо у чаті 50 повідомлень — тест гарантовано "зависне" на кілька секунд.

Підхід QA Architect
// Варіант 1: Одразу перевіряємо наявність тексту у списку (з auto-retry)
await expect(page.locator('.chat-message')).toContainText(['Замовлення успішне']);

// Варіант 2: Якщо масив реально потрібен для хитрої логіки
const allTexts = await page.locator('.chat-message').allTextContents();

Чому це шедевр: Швидкість світла і стабільність. Playwright виконує allTextContents() або toContainText() за одну мілісекунду на рівні браузерного рушія, перехоплюючи весь масив одразу. Крім того, веб-ассерт автоматично зачекає (до 5 секунд), поки потрібне повідомлення не з'явиться в DOM, що рятує від Flaky-тестів.

Золоте правило: Якщо ви пишете цикл for для перебору UI-елементів у Playwright — зупиніться. З імовірністю 99% ви робите щось не так і для цього вже є нативний оптимізований метод.

А як ви працюєте зі списками елементів? 👇
🧨 Руйнівники IT-міфів: "Record & Playback напише тести за нас"

Привіт, екіпаж! Сьогодні розбираємо класичний міф, який дуже люблять продавати менеджерам творці платформ для тестування (і в який часто вірять початківці). ☕️

Міф: "Навіщо писати код руками і вчити архітектуру? Вмикаємо Playwright Codegen (або Cypress Studio), проклікуємо флоу в браузері — і фреймворк генерує ідеальні автотести за 5 хвилин! QA може просто записувати свої дії."

💥 Реальність (Бум!):
Вітаю, ви щойно згенерували найгірший вид легасі. Record & Playback — це пастка для великих проєктів:

1️⃣Смертельний хардкод: Генератор запише ваші дії буквально. await page.fill('#email', 'test@test.com'). На наступному запуску тест впаде, бо цей email вже зайнятий у базі.

2️⃣Жодної архітектури: Згенерований код — це "простирадло" з локаторів. Там немає ні Page Object, ні Fixtures, ні перевикористання кроків. Змінився селектор однієї кнопки? Будете руками правити 100 згенерованих файлів.

3️⃣Сліпота до асинхронності: Рекордер не знає, що після кліку треба дочекатися відповіді бекенду або закінчення анімації. Він просто запише клік, а ваш пайплайн потім буде "блимати" червоним через мікро-затримки мережі (Flaky tests).


Як має бути (Підхід Архітектора):
Codegen — це лише допоміжний інструмент (як пінцет). Його використовують виключно для того, щоб швидко знайти оптимальний локатор (getByRole) на складній сторінці, або накидати "чернетку" скрипта.

Але справжній автотест завжди проєктується інженером: з ізоляцією даних, динамічними моками та правильною інфраструктурою.


Золоте правило: Тести, які легко і швидко записуються через Record, найважче і найдорожче підтримувати в майбутньому.

А як ви ставитесь до автогенерації коду? 👇
🕵️‍♂️ Інженерний детектив: Справа про "Хитрого Гамбургера" (або Пастка Роздільної Здатності)

Привіт, екіпаж! Середа — час нашої рубрики «Інженерний детектив». Сьогодні розслідуємо злочин, заснований виключно на геометрії та ілюзіях. ☕️

Сцена злочину (Симптоми):
Ви пишете базовий тест: зайти на головну сторінку і клікнути на пункт меню «Налаштування Профілю» у верхньому навігаційному барі.

Ви запускаєте тест локально з відкритим браузером (--headed) — ідеально. Пушите код у репозиторій. У CI/CD пайплайні тест падає з помилкою: Error: locator.click(): Target closed. Element is not visible.

Як так? Сторінка завантажилась повністю, жодних проблем з мережею немає, але Playwright впритул не бачить кнопку!


Хибний слід:
Джун думає, що це якийсь баг рендерингу в headless-режимі. Починає писати милиці: змушує тест скролити сторінку вниз-вгору (mouse.wheel), або намагається пробити невидимість через force: true. Звісно, це не допомагає, бо кнопки там фізично немає.

🔍 Що сталося насправді (CSS Media Queries):
Справа не в браузері, а у розмірі вікна (Viewport).

Коли ви працюєте локально, ви, як справжній розробник, сидите за широким монітором (наприклад, 1920x1080). Ваш Angular-компонент бачить багато місця і рендерить гарне горизонтальне меню.

Але в CI/CD серверах Playwright за замовчуванням відкриває вікно браузера з роздільною здатністю 1280x720. На цій ширині спрацьовує CSS-брейкпоінт адаптивного дизайну (наприклад, max-width: 1024px у Tailwind).

Додаток "думає", що його відкрили на планшеті! Верхнє меню миттєво зникає (отримує display: none), а всі лінки ховаються всередину іконки мобільного меню (того самого "Гамбургера" 🍔).

Лінку «Налаштування» просто немає на екрані, поки ви не розгорнете бургер-меню!


Вирок та Рішення:
Тести не повинні залежати від розміру вашого домашнього монітора. Візуальне середовище має бути жорстко зафіксоване для всіх запусків.

Йдемо в playwright.config.ts і явно прописуємо Viewport для десктопного проєкту:
projects: [
{
name: 'Desktop Chrome',
use: {
...devices['Desktop Chrome'],
// Жорстко фіксуємо розмір вікна для CI та локалки
viewport: { width: 1920, height: 1080 },
},
},
]


А якщо ви хочете тестувати мобільну версію — створюєте окремий проєкт у конфігу з емуляцією iPhone, де тест буде спочатку явно клікати на .hamburger-icon, а вже потім шукати ваш лінк.

А ви вже ставали жертвою адаптивної верстки в CI? 👇
🔥 — Завжди хардкодю Viewport у конфігу першим ділом!
👀 — Було діло... Довго шукав кнопку, яка просто сховалась у бургер.
🤯 — Стоп, тобто Playwright у пайплайні емулює екран ноутбука з 2012 року?!
🗂 Ультимативна шпаргалка: Жорсткі vs. М'які перевірки (Soft Assertions)

Коротка шпаргалка про те, як зібрати максимум багів за один прогін і не переривати скрипт на півдорозі. Зберігайте! ☕️

🛑 expect() (Жорстка перевірка — Класика)
Як працює: Знайшов помилку ➡️ Тест миттєво впав (Fatal Error) ➡️ Усі наступні кроки скасовано.

Коли юзати: Критичні бізнес-кроки. Якщо після логіну юзер не потрапив у дашборд, немає сенсу намагатися клікати далі.


// Якщо сторінка не завантажилась, тест падає тут...
await expect(page).toHaveURL('/dashboard');
// ...цей клік ніколи не виконається
await page.getByRole('button', { name: 'Створити' }).click();


☁️ expect.soft() (М'яка перевірка — Рятівник часу)
Як працює: Знайшов помилку ➡️ Записав у лог (червоним) ➡️ Пішов виконувати тест далі! Скрипт впаде лише в самому кінці, але збере всі помилки.

Коли юзати: Перевірка великих форм, таблиць, візуальних атрибутів, де один баг (наприклад, неправильний колір тексту) не блокує перевірку інших полів.


// Якщо ім'я не збігається, тест запише помилку, але ВСЕ ОДНО перевірить вік та email!
await expect.soft(page.locator('#name')).toHaveValue('Ivan');
await expect.soft(page.locator('#age')).toHaveValue('25');
await expect.soft(page.locator('#email')).toHaveValue('test@test.com');


Золоте правило:
Використовуйте expect() для навігації та перевірок станів, від яких залежить наступний крок. Використовуйте expect.soft(), коли тестуєте "пачку" незалежних даних (наприклад, перевіряєте всі дані у профілі користувача після збереження).

А ви використовуєте "м'які" перевірки? 👇
🔥 — Так, expect.soft() ідеально підходить для перевірки таблиць!
👀 — Пишу звичайний expect, хай падає одразу, мені так спокійніше.
🤯 — Почекайте, Playwright вміє не зупиняти тест при помилці?!
2
😅 Хтось досі пропускає топові релізи і новини…А ти можеш бути серед тих, хто знає першим!

🚀 GameTech — це:
🎮 ігрові новини та релізи
👾 новини криптовалюти та тренди ринку
📲 корисні додатки і лайфхаки
🖥 техно-новинки та апдейти ОС
🔥 інсайди без води і клікбейту


🎁 + ЗАРАЗ ІДЕ РОЗІГРАШ:
Скін у CS2 (StatTrak) | Triarch — майже новий 🔥


💥 Хочеш шанс забрати?
👉 Підписка + кнопка «Брати участь»

🔥 Збираємо перших 100 активних бро

😎 Підписався = завжди в темі!

👇 Залітай прямо зараз
🚀 ПІДПИСАТИСЬ НА GAMETECH 🚀
1
🔥 Прожарка інструментів: Cucumber (або Чому бізнес ніколи не читатиме ваші тести)

Привіт, екіпаж! Четвер — час розпалювати гриль. Сьогодні на нашій решітці лежить інструмент, який продають менеджерам як "срібну кулю", а для інженерів він часто перетворюється на архітектурні кайдани. Зустрічайте — Cucumber та його синтаксис Gherkin. ☕️

🟢 Як нам це продавали (Очікування):
"Давайте писати тести людською мовою! Given, When, Then. Бізнес-аналітики та продакт-менеджери будуть самі писати сценарії, а автоматизатори — лише підкладати під них код. У нас буде ідеальна жива документація, яку зрозуміє навіть CEO!"


🥩 Прожарка (Сувора реальність):
Бізнес ніколи не пише тести. Це найголовніший міф індустрії. У 99% випадків аналітику немає коли гратися зі специфічним синтаксисом і відступами. У результаті QA-інженер сам вигадує сценарій на Gherkin, а потім сам же пише під нього код. Ви просто робите подвійну роботу.

Прокляття текстових рядків: Замість гнучкого та типізованого TypeScript ви будуєте крихкий міст. Змінили формулювання кроку з "я натискаю кнопку Зберегти" на "я клікаю на кнопку Зберегти" — і тест відвалився, бо не спрацював регулярний вираз (Regex) під капотом.

Біль рефакторингу та дебагу: Уявіть, що змінилася бізнес-логіка і треба переписати 50 тестів. У чистому Playwright з Page Object ви міняєте один метод, і IDE миттєво підсвічує всі місця, де він використовується. З Cucumber ви шукаєте зламані кроки по всьому проєкту через "Find in Files", створюючи жахливе нагромадження дублюючих Step Definitions.


⚖️ Вердикт QA Co-pilot:
BDD (Behavior-Driven Development) — це чудовий процес для обговорення вимог між розробником, тестувальником і бізнесом на етапі планування. Але тягнути BDD у код автотестів — це жорсткий оверінжиніринг. Сучасний Playwright з гарно названими кроками test.step('Заповнення форми оплати', ...) та згенерованим HTML-звітом дає максимально зрозумілу картину для будь-якого менеджера. Без жодних прошарків із "огірків".


А у вас в проєкті ростуть огірки? 👇
🔥 — Давно викинули BDD, пишемо чистий код на TS і кайфуємо!
👀 — Пишу на Gherkin, бо так сказав замовник. Плачу і підтримую регулярки...
🤬 — Не згоден, Cucumber дисциплінує і робить тести читабельними для всіх!
💩 Код з душком: Тести-Доміно (або Гріх спільного стану)

Привіт, екіпаж! П'ятниця — час вивітрювати "смердючий" код. Сьогодні препаруємо архітектурний антипатерн, який на початку здається геніальною оптимізацією, а через півроку перетворює ваш CI/CD на повільне пекло. Говоримо про залежність тестів (Test Interdependence). ☕️

Знайдіть проблему в цьому коді:
//  Як пишуть "оптимізатори" (Антипатерн "Доміно")
let orderId: string;

test.describe('Флоу замовлення', () => {
test('Крок 1: Створити замовлення', async ({ page }) => {
orderId = await createOrderThroughUI(page);
expect(orderId).toBeDefined();
});

test('Крок 2: Оплатити замовлення', async ({ page }) => {
// Використовує ID з попереднього тесту!
await payForOrder(page, orderId);
expect(await getOrderStatus()).toBe('Paid');
});

test('Крок 3: Видалити замовлення', async ({ page }) => {
await deleteOrderThroughUI(page, orderId);
});
});


Чому цей код тхне:

Ви порушили головне правило автоматизації — F.I.R.S.T. (Isolated). Ваші тести тепер склеєні суперклеєм.
1️⃣ Крихкість ланцюга: Якщо "Крок 1" падає через випадковий мікро-лаг мережі або рендеру, "Крок 2" і "Крок 3" автоматично стають червоними, бо змінна orderId порожня. У звіті у вас три зламаних тести, хоча реальна проблема лише в одному місці.

2️⃣ Паралельність мертва: Ви не зможете запустити ці тести паралельно на кількох воркерах у Playwright (fullyParallel: true), бо вони вимагають суворої послідовності. Ваш пайплайн ніколи не буде швидким.

3️⃣ Неможливість локального дебагу: Ви не можете просто взяти і запустити "Крок 3" ізольовано, щоб перевірити логіку видалення. Вам доведеться щоразу чекати, поки проклікаються попередні кроки.


Як це виглядає після код-рев'ю Senior-інженера:

Кожен тест має бути повністю незалежним. Він сам готує для себе ідеальні умови (бажано за мілісекунди через API) і сам за собою прибирає.
// 🚀 Ідеально чистий код (Повна ізоляція)
test('Повинен успішно оплатити замовлення', async ({ request, page }) => {
// 1. Arrange: Блискавично створюємо замовлення "під капотом" (через бекенд)
const order = await request.post('/api/orders').then(r => r.json());

// 2. Act: Тестуємо саме UI оплати
await page.goto(`/orders/${order.id}/pay`);
await page.getByRole('button', { name: 'Оплатити' }).click();

// 3. Assert: Перевіряємо результат
await expect(page.locator('.status')).toHaveText('Paid');
});


Золоте правило: Тест не повинен знати про існування інших тестів. Використовуйте API-виклики (request) або Fixtures для підготовки даних перед дією page.goto(). Кожен запуск — це чиста сторінка.

А як у вас справи із залежністю тестів? 👇
🔥 — Повна ізоляція, кожен тест готує дані через API за мілісекунди!
👀 — У мене величезний test.describe.serial, інакше все ламається...
🤯 — А що, тести можна запускати в довільному порядку?!
👍1
📡 Tech Radar: Головне за тиждень (25.05 – 31.05.2026) від QA Co-pilot

Привіт, екіпаж! Травень завершується, але індустрія не збавляє обертів. Цього тижня маємо потужні апдейти інструментів, якими користуються QA на абсолютно різних проєктах — від тестування API до мобільних додатків та навантаження. Зібрали для вас найважливіше без води. ☕️

👨‍🚀 Postman 12: ШІ-генерація Contract-тестів "з коробки"
Нарешті щось дійсно корисне для тих, хто днями сидить у колекціях API. Postman викотив велике оновлення, де вбудований AI-асистент навчився самостійно генерувати Contract-тести на основі вашої OpenAPI специфікації (Swagger).

Як це вплине на нас: Замість того, щоб руками писати перевірки на кожен тип даних (pm.expect(jsonData.id).to.be.a('number')), ви просто згодовуєте ШІ документацію, і він сам генерує скрипти для валідації всієї схеми відповідей. Час на покриття бекенду тестами скорочується в рази.


📱 Appium 3.0 Beta: Налаштування середовища за 60 секунд
Усі, хто хоч раз налаштовував мобільну автоматизацію з нуля, знають цей біль: завантажити Java, Android Studio, прописати змінні середовища, знайти сумісний ChromeDriver... Команда Appium викотила бету версії 3.0 із концепцією "Zero-Dependency".

Як це вплине на нас: Тепер достатньо однієї команди в терміналі (через спеціальний інсталятор), яка сама завантажує і лінкує всі необхідні драйвери та емулятори під ваш проєкт у контейнері. Мобільне тестування стає таким же простим у старті, як і веб!


🚀 Grafana k6: Browser Module виходить у стабільний реліз
Крута новина для тих, хто займається Performance-тестуванням. Раніше k6 був суто інструментом для бекенду (генерував запити на рівні протоколу). Тепер модуль для тестування браузера (k6 browser) став стабільним.

Як це вплине на нас: Ви можете в одному скрипті згенерувати навантаження на сервер у 1000 віртуальних користувачів через API, і одночасно запустити 1 реальний браузер, щоб виміряти, як сильно при цьому "гальмує" фронтенд (Web Vitals, час рендеру). Це дає реалістичну картину того, що відчуває юзер під час високого навантаження.


Що з цього потягнете на свій проєкт? 👇
🔥 — Postman AI: нарешті автоматизую ці нудні перевірки схем!
👀 — Appium 3.0: дайте два, ненавиджу налаштовувати ці драйвери.
🤯 — k6 Browser: давно хотів поєднати навантаження бекенду та фронтенду в одному звіті!
👍5
⚔️ Битва підходів: Junior vs. QA Architect (UI-Авторизація проти API State Injection)

Привіт, екіпаж! Сьогодні в нашій битві зійдуться два підходи до найпопулярнішої дії в будь-якому фреймворку — авторизації. Як ви заходите в систему перед тим, як протестувати, наприклад, створення профілю чи оплату кошика? ☕️

Підхід Junior-автоматизатора (UI-Логін у кожному тесті)
test.beforeEach(async ({ page }) => {
// Класика: чесно проходимо весь шлях через інтерфейс
await page.goto('/login');
await page.getByLabel('Email').fill('test@user.com');
await page.getByLabel('Password').fill('SuperSecret123!');
await page.getByRole('button', { name: 'Увійти' }).click();
await expect(page.locator('.dashboard')).toBeVisible(); // Чекаємо рендеру
});

test('Повинен додати товар у кошик', async ({ page }) => {
// ... логіка тесту
});

Чому це антипатерн для великих проєктів: Уявіть, що у вас 100 тестів. Кожна UI-авторизація займає приблизно 3-4 секунди (завантаження сторінки, введення, запит, редирект, рендер дашборду). Ви просто так витрачаєте 5-6 хвилин дорогоцінного часу в CI/CD на кожному прогоні! А якщо фронтендери зламають кнопку логіну? У вас впадуть УСІ 100 тестів, хоча кошик, можливо, працює ідеально.

Підхід QA Architect (API State Injection / Global Setup)
// Зберігаємо стан в окремому файлі (наприклад, global.setup.ts)
setup('Авторизація через API', async ({ request }) => {
// 1. Блискавично стукаємо в бекенд
const response = await request.post('/api/auth/login', {
data: { email: 'test@user.com', password: 'SuperSecret123!' }
});

// 2. Зберігаємо куки/токени у файл
await request.storageState({ path: 'auth.json' });
});

// У самому тесті:
test.use({ storageState: 'auth.json' }); // Playwright сам підкладе токени в браузер

test('Повинен додати товар у кошик', async ({ page }) => {
// Ми вже авторизовані! Просто йдемо на потрібну сторінку
await page.goto('/products');
// ... логіка тесту
});


Чому це шедевр: Швидкість та ізоляція. Логін через бекенд та збереження стану займають мілісекунди. Playwright відкриває нову сторінку вже з готовими cookies або localStorage. Усі ваші 100 тестів починаються миттєво з потрібного місця.

Золоте правило: UI-авторизацію треба тестувати рівно один раз в окремому файлі login.spec.ts. Для всіх інших E2E-тестів (профіль, налаштування, кошик) — "чітеримо", підкладаючи готові токени під капот. Не тестуйте логін 100 разів, якщо ваша мета — перевірити кошик!

А як ви заходите в систему у своїх тестах? 👇
🔥 — Тільки збереження стану та API, мої тести літають!
👀 — Кожен тест чесно вводить логін і пароль через UI, зате надійно...
🤯 — А що, можна було просто зберегти куки у JSON?!
🧨 Руйнівники IT-міфів: "100% Code Coverage гарантує відсутність багів"

Привіт, екіпаж! Сьогодні розбираємо найулюбленіший міф менеджерів, який змушує інженерів писати тисячі рядків марного коду просто заради зелених галочок у репортах. ☕️

Міф: "Якщо наші Unit- та E2E-тести покривають 100% рядків коду, ми можемо спокійно релізити. Додаток ідеальний, багів там немає!"

💥 Реальність (Бум!):
Code Coverage (покриття коду) — це найпідступніша метрика в IT. Вона показує лише те, що під час виконання тесту рушій (чи то Jest, чи Playwright) пройшов через певний рядок коду. Вона абсолютно не гарантує, що цей код працює правильно.


Як виглядає 100% покриття, яке нічого не тестує:
// Функція, яку ми "тестуємо"
function calculateDiscount(price: number, role: string) {
if (role === 'VIP') return price * 0.5;
return price;
}

// "Ідеальний" тест, який дасть 100% Coverage у звіті:
test('calculateDiscount coverage cheat', () => {
calculateDiscount(100, 'VIP');
calculateDiscount(100, 'Regular');
// Де перевірка expect()?! Її просто немає.
});

Ви щойно витратили час, CI/CD "позеленів", SonarQube щасливий. Але якщо завтра хтось випадково зламає формулу і напише return price * 99, ваш тест цього не помітить, бо він нічого не перевіряє (Assertion-Free testing).

Як має бути (Підхід Архітектора):
🔹Тестуємо вимоги, а не рядки: Тести мають перевіряти бізнес-сценарії. Чи може юзер змінити пароль? Чи відправляється аналітика? Тестуйте логіку, а не синтаксис.

🔹Мутаційне тестування (Mutation Testing): Замість гонитви за відсотками, круті інженери використовують інструменти типу Stryker. Вони навмисно вносять баги (мутації) у ваш код перед запуском тестів. Якщо тести після цього залишаються зеленими — значить, вони сміттєві, навіть при 100% Coverage.

🔹Правило 80/20: Здорова мета — це 70-80% покриття критичного функціоналу. Спроба покрити останні 20% (геттери, прості конфіги, інтерфейси) зазвичай вимагає 80% бюджету часу і не приносить жодної користі проєкту.


Золоте правило: Code Coverage — це інструмент для розробника, щоб знайти "сліпі зони" у критичній логіці, а не KPI для оцінки якості релізу.

А у вас на проєкті є культ 100% покриття? 👇
🔥 — У нас адекватні 70-80%, тестуємо тільки те, що реально може зламатися!
👀 — Сидимо, пишемо порожні тести просто заради SonarQube...
🤯 — Пішов гуглити, що таке мутаційне тестування, звучить як розрив мозку!
🕵️‍♂️ Інженерний детектив: Справа про "Привида в Базі" (або Пастка Soft Delete)

Привіт, екіпаж! Середа — час нашої рубрики «Інженерний детектив». Сьогодні ми забудемо про UI-фреймворки та швидкість тестів. Розслідуємо справу суто на стику тестування бізнес-логіки та баз даних. З цим багом стикався кожен, хто хоч раз тестував реєстрацію. ☕️

Сцена злочину (Симптоми):
Ви тестуєте стандартний функціонал управління користувачами. Ваш тест (або ви руками) робить наступне:
🔹Створює користувача test@company.com.

🔹Успішно видаляє його через адмінку. UI показує зелений тост: «Користувача видалено». У списку його більше немає.

🔹Ви намагаєтесь зареєструвати нового користувача з тим самим email-ом test@company.com (адже він вільний!).


І тут... Бум! Додаток падає з 500-ю помилкою (Internal Server Error) або видає алерт «Цей email вже зайнятий». Що за магія? Ви ж щойно його видалили!

Хибний слід:
Джун-тестувальник думає, що це проблема кешу браузера, і починає маніакально тиснути Ctrl+F5 або чистити LocalStorage. Коли це не допомагає, він заводить баг на фронтендера зі словами: "UI не оновлюється після видалення". Фронтендер ображається, бо він свою роботу зробив ідеально.


🔍 Що сталося насправді (Soft Delete та Індекси БД):
Справжній детектив дивиться глибше інтерфейсу. У сучасній розробці дані рідко видаляють фізично (команда DELETE в SQL). Замість цього розробники використовують патерн Soft Delete (М'яке видалення).
Коли ви натиснули «Видалити», бекенд просто оновив рядок у базі даних, проставивши прапорець is_deleted = true (або deleted_at = 2026-06-03).

Фронтенд навчений не показувати користувачів із цим прапорцем, тому зі списку він зник.
АЛЕ! У базі даних на колонці email досі висить жорстке обмеження унікальності (UNIQUE CONSTRAINT). База даних бачить, що рядок з таким email фізично існує (навіть якщо він "видалений"), і намертво блокує спробу створити дублікат, кидаючи критичну помилку!


Вирок та Рішення (Як це має перевіряти QA):
QA ніколи не повинен вірити зеленим повідомленням на UI.
Щойно ви бачите функцію "Видалити", ваш перший рефлекс — спробувати створити сутність із такими ж унікальними даними.

Як це фіксять архітектурно (підкажіть вашому бекендеру):
1️⃣ Partial Index: Змінити індекс у базі даних, щоб він перевіряв унікальність тільки для активних записів (CREATE UNIQUE INDEX ON users (email) WHERE deleted_at IS NULL).

2️⃣ Анонімізація: Під час видалення бекенд має змінювати старий email на щось на кшталт test@company.com.deleted.123456, звільняючи оригінальний email для нових реєстрацій.


А як ви тестуєте видалення? 👇
🔥 — Завжди перевіряю створення дублікатів після видалення, це база!
👀 — Чесно? Якщо запис зник з таблиці на UI, я закриваю таску як Pass...
🤯 — Тобто мої дані насправді ніколи не видаляються з баз?!
🤝21
🔥 Прожарка інструментів: Автономні ШІ-тестувальники (або Чому нейромережі поки не заберуть вашу роботу)

Привіт, екіпаж! Четвер — час розпалювати гриль. Сьогодні ми відкладемо класичні фреймворки і поговоримо про найбільший хайп 2026 року. Про інструменти (а-ля Devin для QA, автономні AI-агенти та No-Code ШІ платформи), які менеджери купують з надією звільнити половину відділу тестування. ☕️

🟢 Як нам це продавали (Очікування):
"Більше ніякого кодингу! Ви просто згодовуєте штучному інтелекту посилання на сайт, або даєте лінк на тікет у Jira. ШІ сам аналізує сторінку, сам придумує тест-кейси, сам пише код і сам його підтримує. QA-інженер тепер просто сидить і п'є смузі, поки агенти роблять усю роботу!"


🥩 Прожарка (Сувора реальність):
1️⃣ Генерація спагеті-коду: ШІ чудово пише лінійні скрипти. Але він абсолютно не розуміє архітектури вашого конкретного проєкту. Він не знає, що у вас є глобальна auth.fixture, складні Page Objects або хелпери для роботи з базою даних. Він просто нагенерує вам "простирадло" з хардкодними селекторами, яке неможливо інтегрувати у ваш красивий фреймворк.

2️⃣Галюцинації бізнес-логіки:
Агент бачить кнопку "Купити" і намагається її клікнути. Але він не розуміє, що за бізнес-вимогами ця кнопка має бути активною ТІЛЬКИ для користувачів з підпискою рівня "Premium". ШІ просто видасть помилку "Element not interactable", або ще гірше — почне писати милиці (force: true), щоб зламати вашу ж логіку заради зеленої галочки.

3️⃣Сліпота до станів (State Blindness): Нейромережі тестують UI, але погано розуміють невидимі процеси. Наприклад, те саме "м'яке видалення" з бази даних (Soft Delete) або мікрозатримки анімацій. Вони бачать ідеальну "щасливу стежку", але ігнорують складні крайові випадки (Edge cases), де зазвичай і ховаються найкритичніші баги.


⚖️ Вердикт QA Co-pilot:

Штучний інтелект — це фантастичний інструмент. Це ваш другий пілот (саме тому ми так і називаємося ✈️), який ідеально згенерує складну регулярку, допоможе скласти SQL-запит для підготовки даних або згенерує мок-відповідь для API.

Але довірити ШІ повну автономію в написанні E2E-тестів — це як дати стажеру доступ до продакшену в перший робочий день. ШІ генерує код, але Архітектор генерує надійність.

А як ви використовуєте ШІ в роботі? 👇
🔥 — Тільки як помічника (Copilot): прошу згенерувати дрібні функції або локатори!
👀 — Чесно? Інколи прошу ChatGPT написати весь тест цілком, а потім півдня його фікшу...
🤬 — Взагалі не пускаю ШІ до свого коду, він пише суцільне легасі!