Шпаргалка по Jest (Stylesheet Jest)
Базовая структура теста
describe('Выбор цвета', () => {
beforeAll(() => {
/* Запускается перед всеми тестами */
})
afterAll(() => {
/* Запускается после всех тестов */
})
beforeEach(() => {
/* Запускается перед каждым тестом */
})
afterEach(() => {
/* Запускается после каждого теста */
})
test('Выбираем цвет', () => {
const actual = fn(['Alice', 'Bob', 'John'])
expect(actual).toEqual(['Pink Alice', 'Pink Bob', 'Pink John'])
})
})
Поиск совпадений
Использование поиска совпадений, официальная документация
Базовый поиск совпадений
expect(42).toBe(42) // Строгое равенство (===)
expect(42).not.toBe(3) // Строгое неравенство (!==)
expect([1, 2]).toEqual([1, 2]) // Глубокое сравнение
expect({ a: undefined, b: 2 }).toEqual({ b: 2 }) // Глубокое сравнение
expect({ a: undefined, b: 2 }).not.toStrictEqual({ b: 2 }) // Строгое сравнение
Определение истинности
// Совпадает с истинными значениями
expect('foo').toBeTruthy()
// Совпадает с ложными значениями
expect('').toBeFalsy()
// Совпадает только с `null`
expect(null).toBeNull()
// Совпадает только с `undefined`
expect(undefined).toBeUndefined()
// Значение должно быть определено
expect(7).toBeDefined()
// Совпадает с `true` или `false`
expect(true).toEqual(expect.any(Boolean))
Числа
expect(2).toBeGreaterThan(1) expect(1).toBeGreaterThanOrEqual(1) expect(1).toBeLessThan(2) expect(1).toBeLessThanOrEqual(1) expect(0.2 + 0.1).toBeCloseTo(0.3, 5) expect(NaN).toEqual(expect.any(Number))
Строки
expect('длинная строка').toMatch('стр')
expect('строка').toEqual(expect.any(String))
expect('кофе').toMatch(/ф/)
expect('пицца').not.toMatch('кофе')
expect(['пицца', 'кофе']).toEqual([expect.stringContaining('цц'), expect.stringMatching(/ф/)])
Массивы
expect([]).toEqual(expect.any(Array))
expect(['Alice', 'Bob', 'John']).toHaveLength(3)
expect(['Alice', 'Bob', 'John']).toContain('Alice')
expect([{ a: 1 }, { a: 2 }]).toContainEqual({ a: 1 })
expect(['Alice', 'Bob', 'John']).toEqual(expect.arrayContaining(['Alice', 'Bob']))
Объекты
expect({ a: 1 }).toHaveProperty('a')
expect({ a: 1 }).toHaveProperty('a', 1)
expect({ a: { b: 1 } }).toHaveProperty('a.b')
expect({ a: 1, b: 2 }).toMatchObject({ a: 1 })
expect({ a: 1, b: 2 }).toMatchObject({
a: expect.any(Number),
b: expect.any(Number)
})
expect([{ a: 1 }, { b: 2 }]).toEqual([
expect.objectContaining({ a: expect.any(Number) }),
expect.anything()
])
Исключения
// const fn = () => { throw new Error('Упс!') }
expect(fn).toThrow()
expect(fn).toThrow('Упс')
expect(fn).toThrowErrorMatchingSnapshot()
Снимки
expect(node).toMatchSnapshot()
expect(user).toMatchSnapshot({
date: expect.any(Date)
})
expect(user).toMatchInlineSnapshot()
Функция для создания «моков» (фикций)
// const fn = jest.fn()
// const fn = jest.fn().mockName('Единорог') - именованная фикция
expect(fn).toBeCalled() // Функция была вызвана
expect(fn).not.toBeCalled() // Функция *не была* вызвана
expect(fn).toHaveBeenCalledTimes(1) // Функция была вызвана один раз
expect(fn).toBeCalledWith(arg1, arg2) // Любой вызов функции сопровождался указанными аргументами
expect(fn).toHaveBeenLastCalledWith(arg1, arg2) // При последнем вызове функции, ей были переданы указанные аргументы
expect(fn).toHaveBeenNthCalledWith(args) // Определенный вызов функции сопровождался указанными аргументами
expect(fn).toHaveReturnedTimes(2) // Функция возвращает значения без ошибок
expect(fn).toHaveReturnedWith(value) // Функция возвращает указанное значение
expect(fn).toHaveLastReturnedWith(value) // Последний вызов функции вернул указанное значение
expect(fn).toHaveNthReturnedWith(value) // Определенный вызов функции вернул указанное значение
expect(fn.mock.calls).toEqual([['first', 'call', 'args'], ['second', 'call', 'args']]) // Несколько вызовов
expect(fn.mock.calls[0][0]).toBe(2) // fn.mock.calls[0][0] — первый аргумент первого вызова
«Алиасы» (синонимы)
toBeCalled→toHaveBeenCalledtoBeCalledWith→toHaveBeenCalledWithlastCalledWith→toHaveBeenLastCalledWithnthCalledWith→toHaveBeenNthCalledWithtoReturnTimes→toHaveReturnedTimestoReturnWith→toHaveReturnedWithlastReturnedWith→toHaveLastReturnedWithnthReturnedWith→toHaveNthReturnedWith
Примеси
expect(new A()).toBeInstanceOf(A)
expect(() => {}).toEqual(expect.any(Function))
expect('пицца').toEqual(expect.anything())
Поиск совпадений с промисами
test('Разрешенным значением должен быть "лимон"', () => {
expect.assertions(1)
// Не забудьте добавить оператор `return`
return expect(Promise.resolve('лимон')).resolves.toBe('лимон')
return expect(Promise.reject('осьминог')).rejects.toBeDefined()
return expect(Promise.reject(Error('пицца'))).rejects.toThrow()
})
Или с помощью async/await:
test('Разрешенным значением должен быть "лимон"', async () => {
expect.assertions(2)
await expect(Promise.resolve('лимон')).resolves.toBe('лимон')
await expect(Promise.resolve('лимон')).resolves.not.toBe('осьминог')
})
Асинхронные тесты
Смотрите больше примеров в официальной документации Jest.
Хорошей практикой считается определение количества ожидаемых утверждений (assertions) в асинхронных тестах, тест провалится, если утверждения не будут вызваны.
test('Асинхронный тест', () => {
expect.assertions(3) // В процессе тестирования вызывается ровно три утверждения
// или
expect.hasAssertions() // В процессе тестирования вызывается по крайней мере одно утверждение
// Далее следуют асинхронные тесты
})
Обратите внимание, что вы также можете делать это в файле, за пределами любых describe и test:
beforeEach(expect.hasAssertions)
Это обеспечит присутствие хотя бы одного утверждения в процессе тестирования. Это также подходит для случаев, когда ожидается конкретное число утверждений — expect.assertions(3).
async/await
test('Асинхронный тест', async () => {
expect.assertions(1)
const result = await runAsyncOperation()
expect(result).toBe(true)
})
Промисы
test('Асинхронный тест', () => {
expect.assertions(1)
return runAsyncOperation().then(result => {
expect(result).toBe(true)
})
})
Коллбек done()
Утверждение должно быть обернуто в блок try/catch, иначе Jest будет игнорировать ошибки:
test('Асинхронный тест', done => {
expect.assertions(1)
runAsyncOperation()
setTimeout(() => {
try {
const result = getAsyncOperationResult()
expect(result).toBe(true)
done()
} catch (err) {
done.fail(err)
}
})
})
Фикции
Функции для создания фикций
test('Вызов коллбека', () => {
const callback = jest.fn()
fn(callback)
expect(callback).toBeCalled()
expect(callback.mock.calls[0][1].baz).toBe('пицца') // Второй аргумент первого вызова
// Отслеживаем первый и последний аргументы, но игнорируем второй
expect(callback).toHaveBeenLastCalledWith('мясо', expect.anything(), 'маргарита');
})
Вы также можете использовать снимки:
test('Вызов коллбека', () => {
const callback = jest.fn().mockName('Единорог')
fn(callback)
expect(callback).toMatchSnapshot()
// ->
// [MockFunction Единорог] {
// "calls": Array [
// ...
})
И передавать реализацию в функцию jest.fn():
const callback = jest.fn(() => true)
Возвращение, разрешение и отклонение значений
Ваши фикции могут возвращать значения:
const callback = jest.fn().mockReturnValue(true); const callbackOnce = jest.fn().mockReturnValueOnce(true);
Или разрешать значения:https://googleads.g.doubleclick.net/pagead/ads?client=ca-pub-5265008544060842&output=html&h=174&slotname=6021157728&adk=1238341641&adf=1504049979&pi=t.ma~as.6021157728&w=696&fwrn=4&lmt=1612760223&rafmt=11&psa=1&format=696×174&url=https%3A%2F%2Fbookflow.ru%2Fshpargalka-po-jest-s-primerami-koda%2F&flash=0&host=ca-host-pub-2644536267352236&wgl=1&dt=1643202359645&bpp=5&bdt=763&idt=338&shv=r20220120&mjsv=m202201240101&ptt=9&saldr=aa&abxe=1&cookie=ID%3D53d09eedf053366f-22c28a372bcd0013%3AT%3D1643201667%3ART%3D1643201667%3AS%3DALNI_Mb1ucFagtDc-cmhxjeor_SzpI1WJQ&prev_fmts=0x0&nras=1&correlator=7763405730272&frm=20&pv=1&ga_vid=322347871.1643202360&ga_sid=1643202360&ga_hid=525367307&ga_fc=0&rplot=4&u_tz=120&u_his=2&u_h=768&u_w=1366&u_ah=728&u_aw=1366&u_cd=24&u_sd=1&adx=141&ady=7822&biw=1349&bih=615&scr_x=0&scr_y=0&eid=44750774%2C44753738%2C31064037%2C31064528&oid=2&pvsid=2817133588523098&pem=199&tmod=1215786858&nvt=1&ref=https%3A%2F%2Fbookflow.ru%2Fshpargalka-po-create-react-app%2F&eae=0&fc=1920&brdim=-8%2C-8%2C-8%2C-8%2C1366%2C0%2C1382%2C744%2C1366%2C615&vis=1&rsz=%7C%7CoeEbr%7C&abl=CS&pfx=0&fu=128&bc=31&ifi=2&uci=a!2&btvi=1&fsb=1&xpc=MEdTFhXkGD&p=https%3A//bookflow.ru&dtd=414
const promise = jest.fn().mockResolvedValue(true); const promiseOnce = jest.fn().mockResolvedValueOnce(true);
Они даже могут отклонять значения:
const failedPromise = jest.fn().mockRejectedValue("Роскосмос, у нас случилась оказия");
const failedPromiseOnce = jest.fn().mockRejectedValueOnce("Роскосмос, у нас случилась оказия");
Вы можете комбинировать названные подходы:
const callback = jest.fn() .mockReturnValueOnce(false) .mockReturnValue(true); // -> // вызов 1: false // вызов 2+: true
Создание фиктивных модулей с помощью метода jest.mock()
jest.mock('lodash/memoize', () => a => a) // Должна присутствовать реальная функция lodash/memoize
jest.mock('lodash/memoize', () => a => a, { virtual: true }) // Реальная функция lodash/memoize может отсутствовать
Обратите внимание, при использовании babel-jest вызовы jest.mock() будут подниматься в начало блока кода. Используйте jest.doMock() для предотвращения подобного поведения.
Создание фиктивных модулей в отдельных файлах
- Создаем файл, например,
__mocks__/lodash/memoize.js:module.exports = a => a - Добавлем его в тест:jest.mock(‘lodash/memoize’)
Методы объектов фикций
const spy = jest.spyOn(console, 'log').mockImplementation(() => {})
expect(console.log.mock.calls).toEqual([['dope'], ['nope']])
spy.mockRestore()
const spy = jest.spyOn(ajax, 'request').mockImplementation(() => Promise.resolve({ success: true }))
expect(spy).toHaveBeenCalled()
spy.mockRestore()
Геттеры и сеттеры фикций
Новая версия:
const location = {}
const getTitle = jest.spyOn(location, 'title', 'get').mockImplementation(() => 'пицца')
const setTitle = jest.spyOn(location, 'title', 'set').mockImplementation(() => {})
Старая версия:
const getTitle = jest.fn(() => 'пицца')
const setTitle = jest.fn()
const location = {}
Object.defineProperty(location, 'title', {
get: getTitle,
set: setTitle
})
Очистка и восстановление фикций
Для одной фикции:
fn.mockClear() // Удаляет дату использования фикции (fn.mock.calls, fn.mock.instances) fn.mockReset() // Удаляет любые возвращенные значения или реализации фикции fn.mockRestore() // Сбрасывает и восстанавливает первоначальную реализацию
Обратите внимание: mockRestore() работает только применительно к фикциям, созданным с помощью jest.spyOn().
Для всех фикций:
jest.clearAllMocks() jest.resetAllMocks() jest.restoreAllMocks()
Получение доступа к исходному модулю при использовании «моков»
jest.mock('fs')
const fs = require('fs') // Модуль с "моком"
const fs = require.requireActual('fs') // Исходный модуль
Фиктивные таймеры
Позволяет писать синхронные тесты для кода, в котором используются нативные таймеры (setTimeout, setInterval, clearTimeout, clearInterval).
// Разрешаем использование фиктивных таймеров
jest.useFakeTimers()
test('Убить время', () => {
const callback = jest.fn()
// Запускаем код, в котором используются `setTimeout()` или `setInterval()`
const actual = someFunctionThatUseTimers(callback)
// Перематываем до выполнения всех таймеров
jest.runAllTimers()
// Синхронно проверяем результаты
expect(callback).toHaveBeenCalledTimes(1)
})
Или настраиваем таймеры по времени с помощью advanceTimersByTime():
// Разрешаем использование фиктивных таймеров
jest.useFakeTimers()
test('Убить время', () => {
const callback = jest.fn()
// Запускаем код, в котором используются `setTimeout()` или `setInterval()`
const actual = someFunctionThatUseTimers(callback)
// Перематываем на 250 мс
jest.advanceTimersByTime(250)
// Синхронно проверяем результаты
expect(callback).toHaveBeenCalledTimes(1)
})
В особых случаях используется jest.runOnlyPendingTimers().
Обратите внимание: jest.useFakeTimers() следует вызывать только для использования других методов фиктивных таймеров.
Тестирование, основанное на данных
Запускаем одни и те же тесты с разными данными:
test.each([[3, 2, 1], [1, 2, 3], [2, 1, 3]])('.add(%s, %s)', (a, b, expected) => {
expect(a + b).toBe(expected)
})
Или с помощью шаблонных литералов:
test.each`
a | b | expected
${3} | ${2} | ${1}
${1} | ${2} | ${3}
${2} | ${1} | ${3}
`('Возвращает $expected при сложении $a и $b', ({ a, b, expected }) => {
expect(a + b).toBe(expected)
})
Или на уровне describe:
describe.each([['mobile'], ['tablet'], ['desktop']])('проверка выполнения за %s', (viewport) => {
test('отображение загруженной страницы', () => {
//
})
})
Пропуск тестов. Шпаргалка по Jest.
Не запускать указанные тесты:
describe.skip('makePoniesPink'...
tests.skip('сделать каждого пони розовым'...
Запускать только указанные тесты:
describe.only('makePoniesPink'...
tests.only('сделать каждого пони розовым'...
Тестирование модулей с побочными эффектами
Node.js и Jest will кэшируют запрашиваемые (require) модули. Для тестирования модулей с побочными эффектами необходимо очищать реестр модулей между тестами:
const modulePath = '../module-to-test'
afterEach(() => {
jest.resetModules()
})
test('первый тест', () => {
// Подготовка условия для первого теста
const result = require(modulePath)
expect(result).toMatchSnapshot()
})
test('второй тест', () => {
// Подготовка условия для первого теста
const fn = () => require(modulePath)
expect(fn).toThrow()
})
Возможно вам будет интересно — Шпаргалка по React- ответы на вопросы 2020-2021