Я что-то упускаю из-за того, как шутка работает под капотом?
Две вещи на заметку:
- ES6
import
вызовы подняты в верхнюю часть текущего диапазона
babel-jest
поднимает вызовы на jest.mock
наверх их кодового блока (прежде всего, включая любые вызовы ES6 import
в блоке)
Чем отличается способ создания учетной записиКлиента от клиента, что означает, что в тесте можно шпионить за пробой?
В обоих случаях это выполняется первым:
jest.mock('postmark');
... который автоматически смоделирует модуль postmark
.
Затем запускается:
import accountApi from './account-api';
В оригинальной реализации эта строка запускается:
const accountClient = postmark.AccountClient(accountToken);
... который фиксирует результат вызова postmark.AccountClient
и сохраняет его в accountClient
. Автоматическое макетирование postmark
будет иметь заглушку AccountClient
с фиктивной функцией, которая возвращает undefined
, поэтому accountClient
будет установлено на undefined
.
В обоих случаях теперь запускается тестовый код, который устанавливает макет для postmark.AccountClient
.
Затем во время теста запускается эта строка:
await accountApi.listServers();
В оригинальной реализации этот вызов заканчивается выполнением этого:
const servers = await accountClient.getServers();
... который падает до catch
, поскольку accountClient
не определено, ошибка регистрируется, и тест продолжается до тех пор, пока не произойдет сбой в этой строке:
expect(mockGetServers).toHaveBeenCalledTimes(1);
... так как mockGetServers
никогда не вызывали.
С другой стороны, в рабочей реализации это работает:
const accountClient = postmark.AccountClient(accountToken);
const servers = await accountClient.getServers();
... и так как postmark
подвергается насмешке по этому пункту, он использует макет и тест проходит.
Есть ли способ, которым я могу издеваться (и шпионить) за объектом, который создается на уровне класса, а не на уровне функции?
Да.
Поскольку оригинальная реализация фиксирует результат вызова postmark.AccountClient
, как только он импортирован , вам просто нужно убедиться, что ваш макет настроен , прежде чем импортировать оригинальную реализацию .
Один из самых простых способов сделать это - настроить макет с фабрикой модулей во время вызова на jest.mock
, так как он поднимается и запускается первым.
Вот обновленный тест, который работает с оригинальной реализацией :
import * as postmark from 'postmark';
jest.mock('postmark', () => { // use a module factory
const mockGetServers = jest.fn();
const AccountClient = jest.fn(() => {
return {
getServers: mockGetServers // NOTE: this returns the same mockGetServers every time
};
});
return {
AccountClient
}
});
import accountApi from './account-api';
describe('account-api', () => {
describe('listServers', () => {
it('calls postmark listServers', async () => {
await accountApi.listServers();
const mockGetServers = postmark.AccountClient().getServers; // get mockGetServers
expect(mockGetServers).toHaveBeenCalledTimes(1); // Success!
});
});
});