Тестируем JavaScript-код с Jest
Jest — это простая и удобная среда тестирования. Она не требует дополнительных настроек, легка в понимании и использовании, имеет неплохую документацию. Кроме того, прекрасно подходит для проектов, в которых используются Node, Angular, Vue, React, Babel, TypeScript. Давайте посмотрим, как всё это выглядит на практике.
Установка
Чтобы установить Jest, выполняем:
npm install --save-dev jest
Если используете yarn:
yarn add --dev jest
Также после установки можно обновить секцию scripts вашего файла package.json:
“scripts” : { “test”: “jest” }
Посредством такого простого вызова уже можно запускать тесты, хотя Jest всё равно потребует существование хотя бы одного теста.
Выполнить установку можно и глобально:
npm install jest –global
Для yarn:
yarn global add jest
Далее можно использовать Jest уже из командной строки.
Первый тест на Jest
Итак, создадим файл first.test.js, а потом напишем первый тест:
//first.test.js test('My first test', () => { expect(Math.max(1, 5, 10)).toBe(10); });
Теперь запустим тесты посредством npm run test или командой jest (при глобальной установке). После запуска вы увидите отчёт о прохождении тестов.
<b>PASS</b> ./first.test.js ✓ My first test (1 ms) Test Suites: 1 passed, 1 total Tests: 1 passed, 1 total Snapshots: 0 total Time: 0.618 s, estimated 1 s
Что же, разберём код теста. У нас есть функция test, используемая для создания нового теста. Она принимает 3 аргумента (в примере у нас 2 аргумента). Первый — это строка с названием теста (jest отображает его в отчёте). Второй — это функция, содержащая логику теста. При необходимости используют и третий аргумент — таймаут. Он необязателен и задаётся в миллисекундах. Значение по умолчанию — 5 сек.
Следует добавить, что вместо test() мы можем применять it() — разницы нету, а it() просто является алиасам на функцию test().
Идём дальше. Внутри функции теста мы поначалу вызываем функцию expect(), которой передаём значение для проверки. В нашем случае речь идёт о результате вызова Math.max(1, 5, 10). Здесь expect() возвратит объект-«обёртку», у которой есть методы для сопоставления полученного значения и ожидаемого значения. Один из этих методов мы, как раз, и использовали — это метод toBe.
Разберем основные из этих методов: — toBe() — подойдёт, если нужно сравнить примитивные значения либо проверить, является ли переданное значение ссылкой на тот объект, который указан как ожидаемое значение. Значения сравниваются посредством Object.is(); — toEqual() — если нужно сравнить структуру более сложных типов. Метод выполнит сравнение всех полей переданного объекта с ожидаемым. Он проверит каждый элемент массива, сделав это рекурсивно по всей вложенности:
test('toEqual with objects', () => { expect({ foo: 'foo', subObject: { baz: 'baz' } }) .toEqual({ foo: 'foo', subObject: { baz: 'baz' } }); //ок expect({ foo: 'foo', subObject: { num: 0 } }) .toEqual({ foo: 'foo', subObject: { baz: 'baz' } }); //ошибка }); test('toEqual with arrays', () => { expect([11, 19, 5]).toEqual([11, 19, 5]); //ок expect([11, 19, 5]).toEqual([11, 19]); //ошибка });
— toContain() — проверит, содержит ли массив либо итерируемый объект значение (применяется оператор ===):
const arr = ['apple', 'orange', 'banana']; expect(arr).toContain('banana'); expect(new Set(arr)).toContain('banana'); expect('apple, orange, banana').toContain('banana');
— toContainEqual() — содержит ли массив элемент с ожидаемой структурой:
expect([{a: 1}, {b: 2}]).toContainEqual({a: 1});
— toHaveLength() — соответствует ли свойство length у объекта ожидаемому:
expect([1, 2, 3, 4]).toHaveLength(4); expect('foo').toHaveLength(3); expect({ length: 1 }).toHaveLength(1);
— toBeNull() — проверка на равенство с null; — toBeUndefined() — проверка на равенство с undefined; — toBeDefined() — противоположность toBeUndefined. Проверка, является ли значение !== undefined; — toBeTruthy() — проверка, соответствует ли значение true в булевом контексте; — toBeFalsy() — противоположность toBeTruthy(). Проверка, соответствует ли значение в булевом контексте false; — toBeGreaterThan() — проверка, больше ли числовое значение, чем ожидаемое; — toBeGreaterThanOrEqual() — проверка, что ожидаемое значение больше или равно ожидаемому; — toBeLessThan() и toBeLessThanOrEqual() — противоположности toBeGreaterThan() и toBeGreaterThanOrEqual(); — toBeCloseTo() — метод удобен для чисел с плавающей запятой, когда не важна точность, и вы не желаете, чтобы ваш тест зависел от незначительной разницы в дроби. В качестве 2-го аргумента вы можете передать, до какого знака после запятой нужна точность при сравнении:
const num = 0.1 + 0.2; // 0.30000000000000004 expect(num).toBeCloseTo(0.3); expect(Math.PI).toBeCloseTo(3.14, 2);
— toMatch() — проверка, соответствует ли строка регулярному выражению:
expect('Banana').toMatch(/Ba/);
— toThrow() — подходит, если нужно проверить исключение. Метод может проверить сам факт ошибки либо выполнить проверку на выброс исключения определённого класса, а также по сообщению ошибки либо по соответствию сообщения регулярному выражению;
function funcWithError() { throw new Error('some error'); } expect(funcWithError).toThrow(); expect(funcWithError).toThrow(Error); expect(funcWithError).toThrow('some error'); expect(funcWithError).toThrow(/some/);
— not — свойство, позволяющее выполнить проверку на неравенство. Оно предоставляет объект, имеющий все вышеперечисленные методы, однако работать они будут наоборот:
expect(true).not.toBe(false); expect({ foo: 'bar' }).not.toEqual({}); function funcWithoutError() {} expect(funcWithoutError).not.toThrow();