Spec-Zone.ru › Jest

Мок-функции

Мок-функции также называют «шпионами», поскольку они позволяют наблюдать за поведением функции, которая вызывается косвенно другим кодом, а не только проверять результат. Создать мок-функцию можно с помощью jest.fn(). Если реализация не указана, при вызове мок-функция вернёт undefined.

информация

Примеры TypeScript с этой страницы будут работать так, как описано, только если вы явно импортируете API Jest:

import {expect, jest, test} from '@jest/globals';

Подробные сведения о настройке Jest с TypeScript см. в руководстве Начало работы.

Методы

  • Справочник
    • mockFn.getMockImplementation()
    • mockFn.getMockName()
    • mockFn.mock.calls
    • mockFn.mock.results
    • mockFn.mock.instances
    • mockFn.mock.contexts
    • mockFn.mock.lastCall
    • mockFn.mockClear()
    • mockFn.mockReset()
    • mockFn.mockRestore()
    • mockFn.mockImplementation(fn)
    • mockFn.mockImplementationOnce(fn)
    • mockFn.mockName(name)
    • mockFn.mockReturnThis()
    • mockFn.mockReturnValue(value)
    • mockFn.mockReturnValueOnce(value)
    • mockFn.mockResolvedValue(value)
    • mockFn.mockResolvedValueOnce(value)
    • mockFn.mockRejectedValue(value)
    • mockFn.mockRejectedValueOnce(value)
    • mockFn.whenCalledWith(...args)
    • mockFn.withImplementation(fn, callback)
  • Заменённые свойства
    • replacedProperty.replaceValue(value)
    • replacedProperty.restore()
  • Использование TypeScript
    • jest.fn(implementation?)
    • jest.Mock<T>
    • jest.Mocked<Source>
    • jest.Replaced<Source>
    • jest.mocked(source, options?)
    • jest.Spied<Source>

Справочник

mockFn.getMockImplementation()

Возвращает текущую реализацию мок-функции, заданную с помощью mockImplementation(). Возвращает undefined, если реализация не задана.

  • JavaScript
  • TypeScript
const mockFn = jest.fn();

mockFn.getMockImplementation(); // undefined

mockFn.mockImplementation(() => 42);

mockFn.getMockImplementation(); // () => 42
import {jest} from '@jest/globals';

const mockFn = jest.fn<() => number>();

mockFn.getMockImplementation(); // undefined

mockFn.mockImplementation(() => 42);

mockFn.getMockImplementation(); // () => 42

mockFn.getMockName()

Возвращает строку с именем мока, заданную вызовом .mockName().

mockFn.mock.calls

Массив, содержащий аргументы всех вызовов этой мок-функции. Каждый элемент массива — это массив аргументов, переданных при вызове.

Например: у мок-функции f, вызванной дважды — сначала с аргументами f('arg1', 'arg2'), а затем с аргументами f('arg3', 'arg4'), — массив mock.calls будет выглядеть так:

[
  ['arg1', 'arg2'],
  ['arg3', 'arg4'],
];

mockFn.mock.results

Массив, содержащий результаты всех вызовов этой мок-функции. Каждая запись в этом массиве — объект, содержащий свойство type и свойство value. type может принимать одно из следующих значений:

  • 'return' — означает, что вызов завершился обычным возвратом.
  • 'throw' — означает, что вызов завершился выбросом значения.
  • 'incomplete' — означает, что вызов ещё не завершился. Это происходит, если результат проверяется внутри самой мок-функции или внутри функции, вызванной мок-функцией.

Свойство value содержит выброшенное или возвращённое значение. value имеет значение undefined, если type === 'incomplete'.

Например: у мок-функции f, вызванной трижды — вернувшей 'result1', выбросившей ошибку, а затем вернувшей 'result2', — массив mock.results будет выглядеть так:

[
  {
    type: 'return',
    value: 'result1',
  },
  {
    type: 'throw',
    value: {/* Error instance */},
  },
  {
    type: 'return',
    value: 'result2',
  },
];

mockFn.mock.instances

Массив, содержащий все экземпляры объектов, созданные этой мок-функцией с помощью new.

Например: если мок-функция была вызвана как конструктор дважды, массив mock.instances будет выглядеть так:

const mockFn = jest.fn();

const a = new mockFn();
const b = new mockFn();

mockFn.mock.instances[0] === a; // true
mockFn.mock.instances[1] === b; // true

