QA Co-pilot
94 subscribers
298 photos
1 video
47 links
QA Co-pilot 🚀

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

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

Питання від ліда:
"Фронтендери (наприклад, на вашому улюбленому Angular) вже все зверстали. Але бекенд (на NestJS) ще навіть не починав писати API. У нас є тільки узгоджений Swagger-файл. Як QA гарантувати, що коли вони нарешті зійдуться на тестовому середовищі, все не вибухне?"

Відповідь рівня Junior (Хибний шлях):
"Я просто напишу моки (фейкові дані) для E2E-тестів у Playwright і буду тестувати фронтенд ізольовано. А коли бекенд буде готовий — проженемо реальні тести."

Чому це провал: Ваші моки дуже швидко застаріють. Якщо через тиждень бекендер вирішить перейменувати поле userId на user_id, ваші фронтенд-тести залишаться зеленими (бо моки старі), а на продакшені все впаде.

Відповідь рівня Senior (Підхід Архітектора):

"Нам потрібне Contract Testing (Контрактне тестування), наприклад, через інструмент Pact."
Алгоритм:

1️⃣ Фронтенд пише тест, який генерує "Контракт" (JSON-файл). У ньому чітко написано: "Я відправляю запит X і очікую отримати поле userId у форматі числа".

2️⃣ Цей контракт автоматично завантажується в Pact Broker (спільний репозиторій).

3️⃣ Коли бекендер пише свій код, його CI/CD пайплайн автоматично стягує цей контракт і перевіряє свій API проти нього.

4️⃣ Якщо бекендер перейменував поле або змінив тип даних — його пайплайн падає ще до деплою.


Золоте правило: E2E-тести занадто повільні для перевірки інтеграції двох команд. Контрактні тести — це автоматизований "договір" між клієнтом і сервером, який не дозволяє їм зламати один одного.

А як ви тестуєте розірвані команди? 👇
🔥 — Pact — наш бро! Ловимо невідповідності ще в пайплайнах.
👀 — Пишемо E2E з моками і молимось, щоб бекенд нічого не змінив.
🤯 — Стоп, тобто фронтенд може диктувати бекенду, які дані повертати?!
💩 Код з душком: Жорсткі паузи (або Злочин під назвою sleep())

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

Знайдіть проблему в цьому коді:
//  Антипатерн "Почекун" (Hardcoded Sleep)
test('Завантаження списку транзакцій', async ({ page }) => {
await page.click('#load-transactions');

// Сервер іноді тупить, тому почекаємо 5 секунд "про всяк випадок"
await page.waitForTimeout(5000);

await expect(page.locator('.transaction-item')).toHaveCount(10);
});


Чому цей код тхне:
Це класична ситуація "програш за обома фронтами" (lose-lose).

1️⃣ Крадіжка часу: Якщо бекенд відповів миттєво (за 100 мс), ваш тест все одно стоятиме як укопаний ще 4.9 секунди. Помножте це на 500 тестів, і ваш CI/CD пайплайн перетвориться на нескінченне очікування.

2️⃣ Нульова надійність: Якщо бекенд під навантаженням і відповів за 5.1 секунди — ваш тест гарантовано впаде, незважаючи на паузу.


Як це виглядає після код-рев'ю Senior-інженера:
Жорсткі паузи суворо заборонені. Тест повинен чекати рівно стільки, скільки потрібно, спираючись на події системи, а не на годинник.
// 🚀 Ідеально чистий код (Динамічне очікування мережі)
test('Завантаження списку транзакцій', async ({ page }) => {
// 1. Готуємо "пастку" для запиту до того, як клікнемо
const responsePromise = page.waitForResponse('**/api/transactions');

// 2. Робимо дію
await page.click('#load-transactions');

// 3. Чекаємо на відповідь. Тест піде далі в ту саму мілісекунду, коли вона прийде!
await responsePromise;

await expect(page.locator('.transaction-item')).toHaveCount(10);
});


Золоте правило: Забудьте про sleep() або waitForTimeout(). Чекайте на зникнення лоадера-спінера (waitFor('hidden')), на зміну стану елемента або на конкретний мережевий запит. Зробіть свої тести "розумними", і ваш пайплайн скаже вам дякую.

