vyvchy
    Теми розділу

    13 · Співбесіда

    Лайвкодинг для AQA

    Зміст

    Лайвкодинг (live coding) — це коли на технічній співбесіді тебе просять писати код прямо зараз, з інтерв'юером за плечем: розв'язати невелику задачку, накидати автотест на живу сторінку або розібрати чужий код. Для більшості кандидатів, що переходять з мануального тестування в автоматизацію, це найстрашніший етап — не тому, що задачі складні, а тому, що доводиться думати вголос під наглядом, і будь-яка пауза здається провалом.

    Головне непорозуміння, через яке валяться навіть сильні кандидати: лайвкодинг перевіряє не те, чи напишеш ти ідеальний код без єдиної помилки. Він перевіряє, як ти думаєш — чи вмієш розкласти задачу, поставити уточнювальні питання, згадати крайові випадки, зреагувати на підказку. Робочий код — приємний бонус, але інтерв'юер бачив сотні розв'язків FizzBuzz; його цікавить процес, а не відповідь. Ця глава — про формати, критерії оцінки й тактику, а не про самі задачі: банк алгоритмічних задач із розв'язками живе в розділі «JavaScript/TypeScript для AQA» (глава про live coding), а розбір «протестуй поле/форму» — у розділі «Тест-дизайн».

    Що ним насправді перевіряють

    Чому взагалі змушують кодити наживо, а не надсилають задачу поштою? Бо письмове тестове завдання (тестове завдання) показує результат, а лайвкодинг показує шлях. Інтерв'юер моделює робочу ситуацію — маленьку фічу, за розв'язанням якої можна спостерігати в реальному часі — і дивиться на речі, які в готовому коді не видно:

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

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

    Звідси головний, контрінтуїтивний висновок: правильний, але мовчазний розв'язок часто програє неідеальному, але добре проговореному. Бал ставлять за думання, яке видно, а не за думання, яке відбулося у тебе в голові.

    Три формати лайвкодингу

    Під «лайвкодингом для AQA» ховаються три різні жанри, і готуватися до них треба по-різному:

    ФорматЩо просятьЩо перевіряють насамперед
    Алгоритмічна задачаНаписати функцію: реверс рядка, дублікати в масиві, retry-обгорткуБіглість у мові, крайові випадки, декомпозиція
    Автотест наживоНаписати локатор або тест на живу сторінкуСтратегію локаторів, очікування, структуру тесту
    Рев'ю кодуЗнайти проблеми в готовому шматку тестуЧи бачиш флак і крихкість, чи пояснюєш «чому»

    Далі — про кожен формат окремо: що саме дають, на що дивляться і де підстелити соломки.

    Формат 1: алгоритмічна задача

    Це найближче до класичного програмістського лайвкодингу, але для QA задачі майже завжди прикладні, а не олімпіадні. Динамічного програмування чи графів тут майже не буває — натомість дають те, що ти реально робиш у тестовому коді щодня. Типові категорії (повний банк із розв'язками — у розділі «JavaScript/TypeScript для AQA»):

    • рядки — реверс, паліндром, частотний словник символів чи слів;
    • масиви — дублікати, унікальні значення, перетин двох масивів, сортування об'єктів;
    • масив об'єктів як тестові дані — відфільтрувати, згрупувати, порахувати агрегат (типовий кейс: «ось список замовлень — порахуй суму по кожному статусу»);
    • асинхронні задачі — retry із затримкою, послідовні запити, обмеження паралельності;
    • FizzBuzz-клас — прості задачі на розгалуження, щоб просто побачити, що ти пишеш синтаксично коректний код.

    Чому саме ці, а не абстрактні LeetCode-задачі: вони дзеркалять роботу AQA — трансформувати тестові дані, дедуплікувати, полінгом дочекатися async-стану. Рівень очікувань зростає з грейдом: від trainee/junior чекають рядки й масиви, від middle — впевнену роботу з масивами об'єктів і async.

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

    // Задача: порахувати, скільки разів кожне слово трапляється в рядку.
    // Проговорюємо ВГОЛОС перед кодом:
    //  - регістр враховуємо? ("The" і "the" — одне слово чи різні?)
    //  - розділювач лише пробіл, чи ще пунктуація/переноси?
    //  - порожній рядок → повертаємо порожній об'єкт, не падаємо.
    
    function wordFrequency(input: string): Record<string, number> {
      const counts: Record<string, number> = {};
      for (const word of input.toLowerCase().split(/\s+/).filter(Boolean)) {
        counts[word] = (counts[word] ?? 0) + 1;
      }
      return counts;
    }

    Наївне робоче рішення на цьому етапі важливіше за елегантне. Спершу зроби, щоб працювало, вголос назви крайові випадки — і лише потім, якщо лишається час, оптимізуй.

    Формат 2: «напиши локатор / тест для сторінки»

    Це специфічно AQA-формат, якого немає у програмістів. Інтерв'юер відкриває реальну сторінку (часто демо-застосунок або твій же pet-проєкт) і просить: «напиши локатор для цієї кнопки» або «напиши тест, що логіниться й перевіряє, що відкрився дашборд». Тут дивляться не на алгоритми, а на інженерну зрілість автоматизатора:

    • стратегія локаторів — чи береш стабільні, орієнтовані на користувача локатори (getByRole, getByLabel, getByText) замість крихких CSS/XPath, прив'язаних до верстки; чи розумієш data-testid як контракт із розробкою. Механіка селекторів і DOM — у главі DOM, селектори та події; повна стратегія стабільних локаторів — у розділі «Автоматизація: стратегія».
    • очікування — чи використовуєш web-first assertions з авто-очікуванням замість waitForTimeout із магічним числом. Чому хардкодні паузи породжують флак — у главі практичні сценарії AQA: флак і синхронізація, а чому SPA завантажується не миттєво — у главі асинхронне завантаження.
    • структура — AAA (arrange–act–assert), одна перевірка інваріанта, а не god-тест на пів екрана;
    • уточнення — який браузер, чи є data-testid, чи можна логінитися через API замість UI.

    Порівняй два локатори на одну й ту саму кнопку — інтерв'юер побачить різницю миттєво:

    // Крихко: зламається від зміни верстки чи згенерованого класу
    await page.locator('div.form > button.btn-primary:nth-child(3)').click();
    
    // Стабільно: прив'язка до ролі й доступного імені
    await page.getByRole('button', { name: 'Увійти' }).click();

    А ось мінімальний, але «дорослий» тест — його структуру видно з першого погляду:

    test('успішний вхід відкриває дашборд', async ({ page }) => {
      // Arrange
      await page.goto('/login');
      // Act
      await page.getByLabel('Email').fill('user@example.com');
      await page.getByLabel('Пароль').fill('correct-horse');
      await page.getByRole('button', { name: 'Увійти' }).click();
      // Assert — web-first, з авто-очікуванням, без ручних пауз
      await expect(page.getByRole('heading', { name: 'Дашборд' })).toBeVisible();
    });

    Якщо стек команди — CodeceptJS, той самий тест виглядатиме як сценарій I.amOnPage, I.fillField, I.click, I.see, але критерії ті самі: семантичні локатори й жодних штучних затримок.

    Формат 3: рев'ю коду

    Тобі показують готовий шматок тесту й питають: «що тут не так?». Це перевірка не на те, чи напишеш ти код, а чи бачиш проблеми стабільності й підтримуваності. Типовий підсаджений набір дефектів:

    • забутий await перед асинхронною дією (floating promise) — тест «пробігає» повз перевірку;
    • waitForTimeout(5000) замість очікування конкретної умови;
    • локатор через nth(2) або абсолютний XPath;
    • тест, що залежить від стану, який лишив попередній тест (порушена ізоляція);
    • перевірка без зрозумілого повідомлення, хардкод тестових даних, відсутність прибирання.

    Що оцінюють: чи ти не просто тицяєш пальцем «це погано», а пояснюєш чому (цей waitForTimeout закладає флак і сповільнює прогін) і пропонуєш конкретний фікс (замінити на web-first assertion). Таксономія причин флаку й політика боротьби з ним — у розділі «Автоматизація: стратегія».

    Мислення вголос і декомпозиція

    Це головна мета-навичка, заради якої весь етап і існує. Універсальний шаблон, що працює для будь-якого формату лайвкодингу:

    Ні

    Так

    Отримав задачу

    Уточни вимоги й обмеження

    Наведи приклад входу і виходу

    Накидай наївне рішення

    Прожени крайові випадки

    Працює й вкладаєшся в час?

    Поліпш або спрости

    Проговори складність і межі

    Ні

    Так

    Отримав задачу

    Уточни вимоги й обмеження

    Наведи приклад входу і виходу

    Накидай наївне рішення

    Прожени крайові випадки

    Працює й вкладаєшся в час?

    Поліпш або спрости

    Проговори складність і межі

    Тактика проговорювання проста: кажи, що збираєшся зробити, перед тим, як це зробити. «Спершу уточню: рядок може бути порожній? Юнікод рахуємо як окремі символи? Добре, тоді пройдуся по символах і складатиму словник частот». Інтерв'юер чує хід думки — і навіть якщо ти застрягнеш на синтаксисі, він уже знає, що логіку ти тримаєш.

    Крайові випадки — це той чекліст, який QA має називати сам, не чекаючи підказки. Промовляй їх уголос: порожній ввід, null/undefined, дуже великий ввід, дублікати, юнікод і пробіли, від'ємні числа, а для async — таймаут, помилка й порожній список. Саме тут кандидат-тестувальник має перевагу над кандидатом-розробником: думати про те, що зламається, — твоя основна робота.

    Реакція на підказки

    Підказка від інтерв'юера — це сигнал і допомога, а не вирок. Її дають, щоб зрушити тебе з місця й побачити, чи вмієш ти вбудувати нову інформацію — рівно так, як вбудовуватимеш коментарі рев'юера в реальній роботі. Дві протилежні реакції розводять кандидатів на різні полюси:

    • Погано — проігнорувати підказку й уперто йти своїм шляхом, або розгубитися й замовкнути.
    • Добре — «О, дякую — тобто ви натякаєте, що замість вкладеного циклу тут можна Map і звести до одного проходу? Так, це прибирає квадратичну складність».

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

    Тактика при застряганні

    Застрягнути — нормально; на це дивляться не менш уважно, ніж на гладкий розв'язок, бо в роботі ти теж застрягатимеш. Помилка лише одна — застрягнути мовчки. Порядок дій:

    Ні

    Так

    Ні

    Так

    Застряг

    Проговори, де саме затик

    Знаєш загальний підхід?

    Візьми менший випадок

    Напиши наївний робочий варіант

    Зрушив з місця?

    Попроси підказку прямо

    Продовжуй і перевіряй крок

    Ні

    Так

    Ні

    Так

    Застряг

    Проговори, де саме затик

    Знаєш загальний підхід?

    Візьми менший випадок

    Напиши наївний робочий варіант

    Зрушив з місця?

    Попроси підказку прямо

    Продовжуй і перевіряй крок

    Розкладемо словами:

    1. Проговори затик — «я знаю, що треба згрупувати замовлення за статусом, але не пригадаю точний синтаксис reduce». Це і чесно, і дає інтерв'юеру точку, де підключитися.
    2. Спрости — розв'яжи меншу версію: не «згрупуй і порахуй агрегат», а спершу «просто відфільтруй один статус».
    3. Напиши наївне робоче рішення — навіть на подвійному циклі. Робоче O(n²) б'є елегантне неробоче.
    4. Попроси підказку прямо — якщо реально глухо. Це не мінус; мовчазні п'ять хвилин у стелю — мінус.
    5. Перевір те, що вже є — прожени свій код на прикладі замість тупцювати на місці.

    Як тренуватись

    • Регулярно й уголос. Розв'язуй задачі, промовляючи вголос або записуючи себе на диктофон. Тиша на реальній співбесіді — від нетренованості говорити й кодити одночасно, а не від незнання.
    • Знай мову руками. Методи масивів (map/filter/reduce/find), Promise (all/allSettled), async/await мають згадуватися без гуглінгу базового — це «мова», якою ти пишеш. Матеріал — у розділі «JavaScript/TypeScript для AQA».
    • Тренуйся в тому середовищі, де проситимуть. Часто це середовище бідніше за звичну IDE: онлайн-редактор на кшталт CoderPad, спільний Google Docs або шматок Playwright-проєкту. Порепетируй без милиць IDE.
    • Мок-співбесіди з таймером. Штучний тиск часу — окрема навичка; як його відпрацювати, — у главі план підготовки і mock-співбесіди.
    • Розбирай власний фреймворк. Багато AQA-лайвкодингів — це «покажи, як ти пишеш тест» на твоєму ж стеку. Умій пояснити кожне рішення у своєму проєкті — це також місток до технічної співбесіди AQA.

    Типові помилки

    • Мовчазний геній — виглядає як зосередженість, а насправді інтерв'юер не бачить твого мислення й ставить нижчий бал, ніж за гірший, але проговорений розв'язок.
    • Кинувся кодити одразу — виглядає як упевненість, а насправді пропустив уточнення й розв'язав не ту задачу.
    • Ігнорування крайових випадків — виглядає як «основне ж працює», а насправді для QA-ролі саме крайові випадки — твій хліб; пропустити їх на лайвкодингу тобі гірше, ніж кандидатові-розробнику.
    • Оборона від підказки — виглядає як принциповість, а насправді сигнал, що з тобою важко працювати в парі.
    • waitForTimeout і force: true у тесті — виглядає як «зробив, щоб працювало», а насправді демонструє нерозуміння авто-очікувань і закладає майбутній флак.
    • Передчасна оптимізація — виглядає як сеньйорність, а насправді ти витрачаєш час на «найкращий алгоритм» замість спершу зробити робочий.

    Підсумок

    • Лайвкодинг перевіряє процес, а не відповідь: думай уголос, інакше твоє мислення просто не зарахують.
    • Спершу уточни вимоги й наведи приклад входу/виходу, і лише потім кодь.
    • Крайові випадки називай сам — для QA це головна перевага над кандидатом-розробником.
    • Підказка — це допомога й позитивний сигнал; бери її вдячно, не обороняйся.
    • Робоче наївне рішення б'є елегантне неробоче: спершу «щоб працювало», оптимізація — потім.

    Що питають на співбесіді

    • «Напишіть функцію, що рахує, скільки разів кожне слово трапляється в рядку.» — Дивляться, чи згадаєш крайові випадки (порожній рядок, регістр, пунктуація) і чи проговорюєш хід.
    • «Ось сторінка логіну — напишіть тест, що вводить дані й перевіряє вхід.» — Дивляться на стратегію локаторів, очікування без хардкодних пауз і структуру AAA.
    • «Що не так у цьому тесті?» (зі схованим waitForTimeout і nth-локатором) — Дивляться, чи бачиш джерела флаку й чи пояснюєш, чому це погано, а не лише «перепиши».
    • «Розверніть рядок / знайдіть дублікати в масиві.» — Дивляться на базову біглість у методах мови без гуглінгу елементарного.
    • «Напишіть retry-функцію, що повторює запит N разів із затримкою.» — Дивляться на async/await, обробку помилок і чи не загубив ти await.

    На що дивиться інтерв'юер загалом: не на ідеальний код, а на озвучені припущення, названі крайові випадки й спокійну реакцію на затик. Сказати вголос «я не пам'ятаю точну сигнатуру, гляну в доку» — нормально й навіть плюс; вдавати, що знаєш, і писати навмання — мінус.

    Джерела

    • Playwright — Best Practices — орієнтовані на користувача локатори, ізоляція тестів, web-first assertions, чому не потрібні ручні паузи.
    • Playwright — LocatorsgetByRole/getByLabel/getByText/getByTestId і пріоритет стабільних селекторів.
    • MDN — Array — методи map/filter/reduce/find для задач із тестовими даними.
    • MDN — Promiseall/allSettled/race для async-задач на кшталт retry й обмеження паралельності.

    Ця тема не входить до силабусу ISTQB CTFL 4.0 — це інженерна практика, а не частина тестувальницької теорії; змістовний матеріал з мови й автотестів шукай у розділах «JavaScript/TypeScript для AQA» та «Інструменти автоматизації».