mockFn.mock.contexts

Массив, содержащий контексты всех вызовов мок-функции.

Контекст — это значение this, получаемое функцией при вызове. Контекст можно задать с помощью Function.prototype.bind, Function.prototype.call или Function.prototype.apply.

Например:

const mockFn = jest.fn();

const boundMockFn = mockFn.bind(thisContext0);
boundMockFn('a', 'b');
mockFn.call(thisContext1, 'a', 'b');
mockFn.apply(thisContext2, ['a', 'b']);

mockFn.mock.contexts[0] === thisContext0; // true
mockFn.mock.contexts[1] === thisContext1; // true
mockFn.mock.contexts[2] === thisContext2; // true

mockFn.mock.lastCall

Массив, содержащий аргументы последнего вызова этой мок-функции. Если функция не вызывалась, будет возвращено undefined.

Например: у мок-функции f, вызванной дважды — сначала с аргументами f('arg1', 'arg2'), а затем с аргументами f('arg3', 'arg4'), — массив mock.lastCall будет выглядеть так:

['arg3', 'arg4'];

mockFn.mockClear()

Удаляет все данные, сохранённые в массивах mockFn.mock.calls, mockFn.mock.instances, mockFn.mock.contexts и mockFn.mock.results. Это часто полезно, когда нужно очистить данные об использовании мока между двумя проверками.

Параметр конфигурации clearMocks позволяет автоматически очищать моки перед каждым тестом.

внимание

Имейте в виду, что mockFn.mockClear() заменит mockFn.mock, а не только сбросит значения его свойств! Поэтому не следует присваивать mockFn.mock другим переменным — временным или постоянным, — чтобы избежать обращения к устаревшим данным.

mockFn.mockReset()

Выполняет всё то же, что и mockFn.mockClear(), а также заменяет реализацию мока пустой функцией, возвращающей undefined.

Параметр конфигурации resetMocks позволяет автоматически сбрасывать моки перед каждым тестом.

mockFn.mockRestore()

Выполняет всё то же, что и mockFn.mockReset(), а также восстанавливает исходную (не замоканную) реализацию.

Это полезно, когда в одних тестовых случаях нужно замокать функции, а в других — восстановить исходную реализацию.

Параметр конфигурации restoreMocks позволяет автоматически восстанавливать моки перед каждым тестом.

информация

mockFn.mockRestore() работает только в том случае, если мок создан с помощью jest.spyOn(). Поэтому при ручном присваивании jest.fn() восстановление необходимо выполнять самостоятельно.

mockFn.mockImplementation(fn)

Принимает функцию, которая будет использоваться в качестве реализации мока. Сам мок по-прежнему будет записывать все поступающие вызовы и создаваемые им экземпляры — единственное отличие состоит в том, что при вызове мока также будет выполняться реализация.

совет

jest.fn(implementation) — это сокращённая запись для jest.fn().mockImplementation(implementation).

  • JavaScript
  • TypeScript
const mockFn = jest.fn(scalar => 42 + scalar);

mockFn(0); // 42
mockFn(1); // 43

mockFn.mockImplementation(scalar => 36 + scalar);

mockFn(2); // 38
mockFn(3); // 39
import {jest} from '@jest/globals';

const mockFn = jest.fn((scalar: number) => 42 + scalar);

mockFn(0); // 42
mockFn(1); // 43

mockFn.mockImplementation(scalar => 36 + scalar);

mockFn(2); // 38
mockFn(3); // 39

.mockImplementation() также можно использовать для мокирования конструкторов классов:

  • JavaScript
  • TypeScript
module.exports = class SomeClass {
  method(a, b) {}
};
SomeClass.js
const SomeClass = require('./SomeClass');

jest.mock('./SomeClass'); // this happens automatically with automocking

const mockMethod = jest.fn();
SomeClass.mockImplementation(() => {
  return {
    method: mockMethod,
  };
});

const some = new SomeClass();
some.method('a', 'b');

console.log('Calls to method:', mockMethod.mock.calls);
SomeClass.test.js
export class SomeClass {
  method(a: string, b: string): void {}
}
SomeClass.ts
import {jest} from '@jest/globals';
import {SomeClass} from './SomeClass';

jest.mock('./SomeClass'); // this happens automatically with automocking

const mockMethod = jest.fn<(a: string, b: string) => void>();
jest.mocked(SomeClass).mockImplementation(() => {
  return {
    method: mockMethod,
  };
});

