4. Jest: введение

Что такое Jest?
Заголовок раздела «Что такое Jest?»Jest — самый популярный JavaScript тест-раннер от Meta. Работает из коробки для React, Node.js, TypeScript.
Установка
Заголовок раздела «Установка»# Для Node.js / TypeScriptnpm install --save-dev jest @types/jest ts-jest
# Для React (уже включён в Create React App)npm install --save-dev jest babel-jest @babel/preset-env @babel/preset-react
# jest.config.jsmodule.exports = { testEnvironment: 'node', // или 'jsdom' для браузерных тестов transform: { '^.+\\.tsx?$': 'ts-jest', }, collectCoverageFrom: ['src/**/*.{ts,tsx}'],};{ "scripts": { "test": "jest", "test:watch": "jest --watch", "test:coverage": "jest --coverage" }}Структура теста
Заголовок раздела «Структура теста»// Файлы тестов: *.test.js, *.spec.js, __tests__/*.js
// Группировка тестовdescribe('Math utils', () => { // Выполняется перед каждым тестом в блоке beforeEach(() => { // setup });
// Выполняется после каждого теста afterEach(() => { // teardown });
// Один раз перед всеми тестами блока beforeAll(async () => { await db.connect(); });
// Один раз после всех тестов блока afterAll(async () => { await db.close(); });
// Тест test('adds numbers', () => { expect(1 + 2).toBe(3); });
// Синоним test() it('multiplies numbers', () => { expect(2 * 3).toBe(6); });});Matchers (проверки)
Заголовок раздела «Matchers (проверки)»// Равенствоexpect(2 + 2).toBe(4); // ===expect({ a: 1 }).toEqual({ a: 1 }); // глубокое равенствоexpect(null).toBeNull();expect(undefined).toBeUndefined();expect(true).toBeTruthy();expect(0).toBeFalsy();
// Числаexpect(5).toBeGreaterThan(3);expect(3).toBeLessThan(5);expect(0.1 + 0.2).toBeCloseTo(0.3); // для float!
// Строкиexpect('hello world').toContain('world');expect('hello').toMatch(/hel/);expect('hello').toMatch('ell');
// Массивыexpect([1, 2, 3]).toContain(2);expect([1, 2, 3]).toHaveLength(3);expect([1, 2, 3]).toEqual(expect.arrayContaining([1, 3]));
// Объектыexpect({ name: 'Alice', age: 28 }).toMatchObject({ name: 'Alice' });expect({ id: 1, name: 'Alice' }).toHaveProperty('name', 'Alice');
// Ошибкиexpect(() => { throw new Error('oops') }).toThrow('oops');expect(() => { throw new Error('oops') }).toThrow(Error);
// Отрицаниеexpect(5).not.toBe(6);expect(null).not.toBeUndefined();Асинхронные тесты
Заголовок раздела «Асинхронные тесты»test('fetches user', async () => { const user = await fetchUser(1); expect(user.name).toBe('Alice');});
// Promisetest('fetches user (promise)', () => { return fetchUser(1).then(user => { expect(user.name).toBe('Alice'); });});
// resolves / rejectstest('resolves with user', async () => { await expect(fetchUser(1)).resolves.toMatchObject({ name: 'Alice' });});
test('rejects for missing user', async () => { await expect(fetchUser(999)).rejects.toThrow('User not found');});Организация тестов
Заголовок раздела «Организация тестов»// Пропустить тестtest.skip('will not run', () => { ... });xtest('also skipped', () => { ... });
// Запустить только этот тестtest.only('runs alone', () => { ... });fit('also runs alone', () => { ... });
// Параметрические тестыtest.each([ [1, 2, 3], [10, 20, 30], [-1, -2, -3],])('adds %i + %i = %i', (a, b, expected) => { expect(a + b).toBe(expected);});
// Объектыtest.each([ { input: 'hello', expected: 'HELLO' }, { input: 'world', expected: 'WORLD' },])('uppercase $input → $expected', ({ input, expected }) => { expect(input.toUpperCase()).toBe(expected);});Запуск и фильтрация
Заголовок раздела «Запуск и фильтрация»# Запустить все тестыnpx jest
# Только файлnpx jest utils.test.js
# По паттернуnpx jest --testNamePattern="adds"
# Watch modenpx jest --watch
# Coveragenpx jest --coverage
# Verbose (детальный вывод)npx jest --verboseПрактические задания
Заголовок раздела «Практические задания»- Установи Jest и напиши 5 тестов для разных Matchers
- Протестируй async функцию, которая возвращает Promise
- Используй test.each для таблицы входных данных
- Jest — самый популярный тест-раннер
- describe/test/expect — основа структуры
- beforeEach/afterEach — setup и teardown
- async/await работает нативно