# Тести для live coding: як перевіряти свій код на співбесіді

> Як тестувати рішення live-coding задач: мінімальний патерн без фреймворка, синтаксис vitest/jest, табличні тести, кейси для debounce і groupBy та як промовляти тест-стратегію вголос.

- Автор: Юра Скиба (https://cookiesoftware.io)
- Опубліковано: 2026-09-24
- Категорія: JavaScript і TypeScript
- Canonical: https://cookiesoftware.io/blog/testy-dlia-live-coding

---

**Коротка відповідь.** На live coding тести – це не формальність, а найшвидший спосіб показати інженерне мислення. Навіть якщо середовище співбесіди не має тест-раннера, кілька рядків із `console.assert` демонструють: ти думаєш про крайні випадки до того, як інтерв'юер про них спитає. Нижче – мінімальний патерн без фреймворка, той самий підхід у синтаксисі vitest/jest і готові тест-кейси для двох класичних задач.

## Чому тести підвищують оцінку

Інтерв'юер за 40 хвилин оцінює не лише «працює/не працює», а як ти мислиш. Кандидат, який після happy path каже «тепер перевірю порожній масив і від'ємні значення» і робить це кодом, закриває одразу три пункти оцінки: розуміння вимог, увагу до країв і звичку до самоперевірки. Це працює на будь-якому рівні – від Junior до Senior, різниця лише в глибині кейсів.

## Мінімальний патерн без фреймворка

У більшості онлайн-редакторів співбесід немає jest. Достатньо `console.assert`:

```js
function groupBy(items, keyFn) {
  const groups = new Map();
  for (const item of items) {
    const key = keyFn(item);
    const bucket = groups.get(key) ?? [];
    bucket.push(item);
    groups.set(key, bucket);
  }
  return groups;
}

// Тести: assert мовчить, якщо все добре, і кричить, якщо ні
const byLength = groupBy(['ай', 'бо', 'кіт'], (word) => word.length);
console.assert(byLength.get(2).length === 2, 'два слова довжини 2');
console.assert(byLength.get(3).length === 1, 'одне слово довжини 3');

const empty = groupBy([], (x) => x);
console.assert(empty.size === 0, 'порожній вхід -> порожній результат');
```

Правило: **один assert – одне твердження з підписом**. Підпис важливий: коли щось упаде, ти одразу бачиш що саме, і не витрачаєш хвилини співбесіди на дебаг власних тестів.

## Той самий підхід у vitest/jest

Якщо середовище дозволяє (або тебе просять «як би ти це тестував у проєкті»), синтаксис майже однаковий у [vitest](https://vitest.dev/) і jest:

```ts
import { describe, expect, it } from 'vitest';

describe('groupBy', () => {
  it('групує за обчисленим ключем', () => {
    const result = groupBy(['ай', 'бо', 'кіт'], (word) => word.length);
    expect(result.get(2)).toEqual(['ай', 'бо']);
    expect(result.get(3)).toEqual(['кіт']);
  });

  it('повертає порожню мапу для порожнього входу', () => {
    expect(groupBy([], (x) => x).size).toBe(0);
  });

  it('не мутує вхідний масив', () => {
    const input = ['a', 'b'];
    groupBy(input, (x) => x);
    expect(input).toEqual(['a', 'b']);
  });
});
```

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

## Табличні тести: багато кейсів без копіпасти

Коли кейсів більше трьох, таблиця читається краще за серію it-блоків:

```ts
it.each([
  { input: [1, 2, 2, 3], expected: [1, 2, 3] },
  { input: [], expected: [] },
  { input: [1, 1, 1], expected: [1] },
  { input: ['1', 1], expected: ['1', 1] }, // типи не змішуються
])('unique($input) -> $expected', ({ input, expected }) => {
  expect(unique(input)).toEqual(expected);
});
```

Останній рядок таблиці – хороший приклад «підступного» кейсу: рядок `'1'` і число `1` мають лишитися різними значеннями. Саме такі рядки в таблиці показують, що ти думаєш про типи, а не тільки про щасливий шлях.

## Складніший випадок: тестуємо debounce

`debounce` – задача з часом, тому потрібні фейкові таймери:

```ts
import { afterEach, beforeEach, expect, it, vi } from 'vitest';

beforeEach(() => vi.useFakeTimers());
afterEach(() => vi.useRealTimers());

it('викликає функцію один раз після паузи', () => {
  const spy = vi.fn();
  const debounced = debounce(spy, 300);

  debounced('a');
  debounced('b');
  debounced('c');

  expect(spy).not.toHaveBeenCalled();     // ще чекаємо
  vi.advanceTimersByTime(300);

  expect(spy).toHaveBeenCalledTimes(1);   // один виклик...
  expect(spy).toHaveBeenLastCalledWith('c'); // ...з останнім аргументом
});
```

Два твердження в кінці – суть debounce: не тільки «викликано один раз», а й «з останнім аргументом». Якщо на співбесіді немає vitest, ту саму ідею можна показати через `setTimeout` у демо-виклику і коментар, що саме ти б перевірив.

## Тест до коду: полегшена версія TDD для співбесіди

Повноцінний TDD-цикл на співбесіді зазвичай не потрібен, але один прийом із нього дуже практичний: **запиши перший тест до реалізації** – він фіксує контракт і знімає двозначність умови.

```js
// Умова: «згладь вкладений масив на один рівень»
// Перш ніж писати flatten, фіксуємо, що це означає:
console.assert(
  JSON.stringify(flattenOnce([1, [2, 3], [4, [5]]])) ===
    JSON.stringify([1, 2, 3, 4, [5]]),
  'вкладеність зменшується рівно на один рівень'
);
```

Цей assert ще до реалізації виявляє головне непорозуміння задачі: `[5]` лишається масивом чи ні? Якщо твоє розуміння розходиться з очікуванням інтерв'юера – ви з'ясуєте це за 30 секунд на тесті, а не за 15 хвилин на готовому коді. Фраза «давайте я зафіксую очікуваний результат прикладом» ще жодного кандидата не зробила слабшим.

## Чекліст крайніх кейсів за типом задачі

Швидка шпаргалка, що перевіряти залежно від того, з чим працює функція:

| Тип входу | Обов'язкові кейси |
|---|---|
| Масив | порожній; один елемент; усі елементи однакові; дублікати |
| Рядок | порожній; один символ; пробіли; юнікод/кирилиця |
| Число | 0; від'ємне; дробове; дуже велике |
| Об'єкт | відсутнє поле; null у полі; зайві поля |
| Колбек | кидає виняток; повертає undefined; викликається 0 разів |
| Час (debounce/throttle) | кілька викликів поспіль; виклик після паузи; аргументи останнього виклику |

Не треба покривати всю таблицю на кожній задачі – обери 2-3 рядки, релевантні умові, і назви решту вголос: «за наявності часу я б ще перевірив X та Y».

## Як промовляти тест-стратегію вголос

Формула з чотирьох речень, яка працює для будь-якої задачі:

1. «Спочатку перевірю **основний сценарій** – те, заради чого функція існує.»
2. «Потім **порожні й мінімальні входи**: порожній масив, один елемент.»
3. «Далі **межі контракту**: дублікати, невалідні типи, від'ємні числа – залежно від умови.»
4. «І окремо – **відсутність побічних ефектів**: вхідні дані не мутуються.»

Навіть якщо встигнеш написати лише половину цих тестів, озвучена стратегія вже зарахована.

## Куди далі

Набір задач, до яких варто застосувати цей підхід, – у добірці [JavaScript live coding](/blog/javascript-live-coding-zadachi); для фронтендерів – [React-задачі з TypeScript](/blog/react-live-coding-typescript). Як вбудувати тести в загальний план підготовки по днях – у статті про [підготовку до співбесіди за 30 днів](/blog/pidhotovka-do-tekhnichnoi-spivbesidy).

Практичне завдання: візьми останню розв'язану задачу і додай до неї п'ять тестів за формулою вище. Якщо хоч один упав – ти щойно знайшов баг, який знайшов би інтерв'юер.