const some = new SomeClass();
some.method('a', 'b');

console.log('Calls to method:', mockMethod.mock.calls);
SomeClass.test.ts

mockFn.mockImplementationOnce(fn)

Принимает функцию, которая будет использоваться в качестве реализации мока для одного вызова замоканной функции. Вызовы можно объединять в цепочку, чтобы разные вызовы функции возвращали разные результаты.

  • JavaScript
  • TypeScript
const mockFn = jest
  .fn()
  .mockImplementationOnce(cb => cb(null, true))
  .mockImplementationOnce(cb => cb(null, false));

mockFn((err, val) => console.log(val)); // true
mockFn((err, val) => console.log(val)); // false
import {jest} from '@jest/globals';

const mockFn = jest
  .fn<(cb: (a: null, b: boolean) => void) => void>()
  .mockImplementationOnce(cb => cb(null, true))
  .mockImplementationOnce(cb => cb(null, false));

mockFn((err, val) => console.log(val)); // true
mockFn((err, val) => console.log(val)); // false

Когда у замоканной функции закончатся реализации, заданные с помощью .mockImplementationOnce(), она выполнит реализацию по умолчанию, заданную с помощью jest.fn(() => defaultValue) или .mockImplementation(() => defaultValue), если эти методы вызывались:

const mockFn = jest
  .fn(() => 'default')
  .mockImplementationOnce(() => 'first call')
  .mockImplementationOnce(() => 'second call');

mockFn(); // 'first call'
mockFn(); // 'second call'
mockFn(); // 'default'
mockFn(); // 'default'

mockFn.mockName(name)

Принимает строку, которая будет использоваться в выводе результатов теста вместо 'jest.fn()', чтобы указывать, на какую мок-функцию ссылаются.

Например:

const mockFn = jest.fn().mockName('mockedFunction');

// mockFn();
expect(mockFn).toHaveBeenCalled();

В результате появится такая ошибка:

expect(mockedFunction).toHaveBeenCalled()

Expected number of calls: >= 1
Received number of calls:    0

mockFn.mockReturnThis()

Сокращённая запись для:

jest.fn(function () {
  return this;
});

mockFn.mockReturnValue(value)

Сокращённая запись для:

jest.fn().mockImplementation(() => value);

Принимает значение, которое будет возвращаться при каждом вызове мок-функции.

  • JavaScript
  • TypeScript
const mock = jest.fn();

mock.mockReturnValue(42);
mock(); // 42

mock.mockReturnValue(43);
mock(); // 43
import {jest} from '@jest/globals';

const mock = jest.fn<() => number>();

mock.mockReturnValue(42);
mock(); // 42

mock.mockReturnValue(43);
mock(); // 43

mockFn.mockReturnValueOnce(value)

Сокращённая запись для:

jest.fn().mockImplementationOnce(() => value);

Принимает значение, которое будет возвращено при одном вызове мок-функции. Вызовы можно объединять в цепочку, чтобы последовательные вызовы мок-функции возвращали разные значения. Когда значения mockReturnValueOnce закончатся, вызовы будут возвращать значение, заданное с помощью mockReturnValue.

  • JavaScript
  • TypeScript
const mockFn = jest
  .fn()
  .mockReturnValue('default')
  .mockReturnValueOnce('first call')
  .mockReturnValueOnce('second call');

mockFn(); // 'first call'
mockFn(); // 'second call'
mockFn(); // 'default'
mockFn(); // 'default'
import {jest} from '@jest/globals';

const mockFn = jest
  .fn<() => string>()
  .mockReturnValue('default')
  .mockReturnValueOnce('first call')
  .mockReturnValueOnce('second call');

mockFn(); // 'first call'
mockFn(); // 'second call'
mockFn(); // 'default'
mockFn(); // 'default'

mockFn.mockResolvedValue(value)

Сокращённая запись для:

jest.fn().mockImplementation(() => Promise.resolve(value));

Полезно для мокирования асинхронных функций в асинхронных тестах:

  • JavaScript
  • TypeScript
test('async test', async () => {
  const asyncMock = jest.fn().mockResolvedValue(43);

  await asyncMock(); // 43
});
import {jest, test} from '@jest/globals';

test('async test', async () => {
  const asyncMock = jest.fn<() => Promise<number>>().mockResolvedValue(43);

  await asyncMock(); // 43
});

mockFn.mockResolvedValueOnce(value)

