// QA1 · група QA · ср 04.11.2026 · конспект заняття

Автотест з опису сценарію — і доказ, що він перевіряє

Усе із заняття QA1 в одному тексті: зміст слайдів і пояснення до них. Читайте після заняття, щоб повторити, або замість нього, якщо пропустили. Біля кожного розділу — посилання на відповідні слайди.

Зміст
  1. 1. Про заняття
    1. Автотест з опису сценарію — і доказ, що він перевіряє
    2. План: отримати тест — і перевірити тест
    3. Розбір С6 QA — у звіті перевірки
  2. 2. Зелений тест — ще не перевірений тест · основи тестування
    1. Зелений тест — ще не перевірений тест
    2. Два зелені тести — одна сторінка
    3. Доплата 10 → 12 грн: A зелений, B червоний
    4. Тест, який жодного разу не падав, — нічого не довів
    5. «Пакунок»: 11 функцій — сценарії — джерело правди
    6. Тест-кейс і автотест — та сама анатомія
    7. Словник: вісім слів, якими говорить тест
    8. Піраміда тестування — внизу багато й швидко, вгорі мало й дорого
    9. Конус морозива: коли піраміду перевернули
    10. Де який тест — у проєкті QA1
    11. Рівень — де перевіряємо, тип — що, скринька — як проєктуємо
    12. Словник QA1 — усі терміни
  3. 3. Тест зі сценарію: агенти Playwright
    1. Сценарій словами → агент з живим браузером → тест
    2. Як агент отримує тест: три способи
    3. Одна команда — три агенти і MCP-сервер
    4. Planner → generator → healer — і ви між кроками
    5. Демо 1: план і тести S1–S4
    6. Що зробив generator — і що довелося виправити
    7. Trace: запис прогону крок за кроком
    8. Healer лагодить тест — а не продукт
    9. Тест упав: що змінилося?
    10. Демо 2: дві зміни — один healer
    11. Healer зупинився — а правило все одно запишіть
  4. 4. Чи ловить тест дефект · тест-дизайн
    1. Внести дефект навмисно — і подивитися, хто впаде
    2. Тест без діагностичної цінності: як він виглядає
    3. Як працює npm run defects:check
    4. Демо 3: межа 5 → 6 кг — хто спіймав?
    5. Добрий навмисний дефект — для L1
    6. Класи еквівалентності й межі — точки вибирають, а не вгадують
    7. Комбінації і стани — таблиця рішень і переходи станів
    8. Словник 2: дублери, flaky і хибні тривоги
  5. 5. Мутаційне тестування
    1. Сотні маленьких дефектів — автоматично
    2. Два нижні поверхи — Stryker рахує лише їх
    3. Мутант: вбитий, живий або без покриття
    4. Два слабкі юніт-тести — 37,93%
    5. Живий мутант — це сценарій, якого немає в тестах
    6. Демо 4: агент пише тести — Stryker перевіряє
    7. Чесний mutation score — і що його ламає
  6. 6. Завдання QA1
    1. Завдання QA1: тест і доказ, що він ловить
    2. Проєкт koldovsky/ai-qa-ba-qa1 — старт за 15–30 хвилин
    3. Ваш варіант — функція в меню застосунку
    4. L1: тест зі сценарію і доказ дефектом
    5. L2: набір тестів, healer, порожній тест
    6. L3: юніт- і компонентні тести до 60%
    7. Як здати — один MR
  7. 7. Що далі
    1. Далі — QA2 і фінальний проєкт
    2. П'ять речей, які забираєте
    3. Ресурси
    4. Питання

1. Про заняття

Цей розділ — про початок заняття QA1: що в ньому нового, що буде за дві години і що знадобиться, щоб повторити все самостійно. Розбір завдання С6 QA був лише на занятті — у слайдах і в конспекті його немає.

#Автотест з опису сценарію — і доказ, що він перевіряє

Слайд 276

QA1 — перше заняття групи QA курсу «AI-агенти в роботі QA та BA». Воно відбулося в середу, 04.11.2026, і тривало дві години. Далі заняття груп ідуть раз на два тижні: QA2 — 18.11, QA3 — 02.12.

Агент пише автотест за хвилину. Отримати тест більше не проблема. Проблема в іншому: довести, що тест щось перевіряє. Зелений тест без суттєвих перевірок у звіті виглядає так само, як зелений тест, що ловить дефекти. Тому заняття складається з двох кроків:

  1. Отримати тест — агент з живим браузером пише тест Playwright за сценарієм.
  2. Перевірити тест — трьома способами змусити його впасти навмисно: внести дефект у код, дати healer змінену поведінку і запустити мутаційне тестування.

Строки й дати:

  • Завдання QA1 — до вівторка, 17.11.2026, 23:59.
  • Розбір QA1 — на початку QA2, у середу, 18.11.

Що нового в QA1:

  • Новий проєкт — gitlab.com/koldovsky/ai-qa-ba-qa1: навчальний вебзастосунок «Пакунок» з тестами, сценаріями і командами для перевірки тестів. Форки С1–С6 не підходять, потрібен новий форк.
  • Той самий стек, що в шаблоні фінального проєкту QA: TypeScript + Vite, Playwright 1.64, Vitest, Stryker 10. Що налаштуєте тут, знадобиться там.
  • Потрібен агент, який запускає команди. Лише чату в браузері замало: тести треба запускати. Демо — Claude Code з моделлю Sonnet; підійде будь-який агент з терміналом — Codex, GitHub Copilot, Cursor, OpenCode.
  • Варіант той самий, що в С1–С6, але тепер це функція в меню застосунку.

#План: отримати тест — і перевірити тест

Слайд 277

Після розбору С6 — чотири тематичні блоки, у трьох із них живі демо, і два короткі теоретичні: основи тестування (термінологія, піраміда, де який тест) і тест-дизайн (класи, межі, таблиця рішень, стани). Усі демо — на одній демо-функції «00 · Вартість доставки» і йдуть ланцюжком: агенти Playwright пишуть тести за сценарієм; healer лагодить тести після зміни; навмисний дефект перевіряє, чи тести його ловлять; Stryker рахує, скільки дрібних дефектів ловлять юніт-тести.

Час Що відбувається Розділ конспекту
0:00–0:15 Розбір С6 QA — зі звіту перевірки 1 · слайд 278
0:15–0:23 Зелений ≠ перевірений: два тести, одна зміна; застосунок і сценарії 2 · слайди 279–283
0:23–0:34 Основи тестування: тест-кейс → автотест, словник, піраміда, де який тест, рівні і типи 2 · слайди 284–289
0:34–0:58 Тест зі сценарію: MCP, planner → generator, healer; демо 1 і 2 3 · слайди 290–300
0:58–1:14 Чи ловить тест дефект: порожні тести, defect seeding; демо 3 4 · слайди 301–305
1:14–1:20 Тест-дизайн: класи еквівалентності й межі, таблиця рішень, стани; словник 2 4 · слайди 306–308
1:20–1:40 Мутаційне тестування: юніт і компонент, Stryker; демо 4 5 · слайди 309–315
1:40–1:52 Завдання QA1: варіант, L1–L3, здача 6 · слайди 316–322
1:52–2:00 Що далі, головне, ресурси, питання 7 · слайди 323–326

Записані прогони всіх чотирьох демо — на сторінці «Демо»: ті самі промпти, справжні відповіді агента, цифри токенів і вартості.

#Розбір С6 QA — у звіті перевірки

Слайд 278

Розбір завдання С6 QA тренер показував на занятті зі звіту перевірки в режимі показу: що вийшло добре, типові помилки змісту і здачі, найкращі роботи, бали за рівнями. На екрані був лише розбір — без імен, номерів MR і приватних нотаток. У слайдах і в конспекті розбору немає.

Відгук до вашої роботи — коментар у вашому MR С6. Не згодні з оцінкою чи коментарем — відповідайте там само.

Місток до QA1: у С6 ви перевіряли твердження агента про код — «файл і функція». Сьогодні агент пише тести, і перевірка та сама: тест каже «працює» — а що саме він перевірив? Реєстр міжсистемних сценаріїв і контракт стику з С6 знадобляться на QA2, де йдеться про API-тести.

2. Зелений тест — ще не перевірений тест · основи тестування

Цей розділ — про те, чому зелений тест ще нічого не доводить. Два тести на одну функцію, обидва зелені, і одна зміна в коді, яка показує різницю між ними. Наприкінці — застосунок «Пакунок» і сценарії, на яких побудовані демо і завдання. Друга половина розділу — основи тестування для тих, хто досі тестував вручну: як тест-кейс стає автотестом, слова, якими говорять про тести, піраміда тестування, де який тест у проєкті QA1 і чим рівень тестування відрізняється від типу. Наприкінці — словник усіх термінів заняття.

#Зелений тест — ще не перевірений тест

Слайд 279

Агент пише тест, тест проходить. Але «проходить» може означати дві різні речі: продукт поводиться правильно — або тест не перевіряє нічого суттєвого. У звіті прогону ці два випадки виглядають однаково: зелена галочка.

#Два зелені тести — одна сторінка

Слайд 280

Два тести на ту саму сторінку демо-функції «00 · Вартість доставки». Обидва написав агент, обидва зелені.

Тест A · «розрахунок працює». З тих, що агент пише, коли просиш «тест на розрахунок»: заповнити вагу, натиснути кнопку і побачити результат.

test('розрахунок працює', async ({ page }) => {
  await page.getByLabel('Вага, кг').fill('7');
  await page.getByRole('button', { name: 'Розрахувати' }).click();
  await expect(page.getByTestId('result')).toBeVisible();
});

Він перевіряє, що блок результату є на сторінці. Але блок result є на сторінці завжди: у нього вставляється і картка з сумою, і текст помилки.