А як ви боретеся з flaky-тестами? 👇
🔥 — Тільки динамічне очікування API чи подій інтерфейсу!
👀 — Іноді ставлю sleep(2000) і сподіваюсь, що на рев'ю не помітять...
🤯 — А що, можна перехоплювати API прямо з фронта, щоб не чекати?!
1
⚔️ Битва підходів: Cucumber (BDD) проти Чистого Коду

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

🥊 Підхід 1: BDD / Gherkin (Свідки Cucumber)
Ви пишете тести людською мовою через ключові слова Given / When / Then.

🔹Як це нам продають: "Бізнес, продакти та мануальні тестувальники зможуть самі читати і навіть писати автотести! У нас буде жива документація!"

🔹Сувора реальність: Це гігантський милиця. Під кожен текстовий рядок When я натискаю кнопку "Купити" AQA-інженер змушений писати мапінг у коді (регулярки або декоратори). Рефакторинг перетворюється на пекло: ви змінили текст кроку — код впав. І найголовніше — за кілька років роботи бізнес жодного разу не відкриє ваш репозиторій, щоб почитати ці тести.


🥊 Підхід 2: Code-First (Чистий Playwright/Cypress на TypeScript)
Ви викидаєте текстовий прошарок і пишете сценарії одразу кодом, використовуючи паттерни на кшталт Page Object або Action Classes.

🔹Переваги: Максимальна швидкість розробки. Строга типізація (TypeScript), миттєвий автокомпліт в IDE, рефакторинг однією кнопкою (F2). Ваші тести гнучкі та легко підтримуються.

🔹Недоліки: Менеджер не зрозуміє, що написано у файлі checkout.spec.ts.


⚖️ Вердикт QA Co-pilot:
BDD — це красива ілюзія, яка добре звучить на конференціях, але на практиці додає 50% оверхеду до часу розробки і підтримки. Для переважної більшості проєктів це абсолютно зайвий баласт.

Здоровий підхід: Пишіть тести чистим кодом, а для менеджерів та мануальників генеруйте красиві HTML-звіти (наприклад, через Allure), де назва тесту test('User can buy item') перетворюється на зрозумілий читабельний рядок. Не робіть інженерів заручниками текстових парсерів.


А в якому таборі ви? 👇
🔥 — Пишу на чистому TS/JS, ніяких "огірків" у моєму коді!
👀 — У нас BDD... Код перетворився на кашу з декораторів, допоможіть.
🤯 — А що, бізнес реально мав читати наші тести?!
1
📡 Tech Radar: Головне для QA цього тижня

Привіт, екіпаж! Понеділок — час оновлювати тулбокс. Два інструменти, які зараз активно обговорюють у ком'юніті:

1️⃣ Playwright UI Mode (Time-Travel Debugging): Якщо ви досі дебажите тести через console.log або повільний інспектор — зупиніться. Запуск із прапорцем --ui відкриває повноцінне вікно, де ви можете буквально "відмотати" час назад. Ви бачите DOM, network та console на кожній мілісекунді виконання тесту.

2️⃣ Faker.js — Deterministic Seeds: Всі люблять генерувати фейкові імена та емейли. Але що робити, коли тест впав, а рандомні дані змінилися при перезапуску? Faker додав можливість задавати faker.seed(123). Тепер ваші дані рандомні, але однакові при кожному прогоні. Ідеально для відтворення плаваючих багів!


Що затестите першим? 👇
🔥 — Playwright UI Mode!
👀 — Faker.js Seed, давно шукав(ла) це.
⚔️ Битва підходів: Візуальні тести (Pixel-Perfect) проти DOM-Асертів

Ще одна тема понеділка! Як перевірити, що ваш Angular-компонент виглядає правильно?

🥊 Підхід 1: Visual Regression (Скріншоти)
Ви робите скріншот сторінки і порівнюєте його з еталоном.

Мінус: Тести стають надзвичайно крихкими (flaky). Дизайнер змінив тінь на кнопці на 1 піксель, або змінився рендер шрифтів у CI/CD на Linux — і всі тести "почервоніли".


🥊 Підхід 2: DOM-Асерти (Логічні перевірки)
Ви перевіряєте лише те, що важливо: expect(btn).toHaveClass(/primary/) та expect(btn).toBeVisible().

Плюс: Куленепробивна стабільність. Колір кнопки вас не обходить, головне — збережена бізнес-логіка і правильні CSS-класи.


