Исключения и отрицание not
Урок показывает, как тестировать выбрасываемые ошибки и как инвертировать любой матчер.
toThrow проверяет, что вызов выбрасывает исключение, а .not инвертирует смысл любого матчера.
Тестирование исключений: toThrow
Когда функция должна бросать ошибку при неверном вводе, это тоже поведение, и его надо проверять. Важная тонкость: в expect нужно передать функцию-обёртку, а не результат вызова — иначе ошибка вылетит раньше, чем Jest её перехватит.
function withdraw(balance, amount) {
if (amount > balance) {
throw new Error('Недостаточно средств');
}
return balance - amount;
}
// ПРАВИЛЬНО: оборачиваем в стрелочную функцию
expect(() => withdraw(100, 200)).toThrow();
expect(() => withdraw(100, 200)).toThrow('Недостаточно средств');
expect(() => withdraw(100, 200)).toThrow(/средств/);
// НЕПРАВИЛЬНО: ошибка выбросится до того, как Jest успеет её поймать
// expect(withdraw(100, 200)).toThrow();toThrow можно вызвать без аргументов (любая ошибка), с подстрокой, с регуляркой или с классом ошибки.
Почему нужна обёртка — на чистом JS
Воспроизведём механику «обернуть вызов, чтобы поймать ошибку» вживую:
function withdraw(balance, amount) {
if (amount > balance) throw new Error('Недостаточно средств');
return balance - amount;
}
function expectToThrow(fn, name) {
try {
fn();
console.log('\u2717 FAILED: ' + name + ' (ошибки не было)');
} catch (e) {
console.log('\u2713 passed: ' + name + ' \u2192 ' + e.message);
}
}
expectToThrow(() => withdraw(100, 200), 'снятие больше баланса бросает ошибку');
expectToThrow(() => withdraw(100, 50), 'снятие в пределах баланса бросает ошибку');Вывод:
✓ passed: снятие больше баланса бросает ошибку → Недостаточно средств ✗ FAILED: снятие в пределах баланса бросает ошибку (ошибки не было)
Здесь видно, зачем нужна функция-обёртка: try/catch вызывает её сам и ловит исключение. Jest toThrow делает ровно это под капотом.
Отрицание: .not
Любой матчер можно инвертировать, вставив .not перед ним:
expect(sum(2, 2)).not.toBe(5);
expect(['a', 'b']).not.toContain('c');
expect(() => withdraw(100, 50)).not.toThrow();
expect(user.name).not.toBeNull();.not читается как «не должно быть»: «expect 2+2 not to be 5».
Когда применять
toThrow— для проверки валидации, защитных условий, обработки ошибок..not— когда важно отсутствие значения/ошибки.
С .not не злоупотребляйте: позитивная проверка («должно быть X») обычно точнее негативной («не должно быть Y»), потому что Y может быть бесконечно много.
Итог
toThrowпроверяет выброс ошибки; вызов оборачивают в функцию.- Можно уточнять ошибку подстрокой, регуляркой или классом.
.notинвертирует любой матчер.- Позитивные проверки обычно надёжнее негативных.