Сокращённая запись для:

jest.fn().mockImplementationOnce(() => Promise.resolve(value));

Полезно для возврата разных значений в нескольких асинхронных вызовах:

  • JavaScript
  • TypeScript
test('async test', async () => {
  const asyncMock = jest
    .fn()
    .mockResolvedValue('default')
    .mockResolvedValueOnce('first call')
    .mockResolvedValueOnce('second call');

  await asyncMock(); // 'first call'
  await asyncMock(); // 'second call'
  await asyncMock(); // 'default'
  await asyncMock(); // 'default'
});
import {jest, test} from '@jest/globals';

test('async test', async () => {
  const asyncMock = jest
    .fn<() => Promise<string>>()
    .mockResolvedValue('default')
    .mockResolvedValueOnce('first call')
    .mockResolvedValueOnce('second call');

  await asyncMock(); // 'first call'
  await asyncMock(); // 'second call'
  await asyncMock(); // 'default'
  await asyncMock(); // 'default'
});

mockFn.mockRejectedValue(value)

Сокращённая запись для:

jest.fn().mockImplementation(() => Promise.reject(value));

Полезно для создания асинхронных мок-функций, которые всегда завершаются отклонённым промисом:

  • JavaScript
  • TypeScript
test('async test', async () => {
  const asyncMock = jest
    .fn()
    .mockRejectedValue(new Error('Async error message'));

  await asyncMock(); // throws 'Async error message'
});
import {jest, test} from '@jest/globals';

test('async test', async () => {
  const asyncMock = jest
    .fn<() => Promise<never>>()
    .mockRejectedValue(new Error('Async error message'));

  await asyncMock(); // throws 'Async error message'
});

mockFn.mockRejectedValueOnce(value)

Сокращённая запись для:

jest.fn().mockImplementationOnce(() => Promise.reject(value));

Полезно в сочетании с .mockResolvedValueOnce() или для отклонения промиса с разными исключениями в нескольких асинхронных вызовах:

  • JavaScript
  • TypeScript
test('async test', async () => {
  const asyncMock = jest
    .fn()
    .mockResolvedValueOnce('first call')
    .mockRejectedValueOnce(new Error('Async error message'));

  await asyncMock(); // 'first call'
  await asyncMock(); // throws 'Async error message'
});
import {jest, test} from '@jest/globals';

test('async test', async () => {
  const asyncMock = jest
    .fn<() => Promise<string>>()
    .mockResolvedValueOnce('first call')
    .mockRejectedValueOnce(new Error('Async error message'));

  await asyncMock(); // 'first call'
  await asyncMock(); // throws 'Async error message'
});

mockFn.whenCalledWith(...args)

Настраивает возвращаемое значение или реализацию, которые срабатывают только тогда, когда мок вызывается с аргументами, соответствующими ...args. Полезно, когда один мок должен вести себя по-разному для разных списков аргументов, без ветвления логики внутри mockImplementation.

const fn = jest.fn();
fn.whenCalledWith('apple').mockReturnValue('red');
fn.whenCalledWith('banana').mockReturnValue('yellow');

fn('apple'); // 'red'
fn('banana'); // 'yellow'
fn('grape'); // undefined

Возвращаемый объект — это настоящий Mock, поэтому здесь доступны все методы цепочки обычного jest.fn(): mockReturnValue, mockReturnValueOnce, mockResolvedValue, mockResolvedValueOnce, mockRejectedValue, mockRejectedValueOnce, mockImplementation, mockImplementationOnce. Каждый подходящий вызов направляется в соответствующий подмок; вызовы, не соответствующие условиям, передаются базовому моку.

Сопоставление

Каждый элемент args принимает литерал или любой асимметричный матчёр:

fn.whenCalledWith(expect.any(Number)).mockReturnValue('numeric');
fn.whenCalledWith({user: expect.any(String)}).mockReturnValue('user');

fn(42); // 'numeric'
fn({user: 'alice'}); // 'user'

Структурное равенство, различение Map/Set и асимметричные матчёры работают так, как и ожидается от toHaveBeenCalledWith(). Пользовательские тестеры, зарегистрированные через expect.addEqualityTesters(...), пока не применяются при сопоставлении whenCalledWith. Если вам это необходимо, создайте задачу.

  • Арность — whenCalledWith('a') соответствует fn('a') и fn('a', undefined), но не fn('a', 'b') или fn(). (Допускаются завершающие undefined, чтобы соответствовать существующей семантике отслеживания вызовов Jest.)
  • Глубокое равенство — объекты, массивы, Map и Set сравниваются структурно.