Вердикт QA Co-pilot: Скріншотні тести мають право на життя ТІЛЬКИ в Storybook для ізольованих UI-компонентів. В End-to-End тестах використовуйте виключно DOM-перевірки.

А як ви шукаєте візуальні баги? 👇
🔥 — Тільки DOM, не хочу розбирати впавші скріншоти.
👀 — Робимо скріншоти, але боляче...
👍1
🧨 Руйнівники IT-міфів: "100% Code Coverage означає відсутність багів"

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

Міф: "Наш SonarQube показує 100% покриття коду тестами. Ми можемо спокійно релізити, багів немає!"

💥 Реальність:
Code Coverage показує лише те, які рядки коду виконувалися під час тестів. Але він НЕ гарантує, що ви перевірили результат!

Ви можете написати тест, який викликає функцію calculateSalary(), і не написати жодного expect(). Покриття буде 100%, а функція може повертати null.


Як має бути:
Справжній показник надійності — це Mutation Testing (наприклад, Stryker). Цей інструмент штучно вносить баги у ваш код (міняє + на -) і перевіряє, чи впадуть ваші тести. Якщо не впали — ваші тести сліпі, незалежно від відсотків покриття!


Ганяєтесь за 100% покриттям? 👇
🔥 — Ні, фокусуємось на критичних бізнес-сценаріях!
👀 — У нас KPI на 80% покриття, пишемо тести заради цифри...
🧠 Задача з Senior співбесіди: "Подорож у часі"

Продовжуємо вівторок задачею з лайв-кодингу.

Умови: На сайті є банер "Знижка згорить завтра об 11:00". Як автоматизувати перевірку того, що банер дійсно зникає, коли настає час Х?

Відповідь Джуна: "Я створю тестовий банер, який зникає через 5 секунд, поставлю sleep(5000) у тесті і перевірю." (Погано: хардкод логіки під тести).

Відповідь Сеньйора:
Ми замокаємо системний годинник прямо в браузері!

Сучасні фреймворки мають вбудовану машину часу. Наприклад, у Playwright ми використовуємо await page.clock.setFixedTime(new Date('2026-12-31T11:01:00')).

Браузер думатиме, що дедлайн уже минув, Angular-компонент миттєво перерахує час, і банер зникне. Нуль очікувань, 100% надійність.


Мокаєте час у тестах? 👇
🔥 — Постійно, це єдиний спосіб тестувати таймери!
👀 — Чесно? Навіть не знав(ла), що так можна.
🕵️‍♂️ Інженерний детектив: "Невидима перешкода" (або Z-Index пастка)

Привіт, екіпаж! Середа — час розслідувань.

Симптоми: Користувачі скаржаться, що кнопка "Купити" не натискається. Ви запускаєте Cypress/Playwright — тест клікає кнопку і світиться зеленим. Ви відкриваєте руками — кнопка реально не реагує на мишку!

🔍 Що сталося:
Playwright за замовчуванням має механізм "Actionability", але іноді він хибить. Фронтендер випадково розтягнув прозорий <div> (наприклад, невидимий тултип) поверх кнопки.

Візуально кнопка є. В DOM вона є. Але фізично курсор клікає по прозорому <div>, який лежить вище по z-index!


Вирок:
У Playwright іноді використовують force: true для кліку. Це змушує фреймворк пробити DOM і клікнути елемент, ігноруючи перешкоди. Ніколи цього не робіть.

Якщо тест падає через "element intercepts pointer events" — це не нестабільний тест, це реальний баг UI, який блокує ваших живих користувачів.
📝 Ультимативна Шпаргалка: HTTP Status Codes (Версія для QA)

Ми всі знаємо 200 (OK) та 404 (Not Found). Але на співбесідах (і під час тестування NestJS бекендів) постійно плутають помилки клієнта. Зберігайте:

401 Unauthorized: "Я не знаю, хто ти". (Ти забув передати токен авторизації, або він прострочений).

403 Forbidden: "Я знаю, хто ти, але тобі туди не можна". (Ти залогінений як звичайний юзер, а намагаєшся видалити проєкт як Адмін).

