📡 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
📡 Tech Radar: Головне за тиждень (18.05 – 24.05.2026) від QA Co-pilot
Привіт, екіпаж! Новий тиждень — нові виклики. Минулого тижня індустрія видала кілька потужних релізів, які прямо зараз змушують команди переглядати свої пайплайни. Зібрали для вас найважливіше без води і маркетингового шуму. ☕️
🅰️ Реліз Angular 22: Прощання з Zone.js
📱 Telegram викотив пісочницю для E2E тестування Mini Apps (TMA)
🤖 Playwright 1.60 Beta: Перші кроки до Self-Healing локаторів
Що з цього апдейту випробуєте першим? 👇
🔥 — Telegram Mini Apps пісочниця! Нарешті покрию свого бота нормальними тестами.
👀 — Angular 22: Пішов перевіряти, чи не "почервоніли" мої пайплайни.
🤯 — Self-healing у Playwright: звучить хайпово, але я поки ШІ в DOM не пущу!
Привіт, екіпаж! Новий тиждень — нові виклики. Минулого тижня індустрія видала кілька потужних релізів, які прямо зараз змушують команди переглядати свої пайплайни. Зібрали для вас найважливіше без води і маркетингового шуму. ☕️
🅰️ Реліз 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-автоматизатора
Чому це антипатерн: Це повільно і крихко. По-перше, count() стріляє миттєво і не чекає на рендер (часто повертає 0). По-друге, кожна ітерація циклу for робить окремий асинхронний запит до браузера. Якщо у чаті 50 повідомлень — тест гарантовано "зависне" на кілька секунд.
✅ Підхід QA Architect
Чому це шедевр: Швидкість світла і стабільність. Playwright виконує allTextContents() або toContainText() за одну мілісекунду на рівні браузерного рушія, перехоплюючи весь масив одразу. Крім того, веб-ассерт автоматично зачекає (до 5 секунд), поки потрібне повідомлення не з'явиться в DOM, що рятує від Flaky-тестів.
Золоте правило: Якщо ви пишете цикл for для перебору UI-елементів у Playwright — зупиніться. З імовірністю 99% ви робите щось не так і для цього вже є нативний оптимізований метод.
А як ви працюєте зі списками елементів? 👇
Сьогодні розберемо класичну ситуацію: вам треба перевірити масив елементів на сторінці (наприклад, список повідомлень у чаті або таблицю). Як витягнути та перевірити дані, не змусивши ваш тест "гальмувати"? ☕️
❌ Підхід 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 — це пастка для великих проєктів:
✅ Як має бути (Підхід Архітектора):
Золоте правило: Тести, які легко і швидко записуються через Record, найважче і найдорожче підтримувати в майбутньому.
А як ви ставитесь до автогенерації коду? 👇
Привіт, екіпаж! Сьогодні розбираємо класичний міф, який дуже люблять продавати менеджерам творці платформ для тестування (і в який часто вірять початківці). ☕️
❌ Міф: "Навіщо писати код руками і вчити архітектуру? Вмикаємо 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, найважче і найдорожче підтримувати в майбутньому.
А як ви ставитесь до автогенерації коду? 👇
🕵️♂️ Інженерний детектив: Справа про "Хитрого Гамбургера" (або Пастка Роздільної Здатності)
Привіт, екіпаж! Середа — час нашої рубрики «Інженерний детектив». Сьогодні розслідуємо злочин, заснований виключно на геометрії та ілюзіях. ☕️
Сцена злочину (Симптоми):
❌ Хибний слід:
Джун думає, що це якийсь баг рендерингу в headless-режимі. Починає писати милиці: змушує тест скролити сторінку вниз-вгору (mouse.wheel), або намагається пробити невидимість через force: true. Звісно, це не допомагає, бо кнопки там фізично немає.
🔍 Що сталося насправді (CSS Media Queries):
✅ Вирок та Рішення:
Тести не повинні залежати від розміру вашого домашнього монітора. Візуальне середовище має бути жорстко зафіксоване для всіх запусків.
Йдемо в playwright.config.ts і явно прописуємо Viewport для десктопного проєкту:
А якщо ви хочете тестувати мобільну версію — створюєте окремий проєкт у конфігу з емуляцією iPhone, де тест буде спочатку явно клікати на .hamburger-icon, а вже потім шукати ваш лінк.
А ви вже ставали жертвою адаптивної верстки в CI? 👇
🔥 — Завжди хардкодю Viewport у конфігу першим ділом!
👀 — Було діло... Довго шукав кнопку, яка просто сховалась у бургер.
🤯 — Стоп, тобто Playwright у пайплайні емулює екран ноутбука з 2012 року?!
Привіт, екіпаж! Середа — час нашої рубрики «Інженерний детектив». Сьогодні розслідуємо злочин, заснований виключно на геометрії та ілюзіях. ☕️
Сцена злочину (Симптоми):
Ви пишете базовий тест: зайти на головну сторінку і клікнути на пункт меню «Налаштування Профілю» у верхньому навігаційному барі.
Ви запускаєте тест локально з відкритим браузером (--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() (Жорстка перевірка — Класика)
☁️ expect.soft() (М'яка перевірка — Рятівник часу)
Золоте правило:
Використовуйте expect() для навігації та перевірок станів, від яких залежить наступний крок. Використовуйте expect.soft(), коли тестуєте "пачку" незалежних даних (наприклад, перевіряєте всі дані у профілі користувача після збереження).
А ви використовуєте "м'які" перевірки? 👇
🔥 — Так, expect.soft() ідеально підходить для перевірки таблиць!
👀 — Пишу звичайний expect, хай падає одразу, мені так спокійніше.
🤯 — Почекайте, Playwright вміє не зупиняти тест при помилці?!
Коротка шпаргалка про те, як зібрати максимум багів за один прогін і не переривати скрипт на півдорозі. Зберігайте! ☕️
🛑 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
😅 Хтось досі пропускає топові релізи і новини…А ти можеш бути серед тих, хто знає першим!
🎁 + ЗАРАЗ ІДЕ РОЗІГРАШ:
Скін у CS2 (StatTrak™) | Triarch — майже новий 🔥
💥 Хочеш шанс забрати?
👉 Підписка + кнопка «Брати участь»
🔥 Збираємо перших 100 активних бро
😎 Підписався = завжди в темі!
👇 Залітай прямо зараз
🚀 ПІДПИСАТИСЬ НА GAMETECH 🚀
🚀 GameTech — це:
🎮 ігрові новини та релізи
👾 новини криптовалюти та тренди ринку
📲 корисні додатки і лайфхаки
🖥 техно-новинки та апдейти ОС
🔥 інсайди без води і клікбейту
🎁 + ЗАРАЗ ІДЕ РОЗІГРАШ:
Скін у CS2 (StatTrak™) | Triarch — майже новий 🔥
💥 Хочеш шанс забрати?
👉 Підписка + кнопка «Брати участь»
🔥 Збираємо перших 100 активних бро
😎 Підписався = завжди в темі!
👇 Залітай прямо зараз
🚀 ПІДПИСАТИСЬ НА GAMETECH 🚀
❤1