Тест B · сценарій S2 «межа 5 кг». Узятий зі сценаріїв функції: 5,2 кг — це вже понад 5 кг, отже 70 + 10 = 80 грн.

test('S2 · 5,2 кг по області — 80 грн', async ({ page }) => {
  await page.getByLabel('Вага, кг').fill('5,2');
  await page.getByLabel('Маршрут').selectOption('область');
  await page.getByRole('button', { name: 'Розрахувати' }).click();
  await expect(page.getByTestId('result-lines'))
    .toContainText('До сплати: 80 грн');
});

Він перевіряє конкретне число зі сценарію — і саме над межею, де починається доплата.

#Доплата 10 → 12 грн: A зелений, B червоний

Слайд 281

Ми це запустили: змінили доплату з 10 на 12 грн у функції 00 і прогнали тести. Звіт Playwright (npm run e2e:report) показав 1 failed · 2 passed.

  • Упав лише тест зі сценарію. Playwright показує, що очікував і що отримав: «До сплати: 80 грн» проти 82 грн, з підсвіткою різниці.
  • Тест A пройшов. Блок результату видно — отже, «працює». Зміну ціни він не помітив би ніколи. У звіті він зелений поруч із червоним, і без цього прогону ви б не відрізнили його від корисного.
  • Що далі. 82 грн — дефект чи нова вимога? Може, ціну справді підняли. Вирішує не тест і не агент. Але зелений тест A не дав би навіть приводу спитати. До цього питання ми повернемося в розділі 3, коли дійдемо до healer.

У звіті є кнопка View Trace — запис прогону крок за кроком. Про неї — теж у розділі 3.

#Тест, який жодного разу не падав, — нічого не довів

Слайд 282

Головна думка заняття. Тест — це твердження «якщо продукт зламається тут, я впаду». Поки ви не бачили, як він падає, ви не знаєте, чи це твердження правдиве. Сьогодні — три способи змусити тест упасти навмисно:

Що перевіряємо Як Розділ
e2e-тест Навмисний дефект (defect seeding): зсуваємо межу чи число в коді — тест має впасти. У фінальному проєкті — команда defects:check 4
юніт-тести Мутаційне тестування: Stryker автоматично робить сотні маленьких змін і рахує, скільки спіймано. Mutation score — метрика якості тестів, а не кількості 5
healer Зміна поведінки: агент, який лагодить тести, може «полагодити» тест під дефект. Перевіряємо, чи не послабив він перевірку 3

#«Пакунок»: 11 функцій — сценарії — джерело правди

Слайд 283

Застосунок для демо і завдання — навчальний «Пакунок» вигаданого сервісу доставки: стартовий трекер посилки і 11 невеликих функцій у меню. 00 — демо тренера, 01–10 — ваші варіанти. Кожна функція — форма з полів, кнопка і картка результату або текст помилки. Стек той самий, що в шаблоні фінального проєкту QA: TypeScript + Vite, Playwright 1.64, Vitest, Stryker 10.

У кожної функції — правила і сценарії мовою користувача у materials/features/NN-назва/scenarios.md. Це вхід для агента і джерело правди для очікуваних значень. Сценарії демо-функції 00:

№ Дії Очікувано
S1 2 кг · місто «До сплати: 50 грн»
S2 5 кг · область, і 5,2 кг 70 грн · 80 грн
S3 12 кг · Україна 160 грн
S4 30,5 кг помилка, картки немає
S5 вага «два» «Поле «Вага, кг» має бути числом.»

Правила 00: місто — 50 грн, область — 70, Україна — 90, до 5 кг включно; далі +10 грн за кожен розпочатий кілограм; понад 30 кг — відмова.

Чому сценарії, а не сторінка. Агент, якого попросили «напиши тест на сторінку», подивиться, що сторінка показує, і запише це як очікуване. Якщо на сторінці дефект — тест його закріпить. Тому правило для агента: очікуване значення — зі сценарію; розходиться зі сторінкою — зупинись і скажи, це може бути дефект.

Код функцій не змінюємо: ми тестуємо код, а не підганяємо його під тести.

#Тест-кейс і автотест — та сама анатомія

Слайд 284

Якщо ви писали тест-кейси вручну, головне в автотесті ви вже вмієте. Ручний тест-кейс має три частини: передумову, кроки й очікуваний результат. Автотест Playwright складається з тих самих трьох частин. Різниця одна: кроки виконує машина, і робить це однаково щоразу.

Тест-кейс TC-00-02 «S2 над межею 5 кг» і той самий тест у коді:

Частина тест-кейсу Що в ній У коді Playwright
Передумова · Arrange відкрито сторінку /#/00-delivery-cost, дата «сьогодні» фіксована test.beforeEach: page.clock.setFixedTime(…), page.goto(…)
Кроки · Act «Вага, кг» = 5,2 · «Маршрут» = область · «Розрахувати» fill, selectOption, click
Очікуваний результат · Assert «До сплати: 80 грн» expect(…).toContainText('До сплати: 80 грн')
test.beforeEach(async ({ page }) => {
  await page.clock.setFixedTime(new Date('2026-11-04T12:00:00'));
  await page.goto('/#/00-delivery-cost');
});

test('S2 · 5,2 кг по області — 80 грн', async ({ page }) => {
  await page.getByLabel('Вага, кг').fill('5,2');
  await page.getByLabel('Маршрут').selectOption('область');
  await page.getByRole('button', { name: 'Розрахувати' }).click();
  await expect(page.getByTestId('result-lines'))
    .toContainText('До сплати: 80 грн');
});
  • Передумова — у beforeEach: вона виконується перед кожним тестом файлу. Дату фіксують, щоб тест не залежав від дня, коли його запустили.
  • Кроки — дії користувача. Поле шукають за підписом (getByLabel), кнопку — за роллю й назвою (getByRole): так, як їх бачить людина.
  • Очікуваний результат — expect. Число 80 взято зі сценарію S2 (70 грн по області + 10 грн за розпочатий кілограм понад 5), а не з того, що показала сторінка.

Схему «підготувати — діяти — перевірити» називають Arrange — Act — Assert. Це те саме, що Given / When / Then з С2.

#Словник: вісім слів, якими говорить тест

Слайд 285

Вісім термінів, які звучать на занятті весь час. Їх зручно запам'ятати трьома групами.

Що ми пишемо.

  • Тестовий сценарій (test scenario) — що перевіряємо, мовою користувача, без кліків: «посилка трохи важча за 5 кг коштує на 10 грн більше». У QA1 це S1–S5 у scenarios.md.
  • Тест-кейс (test case) — одна конкретна перевірка: передумова, кроки, очікуване. З одного сценарію виходить кілька тест-кейсів: S2 дає точки 4,9, 5 і 5,2 кг. В автотесті тест-кейс — один test('…').
  • Тестовий набір (test suite) — тести, які запускають разом: файл *.spec.ts або всі e2e через npm run e2e. Усередині файлу тести можна згрупувати через test.describe.

Як тест вирішує, зелений він чи червоний.

  • Перевірка, твердження (assertion) — рядок, що валить тест, коли факт не збігається з очікуваним: expect(…).toContainText('80 грн').
  • Тестовий оракул (test oracle) — джерело правильної відповіді. У QA1 це scenarios.md, а не те, що зараз показує сторінка. Якщо оракул — сторінка, тест закріплює дефект як правило; такі тести — у розділі 4.

На чому тест стоїть.

  • Фікстура (fixture) — готове оточення, яке тест отримує до старту: { page } від Playwright (свої фікстури роблять через test.extend). Підготовку перед кожним тестом пишуть у beforeEach — це hook. Фіксована дата page.clock.setFixedTime — це вже тестовий дублер, stub (словник 2). Тестові дані (test data) — посилки PARCELS для трекера.
  • Локатор (locator) — спосіб знайти елемент. getByRole, getByLabel — як бачить користувач; getByTestId — окрема мітка data-testid для тестів: стабільна, але користувач її не бачить. Усі три стійкіші за CSS-селектори.
  • Прогін (test run) — запуск набору плюс звіт: npx playwright test (або npm run e2e), звіт — npm run e2e:report, trace.

Тест-кейс, чек-лист і тестові дані знайомі з С2. Дублери, flaky-тести і хибні тривоги — у словнику 2 (розділ 4). Усі терміни разом — у словнику в кінці цього розділу і в шпаргалці (розділ 12).

#Піраміда тестування — внизу багато й швидко, вгорі мало й дорого

Слайд 286

Піраміду тестування описав Майк Кон у книзі «Succeeding with Agile» (2009). Її ідея: тести різних рівнів коштують по-різному, тому й кількість їх має бути різною. Знизу вгору:

