Тестування JavaScript з Jest

Test-Driven Development (TDD)

📖 Теорія

TDD — методологія розробки: спочатку тести, потім код.

Цикл TDD (Red → Green → Refactor):
1. Red — пишемо тест (що провалюється)
2. Green — пишемо мінімальний код щоб тест пройшов
3. Refactor — покращуємо код (тести все ще зелені)

Приклад TDD для функції isPalindrome:

💡 Приклад коду
Вивід:

                            
📝 ЗАВДАННЯ (3)
1.
Завдання 1: TDD isPalindrome
10 XP
Реалізуй isPalindrome(str) та перевір:
1. 'racecar' → true
2. 'level' → true
3. 'hello' → false
4. 'A man a plan a canal Panama' (очищений) → true
💡 Підказка: Очисти рядок: toLowerCase + replace(/[^a-z]/g, ''). Порівняй з оберненим
🔓 Розв'язок:
const isPalindrome = str => {
  const s = str.toLowerCase().replace(/[^a-z]/g, '');
  return s === [...s].reverse().join('');
};

console.log(isPalindrome('racecar'));
console.log(isPalindrome('level'));
console.log(isPalindrome('hello'));
console.log(isPalindrome('A man a plan a canal Panama'));
Вивід:

                                

2.
Завдання 2: TDD для groupBy
20 XP
Реалізуй функцію groupBy(arr, key) що групує масив об'єктів за ключем.

Вхід: [{name:'Аня',dept:'dev'},{name:'Богдан',dept:'qa'},{name:'Вова',dept:'dev'}], 'dept'
Вихід: { dev: [{...},{...}], qa: [{...}] }

Виведи JSON.stringify результату.
💡 Підказка: Використай reduce: acc[item[key]] ??= []; acc[item[key]].push(item); return acc
🔓 Розв'язок:
function groupBy(arr, key) {
  return arr.reduce((acc, item) => {
    (acc[item[key]] ??= []).push(item);
    return acc;
  }, {});
}
const team = [{name:'Аня',dept:'dev'},{name:'Богдан',dept:'qa'},{name:'Вова',dept:'dev'}];
const result = groupBy(team, 'dept');
console.log(JSON.stringify(result));
Вивід:

                                

3.
Завдання 3: Комплексний тест-suite
30 XP
Реалізуй клас Calculator та запусти тести:
- add(2, 3) = 5
- subtract(10, 4) = 6
- multiply(3, 7) = 21
- divide(15, 3) = 5
- divide(5, 0) throws 'Ділення на нуль'
- chain: calc.add(5).multiply(2).subtract(3).result === 7
💡 Підказка: Для chain: кожен метод повертає this, зберігай поточне значення в this.result
🔓 Розв'язок:
class Calculator {
  constructor(val = 0) { this.result = val; }
  add(n) { this.result += n; return this; }
  subtract(n) { this.result -= n; return this; }
  multiply(n) { this.result *= n; return this; }
  divide(n) {
    if (n === 0) throw new Error('Ділення на нуль');
    this.result /= n;
    return this;
  }
}

// Статичні методи
Calculator.add = (a, b) => a + b;
Calculator.subtract = (a, b) => a - b;
Calculator.multiply = (a, b) => a * b;
Calculator.divide = (a, b) => { if (!b) throw new Error('Ділення на нуль'); return a/b; };

const tests = [
  ['add(2,3)', () => Calculator.add(2,3), 5],
  ['subtract(10,4)', () => Calculator.subtract(10,4), 6],
  ['multiply(3,7)', () => Calculator.multiply(3,7), 21],
  ['divide(15,3)', () => Calculator.divide(15,3), 5],
];
tests.forEach(([name, fn, expected]) => {
  const r = fn();
  console.log(`${name} = ${r} ${r === expected ? 'PASS' : 'FAIL'}`);
});
try { Calculator.divide(5,0); } catch(e) { console.log(`divide(5,0) throws PASS`); }
const chain = new Calculator(5).add(5).multiply(2).subtract(3).result;
console.log(`chain result: ${chain} ${chain === 17 ? 'PASS' : 'FAIL'}`);
Вивід: