Импровизированный импорт, который вводит два псевдонима - PullRequest
0 голосов
/ 14 января 2019

Я пытаюсь написать модульные тесты в Jest, чтобы смоделировать несколько частей кода, используя библиотеку moment.js. Для полноты, это проект Node + Express, написанный как TypeScript с поддерживаемым файлом moment.d.ts.

Блок импорта и кода, который я пытаюсь проверить:

import moment from 'moment';

const durationSinceLastEmail = moment.duration(moment(new Date())
                .diff(moment(user.passwordRecoveryTokenRequestDate)));

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

(alias) function moment(inp?: moment.MomentInput, format?: moment.MomentFormatSpecification, strict?: boolean): moment.Moment (+1 overload)
(alias) namespace moment
import moment

Мой код реализации использует обе формы: moment.duration для пространства имен и moment(...params) для функции.

Моя общая стратегия насмешек над Шутом не была очень эффективной. Ex)

jest.mock('moment', () => {
    return jest.fn().mockImplementation( () => {
        return {
            duration: (...params) => mockDuration(...params)
        };
    });
});

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

const originalDuration: Function = moment.duration;

mockDuration.mockImplementation((...params) => {
    const original = originalDuration(...params);
    // Apply mocks on returning object here
    // or supply entirely new mock object
    return original;
});

moment.duration = mockDuration;

Честно говоря, код довольно грубый, но он уводит меня наполовину, поскольку это позволяет мне перехватывать вызовы moment.duration(...params), но каждый метод, который я пробовал для макета вызова moment(...), либо не работал, либо полностью конфликтует с подходом выше (и тоже не работает).

Кажется, источником моих проблем является конфликт имен, поэтому мой вопрос:

1) Могу ли я в любом случае выделить эти разные ссылки, чтобы их можно было явно рассмотреть?

или

2) Есть ли для меня эффективный способ поразить их по отдельности или иным образом предоставить имитацию как для функции, так и для пространства имен в одном объекте-макете?

1 Ответ

0 голосов
/ 14 января 2019

Вы можете создать Ручной макет для moment и дать ему любую реализацию, какую захотите.

Создайте __mocks__/moment.js в корне вашего проекта рядом с node_modules:

const momentMock = jest.fn();  // create the moment mock
momentMock.mockImplementation(() => ({ diff: jest.fn() }));  // give it a mock implementation

momentMock.duration = jest.fn();  // add the moment.duration mock

export default momentMock;  // export the mock

Позвоните jest.mock('moment'); в своем тесте, чтобы использовать макет:

import moment from 'moment';

jest.mock('moment');  // use the mock

test('durationSinceLastEmail', () => {
  const user = {
    passwordRecoveryTokenRequestDate: new Date('2019-01-01')
  }
  const durationSinceLastEmail = moment.duration(moment(new Date())
    .diff(moment(user.passwordRecoveryTokenRequestDate)));

  expect(moment).toHaveBeenCalledTimes(2);  // SUCCESS
  expect(moment.duration).toHaveBeenCalledTimes(1);  // SUCCESS
});
...