Несколько матчёров

Разные матчёры направляют вызовы независимо:

const fn = jest.fn();
fn.whenCalledWith('a').mockReturnValue(1);
fn.whenCalledWith('b').mockReturnValue(2);
fn.whenCalledWith('c').mockReturnValue(3);

fn('a'); // 1
fn('b'); // 2
fn('c'); // 3
fn('z'); // undefined

Две регистрации, матчёры которых пересекаются для определённого вызова (например, expect.objectContaining({a: 1}) и expect.objectContaining({b: 2}) для fn({a: 1, b: 2})), обе соответствуют ему. Правила приоритета ниже определяют, какая из них сработает.

Одноразовые и постоянные значения

mockReturnValueOnce добавляет одноразовое значение в очередь соответствующей ветви; mockReturnValue задаёт постоянное значение по умолчанию. Одноразовые значения используются в порядке регистрации, а затем срабатывает постоянное значение:

fn.whenCalledWith('x')
  .mockReturnValueOnce('A')
  .mockReturnValueOnce('B')
  .mockReturnValue('persistent');

fn('x'); // 'A'
fn('x'); // 'B'
fn('x'); // 'persistent'
fn('x'); // 'persistent'

Асинхронные варианты работают так же:

const fetchUser = jest.fn();
fetchUser.whenCalledWith(1).mockResolvedValue({id: 1});
fetchUser.whenCalledWith(2).mockRejectedValue(new Error('not found'));

Повторные вызовы возвращают новые ветви

Каждый вызов whenCalledWith(...) возвращает совершенно новый подмок, даже если матчёры выглядят одинаково. Вызовы с пересекающимися матчёрами разрешаются по приведённым ниже правилам приоритета: преимущество имеет последнее зарегистрированное постоянное значение, а одноразовые значения из очереди используются в порядке регистрации во всех подходящих ветвях:

fn.whenCalledWith('x')
  .mockReturnValueOnce('first-once')
  .mockReturnValue('first-persistent');
fn.whenCalledWith('x')
  .mockReturnValueOnce('second-once')
  .mockReturnValue('second-persistent');

fn('x'); // 'first-once'         (earliest matching branch's queued once)
fn('x'); // 'second-once'        (next branch's queued once)
fn('x'); // 'second-persistent'  (last-registered persistent wins after onces drain)
fn('x'); // 'second-persistent'

Передача вызова базовому моку

Когда в подходящей ветви заканчиваются значения (одноразовые значения из очереди использованы, а постоянное значение не задано), вызов передаётся базовому моку — он не возвращает undefined без предупреждения:

fn.mockReturnValue('default');
fn.whenCalledWith('x').mockReturnValueOnce('once');

fn('x'); // 'once'
fn('x'); // 'default' (matched branch drained, falls through)
fn('y'); // 'default' (no matcher fires)

Приоритет

Если одному вызову соответствуют несколько регистраций, они разрешаются в следующем порядке:

Приоритет Источник
1 Очередь базового *Once (fn.mockReturnValueOnce, fn.mockImplementationOnce и т. д.) — наиболее явное переопределение для одного вызова, срабатывающее независимо от совпадающих ветвей
2 Самая ранняя зарегистрированная подходящая ветвь с *Once
3 Самая поздняя зарегистрированная подходящая ветвь с постоянной реализацией
4 Реализация, заданная для базового мока (fn.mockReturnValue, исходный метод spyOn и т. д.), или undefined, если её нет
fn.mockReturnValue('base');
fn.whenCalledWith('x').mockReturnValue('matched-persistent');
fn.whenCalledWith('x').mockReturnValueOnce('matched-once');
fn.mockReturnValueOnce('base-once');

fn('x'); // 'base-once'           — priority 1
fn('x'); // 'matched-once'        — priority 2
fn('x'); // 'matched-persistent'  — priority 3
fn('y'); // 'base'                — priority 4 (no match)

Для шпионов

Работает с jest.spyOn(). Вызовы, не соответствующие условиям, передаются исходному методу объекта, за которым ведётся наблюдение:

const target = {greet: name => `hello ${name}`};
const spy = jest.spyOn(target, 'greet');
spy.whenCalledWith('world').mockReturnValue('hi world');