400 Bad Request: "Ти відправив технічну діч". (Синтаксична помилка, не валідний JSON, бракує обов'язкового поля).

422 Unprocessable Entity: "Формат правильний, але бізнес-логіка проти". (Ти відправив ідеальний JSON з полем email, але цей email вже зайнятий у PostgreSQL).


Перевіряйте не просто факт помилки, а її ТОЧНИЙ код у ваших API тестах!
🔥 Прожарка інструментів: Selenium WebDriver (Легенда, якій час на пенсію)

Привіт, екіпаж! Сьогодні смажимо прабатька всієї UI-автоматизації.

🟢 Як нам це продають: "Це стандарт! Він підтримує навіть Internet Explorer 8 і будь-які мови програмування!"

🥩 Прожарка:
1️⃣ Пекло версій: Скільки життів згоріло через помилку SessionNotCreatedException: This version of ChromeDriver only supports Chrome version X. Ви оновили браузер — тести впали. Потрібно постійно менеджити драйвери (так, є WebDriverManager, але це ще один костиль).

2️⃣ Архітектура: Selenium працює через HTTP-запити до драйвера. Він фізично не може зазирнути всередину браузера, перехопити мережу чи працювати з LocalStorage так само елегантно і швидко, як Playwright чи Cypress (які спілкуються через CDP протокол).


Вердикт: Якщо ви стартуєте новий проєкт у 2026 році — Selenium є найгіршим вибором з точки зору швидкості розробки (DX). Залиште його для підтримки легасі.
🩻 Рентген співбесіди: "Тестування Webhooks"

Продовжуємо четвер питанням для мідлів+.

Питання: "Ваш додаток інтегровано з платіжною системою. Коли оплата проходить, стороння система відправляє Webhook (асинхронний POST запит) на ваш бекенд. Як це протестувати?"

Відповідь Джуна: "Я оплачу на UI і буду робити sleep(10000) або постійно оновлювати сторінку, поки баланс не зміниться."

Відповідь Сеньйора:
Я взагалі не буду чіпати сторонню систему. Я використаю API-клієнт в автотестах і сам відправлю POST-запит на наш ендпоінт вебхука (наприклад, /api/webhooks/stripe), імітуючи payload від платіжки з правильними signature-заголовками.

Або, якщо треба протестувати реальний флоу, підніму локальний тунель через Ngrok у CI/CD, щоб стороння система могла "достукатися" до мого тестового оточення.
💩 Код з душком: Магічні числа (або "Чому саме 5?")

Привіт, екіпаж! П'ятниця — вивітрюємо антипатерни.

Знайдіть проблему:
test('Відображення списку статей', async ({ page }) => {
await expect(page.locator('.article-card')).toHaveCount(5);
});

Чому це тхне:
Що таке 5? Це хардкод. Якщо хтось додасть нову статтю в базу даних — тест впаде, хоча функціонал працює. Вам доведеться йти в код і міняти 5 на 6. Це перетворює підтримку тестів на рутину.

Як має бути:
Завжди спирайтеся на динамічні дані. Якщо ви мокаєте мережу — беріть довжину з моку. Якщо берете з бази — робіть запит:
// 🚀 Ідеально
const articlesMock = [{id: 1}, {id: 2}];
await page.route('**/api/articles', route => route.fulfill({ json: articlesMock }));
await expect(page.locator('.article-card')).toHaveCount(articlesMock.length);

Додали елемент у масив? Тест адаптується автоматично.
⚔️ Битва підходів: Page Object Model (POM) проти Custom Fixtures

Завершуємо тиждень класичною битвою архітектур у Playwright.

🥊 Підхід 1: Page Object Model (Класика)
Ви створюєте клас LoginPage з методами fillEmail() та clickSubmit().

Проблема: З часом класи стають гігантськими ("Божественний об'єкт"), вимагають постійного new LoginPage(page) і засмічують пам'ять.


🥊 Підхід 2: Playwright Fixtures (Сучасність)
Ви інкапсулюєте кроки прямо в інфраструктуру тесту. Тест просто просить те, що йому треба у параметрах:
test('buy item', async ({ loggedInUser, cartInfo }) => { ... })

Перевага: loggedInUser сам під капотом відкриє сторінку, залогіниться, перевірить сесію і віддасть готовий стан. Жодних new, максимальна ізоляція та перевикористання.


Вердикт: POM все ще крутий для опису селекторів (аби не дублювати locator), але для складних флоу переходьте на кастомні Fixtures — це робить ваші тести чистими як сльоза.