Поверх Що це У QA1
юніт (модульні) одна функція правил без сторінки: мілісекунди, тестів можуть бути сотні Vitest: src/domain/*.test.ts; rules.test.ts для своєї функції пишете в L3
компонентні (UI) сторінка або UI-компонент у jsdom — без справжнього браузера: поля, картка, текст помилки Vitest + jsdom: src/app.test.ts, src/ui/parcel-card.test.ts; page.test.ts — L3
інтеграційні · контрактні стик двох систем: чи однаково вони розуміють формат даних немає; це QA2, вхід — контракт стику з С6
API сервіс без інтерфейсу: запит → відповідь немає; це QA2
e2e / UI справжній браузер, шлях користувача від початку до кінця Playwright: e2e/features/*.spec.ts
ручне · дослідницьке людина: зручність, зрозумілість, «спірне» «спірне» з плану planner, як 1e1 у полі ваги

Чим вище поверх, тим тест повільніший, дорожчий і крихкіший: e2e падає від будь-чого на шляху, від мережі до підпису кнопки. І тим менш точно він показує, де дефект. Юніт-тест, що впав, вказує на функцію і рядок. Тому внизу тестів багато, а вгорі мало.

«Компонентні» тут — у сенсі фронтенду: тест сторінки чи UI-компонента без браузера. У ISTQB «компонентне тестування» — синонім модульного, тобто юніт; детальніше — нижче, у розділі про рівні.

Ручне тестування на вершині — не «гірше» за автоматизоване. Це те, що машина не оцінить: чи зрозуміла помилка, чи зручна форма, що робити з «1e1».

Орієнтир у чистому проєкті QA1, до ваших тестів: npm test (юніт + компонентні) — 38 тестів за секунди; npm run e2e — 16 тестів приблизно за хвилину разом зі збіркою. Це орієнтир, а не закон: важить не відсоток, а щоб кожна перевірка жила на своєму поверсі.

#Конус морозива: коли піраміду перевернули

Слайд 287

Частий стан у командах, де автоматизація почалася з інтерфейсу: юніт-тестів майже немає, зате сотні e2e і тиждень ручної регресії. Фігура перевернута і схожа на ріжок морозива — звідси назва антипатерну (ice-cream cone; термін Alister Scott, 2012).

Симптоми:

  • регресія — тиждень ручних прогонів перед кожним релізом;
  • e2e червоніють від перейменованої кнопки — це хибні тривоги, і команда перестає їм вірити;
  • коли e2e справді червоний, він не каже, де дефект: у правилі, у сторінці чи в даних.

З агентами ризик більший: e2e-тест тепер коштує хвилину, і спокуса писати лише їх зростає. Відповідь — не «менше e2e», а кожну перевірку робити на найнижчому рівні, де вона можлива. Правило ціни перевіряє юніт-тест, сторінку — компонентний, шлях користувача — кілька e2e. Тому в QA1 обидва поверхи: e2e — у L1–L2, юніт і компонентні — у L3.

#Де який тест — у проєкті QA1

Слайд 288

Карта заняття: які тести є в проєкті, де вони лежать і чим перевірити самі тести. Рядки стоять як поверхи піраміди: ручне вгорі, юніт унизу.

Рівень Що перевіряє Інструмент Де в QA1 Хто зазвичай пише Як перевірити сам тест
ручне · дослідницьке зручність, зрозумілість, «спірне» людина «спірне» з плану planner: 1e1, 0x10 QA —
e2e / UI шлях користувача в браузері Playwright e2e/features/NN-….spec.ts (L1–L2) · e2e/tracking.spec.ts QA-автоматизатор, агенти Playwright npm run defects:check
API сервіс без UI: запит → відповідь — немає · QA2 QA-автоматизатор QA2
інтеграційний · контрактний стик двох систем, формат даних — немає · QA2, контракт стику з С6 обидві сторони стику + QA QA2
компонентний (UI) сторінка в jsdom: поля, картка, текст помилки Vitest + jsdom page.test.ts (L3) · src/app.test.ts · src/ui/parcel-card.test.ts розробник, автоматизатор Stryker
юніт (модульний) правило: вага + маршрут → ціна Vitest src/features/NN-…/rules.test.ts (L3) · src/domain/*.test.ts розробник; на курсі — ви з агентом Stryker, mutation score

Остання колонка — головна: defects:check і Stryker — не рівні тестів, а перевірка самих тестів. Для e2e — навмисний дефект (розділ 4), для юніт- і компонентних тестів — мутанти (розділ 5).

Команди:

  • npm test — юніт і компонентні тести;
  • npm run e2e — e2e;
  • npm run defects:check — чи ловлять e2e навмисні дефекти;
  • npm run mutation:feature -- NN — чи ловлять юніт і компонентні тести мутантів;
  • npm run coverage — які рядки виконались під час юніт- і компонентних тестів. Це ще не означає, що їх перевірено.

CI у проєкті QA1 вимкнено: усе запускаєте руками.

#Рівень — де перевіряємо, тип — що, скринька — як проєктуємо

Слайд 289

Плутанина номер один: «регресійне тестування — це рівень?». Ні. Тут три незалежні питання.

Рівень — масштаб: що саме ізолюємо. Юніт, або модульний (функція) → компонентний (UI-компонент або сторінка в jsdom) → інтеграційний (стик) → системний (уся система, e2e) → приймальний (UAT: приймання за критеріями з С2). Чим вище, тим більше системи в одному тесті.

Увага щодо назв. У ISTQB (CTFL) «компонентне тестування» — те саме, що модульне, тобто юніт, а наступний рівень — компонентне інтеграційне. На заняттях «компонентний» — у сенсі фронтенду: тест сторінки чи UI-компонента без браузера. За ISTQB такий тест ближчий до компонентного інтеграційного.

Тип — мета: що хочемо дізнатися.

  • функціональне — чи виконується правило: 5,2 кг → 80 грн;
  • нефункціональне — швидкодія, доступність, безпека, зручність;
  • підтверджувальне (confirmation testing, re-test) — виправлений дефект справді виправлено;
  • регресійне — зміна не зламала решту; разом з підтверджувальним ISTQB називає це тестуванням, пов'язаним зі змінами;
  • smoke (димове) — швидко, широко й неглибоко: застосунок узагалі працює. У QA1 це 11 тестів «розрахунок працює» в e2e/features — по одному на функцію. Тому тест A годиться як smoke, але не як перевірка правила;
  • sanity (санітарне) — вузько й глибше: конкретна зміна чи виправлення після збірки.

У глосарії ISTQB sanity test — синонім smoke test; у командах їх зазвичай розрізняють так, як вище.

Скринька — як спроєктовано тест, а не його рівень.

  • чорна — за поведінкою і scenarios.md: e2e, ручне тестування — і юніт-тест, написаний за сценарієм (як у L3). Точка 5,01 кг — теж чорна скринька: її дає правило «за кожен повний чи неповний кілограм понад 5 кг» у специфікації;
  • біла — тести, спроєктовані за кодом: гілки й умови rules.ts, живі мутанти Stryker, що ведуть у код;
  • сіра — знаєте код, але тестуєте ззовні: форма читає поле через Number(…) у src/features/form-page.ts, тож ви пробуєте 1e1 (= 10) і 0x10 (= 16) через сторінку.

#Словник QA1 — усі терміни

Терміни заняття в одному місці. Приклади — з функції 00 і трекера посилки.

Термін English Що це
тест-кейс test case Одна перевірка: передумова, кроки, очікуваний результат. В автотесті — один test('…'), напр. «S2 · 5,2 кг по області — 80 грн».
тестовий сценарій test scenario Що перевіряємо — мовою користувача, без кліків. З одного сценарію — кілька тест-кейсів: S2 → 4,9 · 5 · 5,2 кг. У QA1 — S1–S5 у scenarios.md.
тестовий набір test suite Тести, які запускають разом: файл *.spec.ts, усі e2e через npm run e2e; група всередині файлу — test.describe.
перевірка, твердження assertion (expect) Рядок, що валить тест, коли факт не збігається з очікуваним: expect(…).toContainText('До сплати: 80 грн'). Тест без суттєвих перевірок не має діагностичної цінності.
тестовий оракул test oracle Джерело правильної відповіді. У QA1 — scenarios.md, а не те, що зараз показує сторінка: інакше тест закріплює дефект.
фікстура, тестові дані fixture, test data Фікстура — готове оточення до старту: { page } від Playwright (свої — через test.extend); підготовка — у beforeEach (hook); фіксована дата page.clock.setFixedTime — це stub. Тестові дані — посилки PARCELS для трекера.
локатор locator Спосіб знайти елемент. getByRole, getByLabel — як бачить користувач; getByTestId — окрема мітка data-testid для тестів (стабільна, але користувач її не бачить). Усі три стійкіші за CSS-селектори.
прогін test run Запуск набору і звіт: npx playwright test (або npm run e2e), звіт — npm run e2e:report, trace.
тестовий дублер: stub, fake, mock, spy test double Підміна справжньої залежності. Stub (заглушка) — заготовлена відповідь (now: () => NOW, brokenApi, slowApi у src/app.test.ts). Fake — спрощена робоча версія (fakeApi шукає посилку в PARCELS). Mock — дублер, у якого перевіряють взаємодію: expect(fn).toHaveBeenCalledWith(…). Spy (шпигун) — записує виклики: vi.spyOn(obj, 'm') обгортає справжню функцію, vi.fn() — порожня функція-записувач. Mock і spy у QA1 не використовуються.
нестабільний тест flaky test То зелений, то червоний без змін у коді: залежить від часу, порядку тестів, мережі, waitForTimeout. Лікують причину, а не повторами: у QA1 дата фіксована, а локально retries: 0.
хибна тривога · пропущений дефект false positive · false negative Хибнопозитивний результат — тест червоний, а дефекту немає (зламаний локатор, flaky). Хибнонегативний — тест зелений, а дефект є (тест A з toBeVisible()). Не плутати з позитивним тестом — тестом на валідних даних.
піраміда тестування test pyramid Внизу багато швидких юніт- (модульних) і компонентних (UI) тестів, вище — менше інтеграційних і API, вгорі — мало e2e і ручних. Кожну перевірку роблять на найнижчому рівні, де вона можлива.
конус морозива ice-cream cone Антипатерн — перевернута піраміда: багато ручних і e2e, мало юніт. Регресія повільна й дорога, багато хибних тривог, червоний тест не каже, де дефект. Термін — Alister Scott (2012).
рівень тестування test level Масштаб того, що тестуємо: юніт (модульне), компонентний (UI-компонент або сторінка; не плутати з ISTQB component testing = юніт), інтеграційний (контрактний), системний (e2e), приймальний (UAT).
тип тестування test type Мета перевірки: функціональне, нефункціональне (швидкодія, доступність, безпека, зручність), пов'язане зі змінами (підтверджувальне, регресійне). Будь-який тип можна робити на будь-якому рівні.
чорна, біла, сіра скринька black, white, grey box Як спроєктовано тест, а не його рівень. Чорна — за поведінкою і scenarios.md (e2e, ручне, юніт-тест за сценарієм). Біла — за кодом (гілки rules.ts, живі мутанти Stryker). Сіра — знаєте код, тестуєте ззовні: форма робить Number(…) у form-page.ts, тож пробуєте 1e1 і 0x10 через сторінку.
димове, санітарне тестування smoke, sanity Smoke — швидко, широко й неглибоко: застосунок узагалі працює (11 тестів «розрахунок працює» в e2e/features, по одному на функцію). Sanity — вузько й глибше: конкретна зміна чи виправлення після збірки. У глосарії ISTQB sanity — синонім smoke; у командах їх зазвичай розрізняють так.
підтверджувальне, регресійне тестування confirmation testing (re-test), regression testing Разом — тестування, пов'язане зі змінами. Підтверджувальне — виправлений дефект справді виправлено. Регресія — зміна не зламала решту: npm test і npm run e2e після кожної зміни. На QA2 це робить CI автоматично.
класи еквівалентності equivalence partitioning Значення, які програма обробляє однаково, утворюють один клас; на клас — один представник. Для 00: вага ≤ 0, (0; 5], (5; 30], > 30, не число; маршрути місто, область, Україна. «Не число» відсікає форма (form-page.ts), тож цей клас — для компонентного чи e2e-тесту.
аналіз граничних значень boundary value analysis Точки на межі й поруч з обох боків: 4,99 · 5 · 5,01; 30 · 30,01; 0 · 0,01. Тут живуть дефекти «на одиницю»: < замість <=, 5 замість 6.
таблиця рішень · переходи станів decision table · state transition Таблиця рішень — коли результат залежить від комбінації умов (маршрут × вага → ціна). Переходи станів — коли поведінка залежить від стану (Створена → … → Отримана); рівні покриття — кожен стан, кожен допустимий перехід, недопустимі переходи.
покриття коду і mutation score code coverage, mutation score Покриття (npm run coverage, лише тести Vitest) — які рядки виконались: юніт-тест deliveryCost(2, 'місто'), що перевіряє лише ok, виконує розрахунок і не помітить зміну ціни. Mutation score — частка виявлених мутантів: (вбиті + timeout) / (вбиті + timeout + живі + без покриття); compile error не рахується.
навмисний дефект defect seeding Вносимо відомий дефект у код (defects/*.json: знайти → замінити), проганяємо тести й повертаємо код. Тест, що лишився зеленим, цей дефект не бачить. У QA1 — npm run defects:check.

3. Тест зі сценарію: агенти Playwright

Цей розділ — про те, як агент отримує тест зі сценарію: три способи, агенти Playwright (planner, generator, healer), як їх підключити і де між їхніми кроками ваша перевірка. Два демо: план і тести S1–S4, потім healer на двох змінах. Наприкінці — правило, яке не дає healer «полагодити» тест під дефект.

#Сценарій словами → агент з живим браузером → тест

Слайд 290

Агент без браузера вгадує локатори з коду. Агент з браузером відкриває сторінку, бачить поля й кнопки і пише тест за кроками, які щойно виконав. Playwright 1.64 дає для цього готових агентів:

  • planner — досліджує сторінку і пише план тестування;
  • generator — виконує кроки плану в браузері і записує тест;
  • healer — запускає тести, що впали, і лагодить їх.

Працюють вони через MCP-сервер playwright-test, вбудований у Playwright.

#Як агент отримує тест: три способи

Слайд 291

Агент без браузера Playwright MCP Playwright Test Agents
Що бачить код, сценарій, вивід тестів живу сторінку: дерево доступності, знімки живу сторінку і тест: запуск, пауза на помилці
Локатори вгадує з коду бере з того, що бачить генерує з того, що бачить
Як підключити нічого @playwright/mcp — окремий сервер npx playwright init-agents
Коли швидко, коли розмітка проста дослідити сторінку, ручні перевірки тести: план → тест → лагодження
  • Агент без браузера — найпростіше: «ось сценарій, напиши тест». На простій формі це часто спрацьовує, але агент не бачить, що насправді на екрані. Запускає тест — і виправляє, поки не пройде.
  • Playwright MCP (@playwright/mcp) — окремий MCP-сервер, через який агент керує браузером: відкриває сторінку, отримує дерево доступності — ролі, підписи, тексти, — натискає. Зручно досліджувати сторінку чи робити ручну перевірку руками агента.
  • Playwright Test Agents — з'явилися в Playwright 1.56, у проєкті QA1 — 1.64. Сервер playwright-test уміє те саме, що й браузерний, плюс запускати тести, ставити тест на паузу на помилці й генерувати локатори. Приходить разом із Playwright проєкту — окремо нічого ставити не треба.

MCP — Model Context Protocol — стандартний спосіб дати агенту інструменти. Тут інструменти — «відкрий сторінку», «натисни», «запусти тест», «покажи знімок». Ми вже згадували MCP у С6, коли говорили про інтеграції.

#Одна команда — три агенти і MCP-сервер

Слайд 292

У корені проєкту:

npx playwright init-agents --loop=claude

Для Claude Code команда створює:

.claude/agents/
├── playwright-test-planner.md
├── playwright-test-generator.md
└── playwright-test-healer.md     # модель sonnet
.mcp.json                         # сервер playwright-test
specs/README.md                   # сюди planner пише плани
e2e/seed.spec.ts                  # якщо вже є — не перезаписує
  • --loop — для якого агента: claude, codex, copilot, opencode, vscode. Файли створюються у форматі того агента.
  • Описи агентів — звичайні markdown-файли з інструкціями, їх можна читати й змінювати. Модель у них — sonnet.
  • .mcp.json — підключення сервера playwright-test. На Windows там cmd /c npx playwright run-test-mcp-server — так і має бути.
  • seed.spec.ts — тест, з якого агенти починають: відкриває застосунок у потрібному стані. У проєкті QA1 seed уже є, з фіксованою датою «сьогодні», і команда його не перезаписує. У новому проєкті команда створює заготовку з невикористаними змінними — у проєкті з суворою перевіркою типів збірка впаде, поки ви її не заповните.
  • Після команди перезапустіть агента в теці проєкту. Claude Code спитає, чи підключати сервер з .mcp.json, — погодьтеся.

.claude/agents/ і .mcp.json — командні налаштування: їх комітять разом із тестами.

#Planner → generator → healer — і ви між кроками

Слайд 293

  1. Planner відкриває сторінку через seed, досліджує її і пише план у specs/ — markdown зі сценаріями і кроками. Вхід — ваш scenarios.md і seed.spec.ts. Ви: план збігається зі сценаріями? Межі є?
  2. Generator бере сценарії з плану чи з вашого промпту, виконує кроки в живому браузері і записує тест з того, що реально спрацювало, — у e2e/features/NN-назва.spec.ts. Ви: що перевіряє кожен expect — і звідки очікуване значення?
  3. Тест запускаєте ви або агент. Червоний — healer: запускає, ставить на паузу на помилці, дивиться сторінку, змінює тест і запускає знову. Ви: що він змінив і чому?

#Демо 1: план і тести S1–S4

Слайд 294

Два промпти, один за одним, у Claude Code з моделлю Sonnet.

Промпт 1 — planner:

Використай агента playwright-test-planner: склади план тестування сторінки «00 · Вартість доставки» (адреса /#/00-delivery-cost) нашого застосунку. Правила функції — у materials/features/00-delivery-cost/scenarios.md. План збережи в specs/00-delivery-cost.md. Наприкінці коротко: скільки сценаріїв і які межі ти знайшов.

Промпт 2 — generator:

Прочитай materials/features/00-delivery-cost/scenarios.md. Використай агента playwright-test-generator: напиши e2e-тести для сценаріїв S1–S4 у файлі e2e/features/00-delivery-cost.spec.ts — додай нові тести, наявний тест у файлі не чіпай. Очікувані значення — зі сценаріїв. Потім запусти цей файл тестів і покажи результат.

На що дивитися:

  1. План: межі під, на і над 5 і 30 кг — чи всі є?
  2. Тест: локатори getByLabel, getByRole, getByTestId.
  3. Кожен expect — число чи текст зі сценарію.

У записаному прогоні planner дослідив сторінку в браузері — прогнав 24 вхідні значення — і записав план на 23 сценарії в 6 групах: позитивні, межа 5 кг, межа 30 кг, межа 0 кг, валідація, початковий стан. Межі — точками під, на і над 0, 5, 6 і 30 кг. Окремо він позначив спірне: запис 1e1 і 0x10 застосунок приймає як число. Це питання до власника, а не до тесту.

Після тестів — запуск і звіт:

npx playwright test e2e/features/00-delivery-cost.spec.ts
npm run e2e:report

#Що зробив generator — і що довелося виправити

Слайд 295

Фрагмент тесту із записаного прогону — назви тестів скорочено «…», S4 — у першій версії, до виправлення:

test('… S2 над межею 5 кг (5,2 кг, область) — 80 грн',
  async ({ page }) => {
  await page.getByLabel('Вага, кг').fill('5.2');
  await page.getByLabel('Маршрут').selectOption('область');
  await page.getByRole('button', { name: 'Розрахувати' }).click();
  await expect(page.getByTestId('result-lines'))
    .toContainText('До сплати: 80 грн');
});

test('… S4 понад ліміт 30 кг — помилка і без картки',
  async ({ page }) => {
  await page.getByLabel('Вага, кг').fill('30.5');
  // …
  await expect(page.getByTestId('result-error'))
    .toHaveText('Посилки понад 30 кг відділення не приймає.');
  await expect(page.getByTestId('result')).toHaveCount(0); // ✗
});
  • 6 нових тестів для S1–S4: S1, три точки S2 — 4,9, 5 і 5,2 кг, — S3 і S4. Очікувані значення — зі сценаріїв. Наявний тест у файлі generator не чіпав, як просили.
  • S4 падав. Тест перевіряв, що блоку result немає. А цей блок є на сторінці завжди — у нього вставляється і помилка, і картка. Картку позначає result-card. Головний агент запустив тести, побачив падіння і виправив перевірку на «картки result-card немає».
  • Без test.describe. Generator записав тести окремими test() поруч із наявним. Для L2 групу describe додаєте ви чи агент на ваше прохання.
  • Вага з крапкою. Generator вводить 5.2, а не 5,2, і пояснює це тим, що поле «має тип number». Насправді це текстове поле, яке приймає і кому, і крапку, — твердження агента про код теж перевіряйте.
  • Урок. Generator не запустив тести сам — запустив головний агент. Агент пише тест упевнено і помиляється в деталях, яких не видно без запуску. Тому порядок такий: запустити → прочитати кожен expect → лише тоді комітити.

#Trace: запис прогону крок за кроком

Слайд 296

Trace Viewer показує кожен крок тесту, знімок сторінки до і після, локатор, очікуване й отримане значення, консоль і мережу. На слайді — справжній trace тесту S2 після зміни доплати на 12 грн: ліворуч кроки, по центру знімок сторінки, внизу — очікуване «До сплати: 80 грн».

  • Trace записується для кожного тесту і зберігається для тих, що впали, — так налаштовано в проєкті (retain-on-failure).
  • Як відкрити: npm run e2e:report → тест → View Trace.
  • UI-режим — npm run e2e:ui: список тестів, запуск одного, кроки і знімки поруч. Зручно, коли пишете тест разом з агентом.

Агент теж може «подивитися» на сторінку — через MCP. Але trace — це ваш доказ, а не агента. Скріншот звіту чи trace показує, що тест падав і чому; кладіть його в evidence/ свого звіту.

#Healer лагодить тест — а не продукт

Слайд 297

Healer — третій агент. Його інструкція — звичайний файл .claude/agents/playwright-test-healer.md: відкрийте і прочитайте.

  • Що він робить: запускає тести, що впали → ставить на паузу на помилці → дивиться сторінку → змінює тест → запускає знову. Поки не пройде.
  • Що в його інструкції: виправляти локатори, перевірки й очікувані значення. Не ставити питань користувачу — «зробити найрозумніше, щоб тест пройшов». Безнадійний тест — позначити test.fixme().
  • Ризик. Для зміни підпису кнопки це ідеально. Для зміни поведінки — небезпечно. Сторінка показує 82 грн замість 80, і для healer «найрозумніше» — записати 82. Тест знову зелений, але тепер він захищає дефект.

#Тест упав: що змінилося?

Слайд 298

Перед тим як лагодити, класифікуйте причину: порівняйте сторінку зі scenarios.md.

Що змінилося Приклади Що робити
Реалізація, поведінка та сама підпис поля, текст кнопки, розмітка, порядок кроків; «Розрахувати» → «Порахувати вартість» лагодити локатор чи крок; очікуване не чіпати
Очікувана поведінка число, межа, текст правила, умова стоп: «сценарій каже X, сторінка показує Y» → дефект чи нова вимога?

Якщо змінилась поведінка:

  • дефект — тест лишається червоним, пишемо баг-репорт;
  • нова вимога — спершу оновлюємо scenarios.md, потім тест.

Хто вирішує «дефект чи нова вимога» — не тест і не агент, а власник продукту чи аналітик. Це правило ви запишете в правила агента в L2. Ідея та сама, що в С5: правила агента — файл, який працює в кожній сесії.

#Демо 2: дві зміни — один healer

Слайд 299

У кожній функції застосунку є дві готові зміни для L2. Їх вносить команда npm run change — код функцій руками не змінюємо.

Зміна інтерфейсу (ui-change.json): кнопку перейменовано «Розрахувати» → «Порахувати вартість». Поведінка та сама.

npm run change -- materials/features/00-delivery-cost/ui-change.json
npm run e2e        # червоні

Зміна поведінки (behaviour-change.json): доплата за кілограм понад 5 кг — 12 грн замість 10. Чи це дефект — вирішує не тест і не агент.

git checkout -- src e2e
npm run change -- materials/features/00-delivery-cost/behaviour-change.json

Промпт — однаковий для обох змін:

Після останньої зміни коду впали тести e2e/features/00-delivery-cost.spec.ts. Використай агента playwright-test-healer, щоб їх полагодити. Наприкінці — що саме змінилося і що ти виправив.

Записані прогони:

  • Зміна інтерфейсу. Healer замінив назву кнопки в усіх 7 тестах. Очікувані значення й перевірки — без змін. 7 з 7 зелені. git diff e2e показує, що змінено лише назву кнопки.
  • Зміна поведінки. Упали 2 тести — S2 (80 → 82 грн) і S3 (160 → 174 грн). Healer тести не змінив: показав «сценарій каже 80, сторінка показує 82» і спитав, дефект це чи нова вимога.

Після демо код повертається: git checkout -- src e2e.

#Healer зупинився — а правило все одно запишіть

Слайд 300

Запобіжник для healer — правило-класифікація з попереднього слайда, записане явно в правилах агента:

## Перед тим як лагодити тест

Тест упав — спершу класифікуй причину і напиши її користувачу:

- **Змінилася реалізація** (підпис, текст кнопки, розмітка), а поведінка за `scenarios.md` та сама — лагодь локатор чи крок.
- **Змінилася очікувана поведінка** (число, межа, текст правила) — **не змінюй очікуване значення в тесті**. Зупинись, покажи розбіжність «сценарій каже X, сторінка показує Y» і спитай: це дефект чи нова вимога? Тест змінюй лише після відповіді й оновленого `scenarios.md`.

Чесно про записані прогони. Ми запускали healer на зміні поведінки тричі (модель Sonnet): з правилами проєкту QA1, де AGENTS.md називає scenarios.md джерелом правди; із запобіжником; і з прибраними правилами. Усі три рази healer не змінив очікуване значення: прочитав сценарій, показав 80 проти 82 і спитав.

Чому запобіжник однаково потрібен. Інструкція healer лишається такою: «виправ очікувані значення, питань не став». Інша модель, інший агент, довга сесія з десятком тестів, що впали, — і вона може переважити. Правило записують, щоб результат не залежав від везіння.

Де записати:

  • AGENTS.md чи CLAUDE.md — діє в кожній сесії;
  • опис агента healer у .claude/agents/ — лише для нього, і його перезапише наступний init-agents.

4. Чи ловить тест дефект · тест-дизайн

Цей розділ — про перевірку e2e-тестів навмисним дефектом (defect seeding). Чотири форми тестів без діагностичної цінності, як працює команда npm run defects:check, демо 3 з дефектом межі 5 кг і правила доброго навмисного дефекту для L1. Потім — техніки тест-дизайну, які допомагають вибирати точки систематично (класи еквівалентності, граничні значення, таблиця рішень, переходи станів), і словник 2: дублери, flaky-тести, хибні тривоги, покриття.

#Внести дефект навмисно — і подивитися, хто впаде

Слайд 301

Як дізнатися, чи тест щось ловить? Зламати продукт навмисно і подивитися. Це defect seeding — посів дефектів: зсуваємо межу чи число в коді, проганяємо тести, повертаємо код. Тест, що лишився зеленим, цей дефект не бачить.

Ідея давня: якщо ви навмисно внесли десять дефектів, а тести спіймали сім, — ви знаєте ціну своїм тестам. У шаблоні фінального проєкту QA це вже автоматизовано: дефекти лежать у defects/ як JSON «знайти → замінити», а команда npm run defects:check вносить їх по одному, проганяє тести і повертає код. У проєкті QA1 команда та сама.

#Тест без діагностичної цінності: як він виглядає

Слайд 302

Чотири типові форми. Усі зелені, усі написані агентами в реальних прогонах — або дуже схожі.

1 · Перевіряє те, що є завжди. Найчастіший тест «розрахунок працює»:

await expect(page.getByTestId('result')).toBeVisible();

Блок результату є і з карткою, і з помилкою.

2 · Перевіряє заголовок, а не число.

await expect(page.getByTestId('result-title'))
  .toHaveText('Вартість доставки');

Картка з'явилася, але з якою сумою — не перевірено. Заголовок той самий за будь-якої суми.

3 · Перевіряє власний ввід.

await page.getByLabel('Вага, кг').fill('7');
await expect(page.getByLabel('Вага, кг')).toHaveValue('7');

Доводить, що поле приймає текст. Про розрахунок — нічого.

4 · Очікуване — «що показала сторінка». Найпідступніший:

// агент подивився на сторінку: 82 грн
await expect(lines).toContainText('До сплати: 82 грн');

Такий тест падає, коли дефект виправляють, і зелений, поки дефект живе. Він закріплює дефект як правило.

Як їх знайти: прочитати кожен expect і спитати «що має зламатися в продукті, щоб це впало?». Якщо відповідь «нічого» або «сторінка не відкриється» — тест без діагностичної цінності. А довести це — навмисним дефектом.

#Як працює npm run defects:check

Слайд 303

Дефект — JSON-файл: ідентифікатор, опис і список змін «у файлі знайти рядок → замінити». Наприклад, дефект демо 3:

{
  "id": "D-04",
  "title": "Доплата починається понад 6 кг замість понад 5 кг",
  "changes": [{
    "file": "src/features/00-delivery-cost/rules.ts",
    "find": "export const INCLUDED_KG = 5;",
    "replace": "export const INCLUDED_KG = 6;"
  }]
}

Скрипт бере дефекти по одному:

  1. вносить зміну в src/;
  2. збирає застосунок і проганяє e2e-тести;
  3. упав хоч один тест — «спіймано ✓», жоден — «пропущено ✗»;
  4. повертає код і дописує результат у reports/defects/summary.md — таблицю з назвами тестів, що впали. Її ви вставляєте у звіт L1.
  • Рядок find — точно один раз у файлі. Інакше скрипт зупиняється.
  • Код після перевірки повертається сам.
  • Лише ваш дефект: npm run defects:check -- --only D-04.

У чистому проєкті QA1 defects:check показує «спіймано 3 з 3» — це три дефекти шаблону в трекері посилки. Той самий формат — у шаблоні фінального проєкту QA.

#Демо 3: межа 5 → 6 кг — хто спіймав?

Слайд 304

Промпт:

Перевір, чи мають наші тести для функції 00 діагностичну цінність. Додай навмисний дефект defects/D-04-extra-kg-boundary.json (формат — defects/README.md): у src/features/00-delivery-cost/rules.ts доплата починається не понад 5 кг, а понад 6 кг (заміни рядок `export const INCLUDED_KG = 5;`). Запусти npm run defects:check і поясни: які тести спіймали дефект, а який тест функції 00 пройшов з дефектом і чому.

Результат записаного прогону — «спіймано 1 з 1»:

Тест Вага Результат з дефектом Чому
S1 2 кг зелений нижче обох меж — доплати немає ні з 5, ні з 6
S2 під межею 4,9 кг зелений те саме
S2 на межі 5 кг зелений те саме: межа зсунулась угору, а не вниз
S2 над межею 5,2 кг впав ✓ з дефектом доплати ще немає: 70 грн замість 80
S3 12 кг впав ✓ доплата за 6 кг замість 7: 150 грн замість 160
S4 30,5 кг зелений помилка ліміту спрацьовує до розрахунку доплати
«розрахунок працює» 7 кг зелений сума змінилася (80 замість 90), але тест перевіряє лише toBeVisible()

Агент сам запропонував посилити тести точками 5 → 5,01 → 6 → 6,01 кг.

#Добрий навмисний дефект — для L1

Слайд 305

Так:

  • Правило вашого варіанту зі scenarios.md: межа, число, умова. Найкорисніші — на межі: «не пізніше ніж» стало «раніше ніж», 7 днів стало 8.
  • Одна зміна — як помилка, яку міг би зробити розробник: <= → <, 5 → 6, пропущена перевірка.
  • Видно на сторінці: інше число, немає помилки, зайва помилка. E2E-тест бачить лише сторінку.
  • Ваш тест його ловить — і ви знаєте, який саме.

Ні:

  • Ламає збірку чи всю сторінку — впаде будь-який тест, це нічого не доводить.
  • Зміна, якої не видно: перейменована змінна, коментар.
  • Дефект під тест, який уже є. Порядок — спершу дефект з правила, потім перевірка, чи ловить.
  • Зміна чужої функції чи form-page.ts.

Файл — defects/NN-коротка-назва.json, формат як у D-04. Запуск — npm run defects:check, у звіт — таблиця з reports/defects/summary.md.

#Класи еквівалентності й межі — точки вибирають, а не вгадують

Слайд 306

У демо 3 одна точка на межі зловила зсув межі лише в один бік. Як вибирати точки систематично, а не «на око»? Для цього є дві класичні техніки тест-дизайну.

Класи еквівалентності (equivalence partitioning). Значення, з якими програма поводиться однаково, утворюють один клас. Для програми 2 і 3 кг — те саме, тож на клас досить одного представника. Для ваги у функції 00 класів п'ять:

Клас ваги Що робить програма Представник
≤ 0 помилка −1 кг
(0; 5] базова ціна маршруту 2 кг
(5; 30] база + 10 грн за кожен розпочатий кілограм понад 5 12 кг
> 30 відмова 31 кг
не число, порожнє поле помилка (перевіряє форма — form-page.ts; юніт-тест rules.ts сюди не дістане) «два»

Плюс маршрут — ще три класи: місто, область, Україна. Невалідні класи (≤ 0, > 30, не число) — теж класи, і тест на кожен потрібен.

Клас «не число» — підказка, де живе тест. Форма читає поле в src/features/form-page.ts і відсікає порожнє поле й «два» ще до функції правил: deliveryCost отримує вже число. Тож цей клас перевіряють компонентним або e2e-тестом, а не юніт-тестом rules.ts.

Граничні значення (boundary value analysis). Дефекти живуть на межах класів, бо розробник найчастіше помиляється «на одиницю»: < замість <=, 5 замість 6. Тому точки ставлять на межі і поруч з обох боків. Для маршруту «область»:

Межа Точки Очікувано
0 кг 0 · 0,01 помилка · 70 грн
5 кг 4,99 · 5 · 5,01 70 · 70 · 80 грн
30 кг 30 · 30,01 320 грн · відмова

Двоточковий варіант — точка на межі й найближча за нею (5 і 5,01). Триточковий — ще й точка перед межею (4,99, 5 і 5,01).

У сценарії S2 точки інші — 4,9 · 5 · 5,2 кг. Вони теж під і над межею; 4,99 і 5,01 — найближчі при кроці 0,01 кг. Крок — домовленість: поле приймає будь-який дріб (і 5,001 коштує 80 грн), тож його уточнюють у власника. А правило «за кожен розпочатий кілограм» робить межею кожен цілий кілограм: 6 кг → 80 грн, 6,01 кг → 90 грн. Межу 6 кг planner теж запропонував у демо 1. Зсув «на одиницю» — саме те, що вносив дефект у демо 3 (5 → 6 кг) і що робить мутант Stryker > → >= (розділ 5).

#Комбінації і стани — таблиця рішень і переходи станів

Слайд 307

Ще дві техніки — для випадків, коли результат залежить не від одного поля.

Таблиця рішень (decision table) — коли результат залежить від комбінації умов. Для функції 00 це маршрут і вага. Колонки — класи ваги, 5,2 кг — представник класу (5; 30]:

Маршрут \ вага (0; 5] кг 5,2 кг > 30 кг
місто 50 грн 60 грн відмова
область 70 грн 80 грн відмова
Україна 90 грн 100 грн відмова

Три маршрути на три класи ваги — дев'ять комбінацій. Але правило «понад 30 кг — відмова незалежно від маршруту» зводить останню колонку до однієї перевірки: виходить 7 тестів. Класи ≤ 0 і «не число» теж не залежать від маршруту — ще 2 тести, усього 9. Клітинка, якої немає в тестах, — сценарій, якого ніхто не перевірив.

Переходи станів (state transition) — коли поведінка залежить від стану. Приклад — трекер посилки зі стартового застосунку (src/domain/status.ts): статуси «Створена» → «Прийнята у відділенні» → «В дорозі» → «Прибула у відділення» → «Отримана».

У техніки є рівні покриття: кожен стан → кожен допустимий перехід → недопустимі переходи. У QA1 статус приходить готовим із даних (PARCELS), а код лише показує його: назву, крок, шкалу. Тож тут тестують кожен стан.

Що тестуємо:

  • кожен стан: назву і шкалу прогресу («Створена» — 0%, «Отримана» — 100%);
  • очікувану дату доставки — вона є лише в станах «Прийнята у відділенні» і «В дорозі»;
  • стан без шкали: «Повертається відправнику» — картка без прогресу (progressPercent повертає null).

#Словник 2: дублери, flaky і хибні тривоги

Слайд 308

Слова, які знадобляться в розділі 5 і в розмовах з розробниками.

Тестові дублери (test doubles) — підміни справжньої залежності. У компонентних тестах сторінку відрізають від сервера і годинника, щоб тест був швидким і передбачуваним.

Дублер Що робить У QA1
stub (заглушка) повертає заготовлену відповідь now: () => NOW, brokenApi (сервер падає), slowApi (відповідає повільно) у src/app.test.ts; page.clock.setFixedTime(…) у e2e
fake (фейк) спрощена робоча версія fakeApi у src/app.test.ts шукає посилку в масиві PARCELS замість сервера
mock дублер, у якого перевіряють взаємодію: expect(fn).toHaveBeenCalledWith(…) — (у проєкті не використовуються; приклад з Vitest)
spy (шпигун) записує виклики: vi.spyOn(obj, 'm') обгортає справжню функцію і за замовчуванням викликає її; vi.fn() — порожня функція-записувач — (у проєкті не використовуються; приклад з Vitest)

У розмові всі вони — «моки». Уточнюйте, що саме мається на увазі.

Чотири результати тесту. Що каже тест — і чи є дефект насправді:

Дефект є Дефекту немає
Тест червоний справжня тривога ✓ хибна тривога (false positive): зламаний локатор після зміни інтерфейсу, flaky-тест
Тест зелений пропущений дефект (false negative): тест A з toBeVisible() усе добре ✓

Найнебезпечніший кут — пропущений дефект: його не видно, поки не внесеш дефект навмисно. Саме про це розділ 4. Не плутайте: позитивний тест — тест на валідних даних, а хибнопозитивний — результат тесту.

Flaky — нестабільний тест: то зелений, то червоний без змін у коді. Причини — час, порядок тестів, мережа, waitForTimeout. Лікують причину, а не повторами: у проєкті QA1 дата у тестах фіксована, а локально retries: 0, щоб повтор не ховав нестабільність.

Покриття ≠ перевіреність. npm run coverage (лише тести Vitest) показує, які рядки й гілки виконались. Юніт-тест deliveryCost(2, 'місто'), що перевіряє лише ok, виконує весь розрахунок — і не помітить зміну ціни. Mutation score показує інше: чи помітили б тести зміну рядка. Про це — розділ 5.

Усі терміни заняття — у словнику в розділі 2.

5. Мутаційне тестування

Цей розділ — про перевірку юніт- і компонентних тестів мутаційним тестуванням. Два нижні поверхи піраміди, як Stryker робить мутантів і рахує mutation score, реальний прогін з двома слабкими тестами, живі мутанти як пропущені сценарії, демо 4 і чесний бал.

#Сотні маленьких дефектів — автоматично

Слайд 309

Defect seeding — ви вносите дефекти руками, по одному. Мутаційне тестування робить те саме автоматично. Stryker змінює код по одній дрібниці — > на >=, + на -, текст на порожній — і щоразу проганяє юніт-тести. Кожна така зміна — мутант. Упав хоч один тест — мутанта вбито. Жоден — мутант вижив, і це місце, де ваші тести сліпі.

Mutation score — частка вбитих мутантів. Це метрика якості тестів, а не їхньої кількості. У фінальному проєкті QA поріг — 60%.

#Два нижні поверхи — Stryker рахує лише їх

Слайд 310

Це два нижні поверхи піраміди тестування (розділ 2, «Піраміда тестування» і «Де який тест»). Тут — лише те, що важливо для Stryker.

Рівень Що робить Інструмент Як перевіряємо тести
юніт · rules.test.ts викликає функцію правил напряму: deliveryCost(5.2, 'область') → 80 грн. Мілісекунди; межі — десятками Vitest mutation score
компонентний · page.test.ts монтує сторінку функції в jsdom через mountFeature: поля, кнопка, картка, текст помилки. Без браузера Vitest mutation score
e2e · *.spec.ts справжній браузер, зібраний застосунок, користувацький сценарій. Секунди на тест Playwright defects:check, не Stryker

Юніт-тест не потребує сторінки: вага і маршрут на вході, результат на виході. Тому кожну межу можна перевірити трьома точками:

it('межа 5 кг: 5 — 70 грн, 5,01 — 80 грн', () => {
  expect(deliveryCost(5, 'область')).toEqual(ok('Вартість доставки', ['Маршрут: область', 'До сплати: 70 грн']));
  expect(deliveryCost(5.01, 'область')).toEqual(ok('Вартість доставки', ['Маршрут: область', 'До сплати: 80 грн']));
});

jsdom — це DOM без браузера, у Node. Компонентний тест перевіряє, що форма читає поля, показує картку і текст помилки. Як монтувати сторінку — приклад у src/app.test.ts.

Stryker проганяє лише Vitest — юніт і компонентні тести. E2E на mutation score не впливають: Stryker їх не запускає, бо один прогін e2e займає хвилину, а мутантів — десятки.

#Мутант: вбитий, живий або без покриття

Слайд 311

З одного рядка Stryker робить кілька мутантів: змінює оператор порівняння, замінює умову на true чи false, текст — на порожній рядок, арифметику — на протилежну. Наприклад, з if (w > 30) у rules.ts:

  • мутант 1 — if (w >= 30);
  • мутант 2 — if (false);
  • мутант 3 — fail(''), порожній текст помилки.

Для кожного мутанта — прогін npm test:

Результат Що сталося Що означає
killed ✓ тест упав тести помітили б таку помилку
survived ✗ усі тести зелені тести не помітили б таку помилку
no coverage ✗ жоден тест не виконує цей рядок тестів тут просто немає

Mutation score = (вбиті + timeout) / (вбиті + timeout + живі + без покриття). Timeout — мутант, через який тести зависли; Stryker теж рахує його виявленим. Поріг у проєкті — 60%: нижче — команда завершується помилкою.

  • Compile error — мутант, якого не пропускає TypeScript. У бал не входить.
  • Еквівалентний мутант — зміна, яку не видно ззовні. Чесно вбити його неможливо: у звіті пишете, чому він еквівалентний, а не підганяєте тест.

#Два слабкі юніт-тести — 37,93%

Слайд 312

Реальний прогін з двома навмисно слабкими юніт-тестами для функції 00: легка посилка по місту і «важка посилка — помилка» лише з перевіркою ok: false.

npm run mutation:feature -- 00

Команда запускає Stryker лише на теці функції 00 — приблизно 20 секунд. Повний npm run mutation по всьому src/ у завданні не потрібен.

Звіт — reports/mutation/index.html:

  • усі файли — 37,93%, нижче порогу 60: команда завершується з помилкою;
  • page.ts — 0%: компонентних тестів немає, 11 мутантів без покриття;
  • rules.ts — 61,11%: тести є, 11 мутантів вбито, але 6 вижили. Два тести — і вже «понад поріг» на rules.ts. Але подивимося, що саме вижило.

#Живий мутант — це сценарій, якого немає в тестах

Слайд 313

Кожен живий мутант читається як питання «а що, якби розробник помилився тут?». У звіті Stryker живі мутанти — червоні позначки в рядках коду.

Рядок Що змінив Stryker Яке правило показує Який тест додати
16 > → >= межа 30 кг: рівно 30 — ще приймаємо 30 кг — картка; 30,01 — помилка
18 + → -, * → / доплата понад 5 кг 5,2 кг — 80 грн, а не лише «ok»
15–16 текст помилки → "" текст відмови для користувача перевірити точний текст помилки
  • Рядок 16. Якщо рівно 30 кг почнуть відхиляти, тести не помітять: межа 30 кг перевірена лише значенням 30,5. Потрібні точки на і над межею.
  • Рядок 18. Доплату почали б віднімати — тест «важка посилка» перевіряє лише, що результат не помилка, а не суму.
  • Текст помилки. Тести перевіряють, що помилка є, але не яка. Користувач побачив би порожнє повідомлення.

#Демо 4: агент пише тести — Stryker перевіряє

Слайд 314

Промпт:

Напиши юніт-тести для src/features/00-delivery-cost/rules.ts і компонентні тести для сторінки (page.ts через mountFeature у jsdom) за сценаріями з materials/features/00-delivery-cost/scenarios.md. Запусти npm test, потім npm run mutation:feature -- 00. Покажи мутаційний бал, розбери мутантів, що вижили: який сценарій чи межу вони показують. Підсиль тести і запусти мутаційне тестування ще раз. Наприкінці — бал до і після.

Записаний прогін, Sonnet, близько 2,5 хвилини:

Перша версія тестів Після підсилення
Mutation score 89,66% (26 вбито, 3 вижили) 96,55% (28 вбито, 1 вижив)
rules.ts 94,44% 100%
page.ts 81,82% 90,91%

Живі мутанти, які агент розібрав:

  • >= на межі 30 кг — додав тести 30 кг (приймається) і 30,01 кг (відмова);
  • порожній вступний текст сторінки — додав перевірку точного тексту;
  • порожнє значення пункту «місто» у списку маршрутів — агент пояснив, що браузер і так вибирає перший пункт, тобто мутант еквівалентний, і не став перевіряти розмітку.

Остання поведінка правильна: тест під реалізацію гірший за чесно пояснений живий мутант.

#Чесний mutation score — і що його ламає

Слайд 315

Так бал піднімають нечесно:

  • знизити поріг у stryker.config.mjs;
  • поставити // Stryker disable над «незручним» рядком;
  • написати тест, що повторює реалізацію: те саме 70 + ceil(w − 5) × 10 в тесті, що й у коді. Такий тест вбиває мутантів, але разом із кодом повторить і помилку в правилі;
  • взяти очікуване з виводу функції, а не зі сценарію.

Агент, якому сказали «досягни 60%», може зробити будь-що з цього. Тому в AGENTS.md проєкту QA1 це заборонено. У вашому робочому проєкті допишіть таке саме.

Так бал стає правдою:

  • очікувані значення — зі scenarios.md;
  • кожна межа — під, на і над;
  • текст помилки — точно, а не «є помилка»;
  • живий мутант — або новий тест, або пояснення, чому еквівалентний.

E2E-тести на mutation score не впливають: Stryker проганяє лише Vitest. Для e2e — defects:check. Разом це дві відповіді на одне питання: «чи ловлять мої тести дефекти?»

6. Завдання QA1

Цей розділ — про завдання QA1: проєкт і швидкий старт, ваш варіант, рівні L1–L3 і як здати. Усе, що ми зробили в чотирьох демо, тільки на функції вашого варіанту: демо 1 і 3 — це L1, демо 2 і порожні тести — L2, демо 4 — L3. Повний текст завдання — у README проєкту.

#Завдання QA1: тест і доказ, що він ловить

Слайд 316

Той самий застосунок «Пакунок», функція вашого варіанту.

  • L1 — тест зі сценарію і навмисний дефект.
  • L2 — набір тестів, healer і тест без діагностичної цінності.
  • L3 — юніт- і компонентні тести до mutation score 60%.
Строк до вівторка, 17.11.2026, 23:59 — два тижні
Розбір на QA2, у середу, 18.11
Проєкт новий — koldovsky/ai-qa-ba-qa1
Варіант той самий, що в С1–С6
Інструмент агент, що запускає команди в терміналі

#Проєкт koldovsky/ai-qa-ba-qa1 — старт за 15–30 хвилин

Слайд 317

Кроки — у README проєкту, розділ «Швидкий старт». Після Fork на gitlab.com, у cmd або Git Bash:

git clone https://gitlab.com/ваш-username/ai-qa-ba-qa1.git
cd ai-qa-ba-qa1
git config user.email …@users.noreply.gitlab.com
git switch -c qa1
npm ci
npx playwright install chromium
npm test                  # 38 passed
npm run e2e               # 16 passed
npm run defects:check     # спіймано 3 з 3
npx playwright init-agents --loop=claude   # або codex, copilot…
  • Що потрібно: Node.js 24 LTS (або 22.22.2+), Git, близько 1 ГБ на диску і агент, що запускає команди.
  • Форк, клон свого форку, приватна пошта для комітів — як у С1–С6, без --global.
  • npm ci і браузер Chromium — один раз. Якщо 38 юніт-тестів і 16 e2e пройшли, а defects:check показав 3 з 3, — середовище готове.
  • init-agents — для вашого агента. Без агентів Playwright теж можна: попросіть свого агента написати і запустити тест.

Якщо щось не стає — питання в чат групи цього тижня, а не 17-го ввечері.

#Ваш варіант — функція в меню застосунку

Слайд 318

Варіант — за першою літерою прізвища, той самий номер, що в С1–С6. Теми — ті самі функції «Пакунка», що в С1–С5, але правила нові, прості й однозначні: тут важливе тестування, а не аналіз вимог.

Прізвище № Функція
А Б 01 Слот кур'єра
В Г Ґ 02 Відмова від посилки
Д Е Є Ж З 03 Довірена особа
И І Ї Й К 04 Кур'єр за посилкою
Л М 05 Претензія про пошкодження
Н О П 06 Оплата бонусами
Р 07 Часткова оплата
С 08 Повідомлення
Т У Ф Х 09 Комірка поштомату
Ц Ч Ш Щ Ю Я 10 Промокод

Код функції — src/features/NN-…. У кожній функції є все для завдання: scenarios.md з правилами і сценаріями, один «порожній» тест, а також ui-change.json і behaviour-change.json для L2.

Відкрийте застосунок — npm run dev — і свою функцію в меню. Прочитайте scenarios.md своєї функції до того, як просити агента. Функція 00 — демо, не варіант.

#L1: тест зі сценарію і доказ дефектом

Слайд 319

Файл тестів — e2e/features/NN-назва.spec.ts.

  1. Щонайменше 2 сценарії зі scenarios.md вашого варіанту, один — з межею. Для межі — точки під, на і над, як у демо 3.
  2. Агент пише тести; ви запускаєте: npx playwright test e2e/features/NN-назва.spec.ts — зелені. Можна і агентом, але вивід запуску у звіті обов'язковий.
  3. Читаєте самі: що перевіряє кожен expect і звідки очікуване значення — сценарій, а не сторінка. Що виправили після агента — у звіт; це плюс, а не мінус.
  4. Навмисний дефект defects/NN-коротка-назва.json на правило варіанту → npm run defects:check → ваш тест спіймав. Лише свій дефект — --only з його id.
  5. Токен-звіт — як у С5–С6: цифри агента або оцінка, і одне речення, як зменшити.

У звіті: промпт дослівно, вивід запуску, таблиця «тест → що перевіряє → звідки очікуване», таблиця з reports/defects/summary.md.

  • Наявний тест у файлі в L1 не чіпайте — він знадобиться в L2.
  • Будь-який агент — Test Agents, Playwright MCP чи агент без браузера — зараховується однаково.

#L2: набір тестів, healer, порожній тест

Слайд 320

  1. Набір із щонайменше 3 тестів за конвенціями Playwright: test.describe, beforeEach, локатори getByRole / getByLabel / getByTestId. Без waitForTimeout і CSS-селекторів. Серед тестів — помилка і межа.
  2. Healer після зміни інтерфейсу. Спершу закомітьте тести — щоб потім побачити diff healer і повернути все однією командою. Далі npm run change -- …/ui-change.json → червоні → healer → зелені. У звіт: що змінив healer і чи не послабив перевірки.
  3. Запобіжник. behaviour-change.json → що зробив healer? Потім правило-класифікація в правилах агента → ще раз → різниця. Пишіть чесно, що сталося: якщо агент зупинився і без правила — напишіть, що саме його зупинило.
  4. Тест без діагностичної цінності. У вашому файлі e2e/features/ він уже є, зелений. Знайти, довести дефектом, що дефект проходить крізь нього, і виправити, щоб тест перевіряв результат.

Після кожної вправи — git checkout -- src e2e. Код функцій не змінюємо — лише npm run change.

#L3: юніт- і компонентні тести до 60%

Слайд 321

Файли — src/features/NN-назва/*.test.ts.

  1. Юніт-тести rules.ts і компонентні тести сторінки — mountFeature у jsdom; приклад — src/app.test.ts.
  2. npm run mutation:feature -- NN → бал до — з першої спроби.
  3. Щонайменше 3 живі мутанти з розбором, як у таблиці на слайді 313: що змінив Stryker → яке правило чи межу показує → який тест додали → вбито.
  4. Бал після ≥ 60%. Без змін stryker.config.mjs, без // Stryker disable, без .skip. Будь-яке послаблення не зараховується.
  5. Одне речення: чому e2e не впливають на mutation score — своїми словами.
  • Звіт Stryker — reports/mutation/index.html; скріншот файлу з мутантами можна покласти в evidence/.
  • Повний npm run mutation не потрібен: функції інших варіантів без тестів, тож загальний бал буде нижчим — це очікувано.
  • Еквівалентний мутант не вбивається — поясніть у звіті, чому. Не підганяйте тест під розмітку.

#Як здати — один MR

Слайд 322

Тести і дефект лишаються там, де їх бачать Playwright і Stryker. Звіт — за шаблоном templates/qa1-report.md.

ai-qa-ba-qa1/                    # ваш форк · гілка qa1
├── e2e/features/NN-назва.spec.ts       # L1–L2
├── defects/NN-коротка-назва.json        # L1
├── src/features/NN-назва/*.test.ts      # L3
└── submissions/ваш-username/
    ├── qa1.md                           # звіт за шаблоном
    └── evidence/                        # за бажанням
  • Merge request: source — ваш форк, гілка qa1 → target koldovsky/ai-qa-ba-qa1, main. Шаблон опису — QA1. Назва: QA1 · username · варіант NN. Виправлення після рев'ю — у той самий MR.
  • Бали: до 10 за кожен рівень за частинами, рівні окремо, як у С3–С6. Формальності — до −2 за роботу. Відгук — коментар у MR.
  • Строк: вівторок, 17.11, 23:59. Розбір — на QA2, у середу, 18.11.

7. Що далі

Цей розділ — про те, що буде після QA1: заняття QA2 і QA3, зв'язок із фінальним проєктом, п'ять головних думок заняття, ресурси і відповіді на типові питання.

#Далі — QA2 і фінальний проєкт

Слайд 323

Коли Що Деталі
вт 17.11, 23:59 строк завдання QA1 один MR у проєкт QA1
ср 18.11 QA2 · API-тести, регресія і автоматичний запуск агент будує API-тести з опису сервісу: позитивні, негативні, межові. Регресійний набір запускається при кожній зміні — GitLab CI. На початку — розбір QA1; вхід — контракт стику і реєстр міжсистемних сценаріїв з С6
ср 02.12 QA3 · Діагностика дефектів. Підсумок від збою до першопричини: чому впав тест у CI, відтворення, локалізація, чернетка виправлення з регресійним тестом. Без завдання; розбір типових зауважень перед поданням фінального проєкту
пн 14.12, 23:59 подання фінального проєкту —

Фінальний проєкт QA: усе сьогоднішнє — його частина. У шаблоні ті самі команди: e2e на кожен потік, defects:check, mutation score ≥ 60%. Агенти Playwright підключаються так само — init-agents. Не відкладайте до грудня.

#П'ять речей, які забираєте

Слайд 324

  1. Тест, що не падав, — не доказ. Зелений тест без перевірок виглядає так само, як корисний. Різницю показує лише навмисний дефект. (Розділи 2 і 4.)
  2. Очікуване — зі сценарію. Не «що показала сторінка». Інакше тест закріплює дефект як правило. (Розділи 2 і 3.)
  3. Межа — три точки. Під, на і над. Одна точка ловить зсув лише в один бік: тест «на межі» 5 кг не спіймав зсув угору. (Демо 3.)
  4. Healer лагодить тест, а не продукт. Змінилась реалізація — лагодь. Змінилась поведінка — стоп і питання: дефект чи нова вимога? Правило — у правилах агента. (Демо 2, L2.)
  5. Mutation score — якість, а не кількість. Живий мутант — сценарій, якого немає в тестах. Бал піднімають тестами, а не порогом. (Розділ 5, демо 4.)

#Ресурси

Слайд 325

Питання між заняттями — у Telegram-чат когорти, гілка QA.

#Питання

Слайд 326

Агент напише тест за хвилину. Довести, що тест щось перевіряє, — ваша робота: навмисний дефект, мутант, питання «дефект чи нова вимога?».

Типові питання і короткі відповіді:

  • «Агента Playwright немає для мого інструмента?» init-agents підтримує claude, codex, copilot, opencode, vscode. Інакше — ваш агент пише і запускає тест сам; зараховується однаково.
  • «Лише чат у браузері?» Для QA1 замало: тести треба запускати. Агент з терміналом — обов'язково.
  • «Chromium заблоковано?» PW_CHANNEL=msedge, як у README.
  • «Healer зупинився і без правила — L2.3 не вийде?» Вийде: напишіть, що його зупинило, і додайте правило однаково.
  • «Mutation score нижче 60% на всьому проєкті?» Рахуємо лише вашу функцію: mutation:feature -- NN.
  • «Можна змінити код функції, щоб тест пройшов?» Ні. Розбіжність зі сценарієм — знахідка для звіту.
  • «Робочий проєкт?» Лише за політикою компанії; у публічних MR — ніколи.