target.greet('world'); // 'hi world'
target.greet('jest'); // 'hello jest' (original method)

Сброс

Вызов mockReset() для родительского объекта удаляет все регистрации whenCalledWith и сбрасывает каждый подмок, поэтому все сохранённые ссылки будут отражать состояние после сброса. Вызов mockReset() для подмока очищает только эту ветвь.

fn.whenCalledWith('x').mockReturnValue('X');
fn('x'); // 'X'
fn.mockReset();
fn('x'); // undefined — registration gone

TypeScript

whenCalledWith принимает тот же кортеж матчёров, что и toHaveBeenCalledWith: тип каждого параметра ограничен типом параметра мока, но в соответствующем элементе также допускается асимметричный матчёр. Цепочки вызовов mockReturnValue/mockResolvedValue ограничены типом возвращаемого значения мока:

const fn = jest.fn<(id: number, options?: {strict: boolean}) => string>();

fn.whenCalledWith(1, {strict: true}).mockReturnValue('exact');
fn.whenCalledWith(expect.any(Number)).mockReturnValue('any number');
fn.whenCalledWith(1).mockReturnValue(42); // Type error — return must be string
fn.whenCalledWith('one'); // Type error — first arg must be number

mockFn.withImplementation(fn, callback)

Принимает функцию, которая будет временно использоваться в качестве реализации мока во время выполнения обратного вызова.

test('test', () => {
  const mock = jest.fn(() => 'outside callback');

  mock.withImplementation(
    () => 'inside callback',
    () => {
      mock(); // 'inside callback'
    },
  );

  mock(); // 'outside callback'
});

mockFn.withImplementation можно использовать независимо от того, является ли обратный вызов асинхронным (возвращает ли он thenable). Если обратный вызов асинхронный, будет возвращён промис. Ожидание этого промиса дождётся завершения обратного вызова и сбросит реализацию.

test('async test', async () => {
  const mock = jest.fn(() => 'outside callback');

  // We await this call since the callback is async
  await mock.withImplementation(
    () => 'inside callback',
    async () => {
      mock(); // 'inside callback'
    },
  );

  mock(); // 'outside callback'
});

Заменённые свойства

replacedProperty.replaceValue(value)

Изменяет значение уже заменённого свойства. Это полезно, когда нужно заменить свойство, а затем настроить его значение в отдельных тестах. В качестве альтернативы можно несколько раз вызвать jest.replaceProperty() для одного и того же свойства.

replacedProperty.restore()

Восстанавливает исходное значение свойства объекта.

Обратите внимание, что replacedProperty.restore() работает только в том случае, если значение свойства было заменено с помощью jest.replaceProperty().

Параметр конфигурации restoreMocks позволяет автоматически восстанавливать заменённые свойства перед каждым тестом.

Использование TypeScript

информация

Примеры TypeScript с этой страницы будут работать так, как описано, только если вы явно импортируете API Jest:

import {expect, jest, test} from '@jest/globals';

Подробные сведения о настройке Jest с TypeScript см. в руководстве Начало работы.

jest.fn(implementation?)

Если передать реализацию в jest.fn(), правильные типы мока будут выведены автоматически. Во многих случаях реализация не указывается. Чтобы обеспечить безопасность типов, можно передать аргумент обобщённого типа (дополнительные примеры см. выше):

import {expect, jest, test} from '@jest/globals';
import type add from './add';
import calculate from './calc';

test('calculate calls add', () => {
  // Create a new mock that can be used in place of `add`.
  const mockAdd = jest.fn<typeof add>();

  // `.mockImplementation()` now can infer that `a` and `b` are `number`
  // and that the returned value is a `number`.
  mockAdd.mockImplementation((a, b) => {
    // Yes, this mock is still adding two numbers but imagine this
    // was a complex function we are mocking.
    return a + b;
  });

  // `mockAdd` is properly typed and therefore accepted by anything
  // requiring `add`.
  calculate(mockAdd, 1, 2);

  expect(mockAdd).toHaveBeenCalledTimes(1);
  expect(mockAdd).toHaveBeenCalledWith(1, 2);
});

jest.Mock<T>

Создаёт тип мок-функции, например тип возвращаемого значения jest.fn(). Это может быть полезно, если необходимо определить рекурсивную мок-функцию:

import {jest} from '@jest/globals';

const sumRecursively: jest.Mock<(value: number) => number> = jest.fn(value => {
  if (value === 0) {
    return 0;
  } else {
    return value + fn(value - 1);
  }
});

jest.Mocked<Source>

Вспомогательный тип jest.Mocked<Source> возвращает тип Source, дополненный определениями типов мок-функции Jest.

import {expect, jest, test} from '@jest/globals';
import type {fetch} from 'node-fetch';

jest.mock('node-fetch');

let mockedFetch: jest.Mocked<typeof fetch>;

afterEach(() => {
  mockedFetch.mockClear();
});

test('makes correct call', () => {
  mockedFetch = getMockedFetch();
  // ...
});

test('returns correct data', () => {
  mockedFetch = getMockedFetch();
  // ...
});

Типы классов, функций или объектов можно передать в качестве аргумента типа для jest.Mocked<Source>. Если вы предпочитаете ограничить входной тип, используйте: jest.MockedClass<Source>, jest.MockedFunction<Source> или jest.MockedObject<Source>.

jest.Replaced<Source>

Вспомогательный тип jest.Replaced<Source> возвращает тип Source, дополненный определениями типов заменённого свойства Jest.

export function isLocalhost(): boolean {
  return process.env['HOSTNAME'] === 'localhost';
}
src/utils.ts
import {afterEach, expect, it, jest} from '@jest/globals';
import {isLocalhost} from '../utils';

let replacedEnv: jest.Replaced<typeof process.env> | undefined = undefined;

afterEach(() => {
  replacedEnv?.restore();
});

it('isLocalhost should detect localhost environment', () => {
  replacedEnv = jest.replaceProperty(process, 'env', {HOSTNAME: 'localhost'});

  expect(isLocalhost()).toBe(true);
});

it('isLocalhost should detect non-localhost environment', () => {
  replacedEnv = jest.replaceProperty(process, 'env', {HOSTNAME: 'example.com'});

  expect(isLocalhost()).toBe(false);
});
src/__tests__/utils.test.ts

jest.mocked(source, options?)

Вспомогательный метод mocked() оборачивает типы объекта source и его вложенных элементов определениями типов мок-функций Jest. Чтобы отключить глубокое мокирование, передайте {shallow: true} в качестве аргумента options.

Возвращает объект source.

export const song = {
  one: {
    more: {
      time: (t: number) => {
        return t;
      },
    },
  },
};
song.ts
import {expect, jest, test} from '@jest/globals';
import {song} from './song';

jest.mock('./song');
jest.spyOn(console, 'log');

const mockedSong = jest.mocked(song);
// or through `jest.Mocked<Source>`
// const mockedSong = song as jest.Mocked<typeof song>;

test('deep method is typed correctly', () => {
  mockedSong.one.more.time.mockReturnValue(12);

  expect(mockedSong.one.more.time(10)).toBe(12);
  expect(mockedSong.one.more.time.mock.calls).toHaveLength(1);
});

test('direct usage', () => {
  jest.mocked(console.log).mockImplementation(() => {
    return;
  });

  console.log('one more time');

  expect(jest.mocked(console.log).mock.calls).toHaveLength(1);
});
song.test.ts

jest.Spied<Source>

Создаёт тип объекта класса или функции, за которыми ведётся наблюдение (то есть тип возвращаемого значения jest.spyOn()).

import {jest} from '@jest/globals';

export function setDateNow(now: number): jest.Spied<typeof Date.now> {
  return jest.spyOn(Date, 'now').mockReturnValue(now);
}
__utils__/setDateNow.ts
import {afterEach, expect, type jest, test} from '@jest/globals';
import {setDateNow} from './__utils__/setDateNow';

let spiedDateNow: jest.Spied<typeof Date.now> | undefined = undefined;

afterEach(() => {
  spiedDateNow?.mockReset();
});

test('renders correctly with a given date', () => {
  spiedDateNow = setDateNow(1_482_363_367_071);
  // ...

  expect(spiedDateNow).toHaveBeenCalledTimes(1);
});

Типы класса или функции можно передать в качестве аргумента типа для jest.Spied<Source>. Если вы предпочитаете ограничить входной тип, используйте jest.SpiedClass<Source> или jest.SpiedFunction<Source>.

Используйте jest.SpiedGetter<Source> или jest.SpiedSetter<Source>, чтобы создать тип метода получения или установки, за которым ведётся наблюдение.

© 2022 Facebook, Inc.
Licensed under the MIT License.
https://jestjs.io/docs/mock-function-api

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API