Отказывание импорта классов ES6
Я хотел бы высмеять мои импортированные классы ES6 в своих тестовых файлах.
Если класс, издевающийся над несколькими клиентами, может иметь смысл перемещать макет в __mocks__, так что все тесты могут делиться макетом, но до тех пор я хотел бы сохранить макет в тестовом файле.
Jest.mock()
jest.mock()
могут модифицировать импортированные модули. Когда передан один аргумент:
jest.mock('./my-class.js');
он использует макетную реализацию, обнаруженную в папке __mocks__, рядом с изделенным файлом, или создает автоматический макет.
Параметр factory
jest.mock()
принимает второй аргумент, который является модулем factory. Для ES6-классов, экспортированных с использованием export default
, неясно, как должна возвращаться эта функция factory. Это:
- Другая функция, возвращающая объект, который имитирует экземпляр класса?
- Объект, который имитирует экземпляр класса?
- Объект с свойством
default
, который является функцией, которая возвращает объект, который имитирует экземпляр класса? - Функция, возвращающая функцию более высокого порядка, которая сама возвращает 1, 2 или 3?
Документы довольно неопределенны:
Второй аргумент может быть использован для указания явного модуля factory, который выполняется вместо использования функции Jest automocking:
Я изо всех сил пытаюсь найти определение factory, которое может функционировать как конструктор, когда потребитель import
класс. Я продолжаю получать TypeError: _soundPlayer2.default is not a constructor
(например).
Я попытался избежать использования функций стрелок (поскольку их нельзя вызвать с помощью new
), а factory возвращает объект, у которого есть свойство default
(или нет).
Вот пример. Это не работает; все тесты бросают TypeError: _soundPlayer2.default is not a constructor
.
Испытываемый класс: звук-плеер-consumer.js
import SoundPlayer from './sound-player'; // Default import
export default class SoundPlayerConsumer {
constructor() {
this.soundPlayer = new SoundPlayer(); //TypeError: _soundPlayer2.default is not a constructor
}
playSomethingCool() {
const coolSoundFileName = 'song.mp3';
this.soundPlayer.playSoundFile(coolSoundFileName);
}
}
Класс издевается: звук player.js
export default class SoundPlayer {
constructor() {
// Stub
this.whatever = 'whatever';
}
playSoundFile(fileName) {
// Stub
console.log('Playing sound file ' + fileName);
}
}
Тестовый файл: sound-player-consumer.test.js
import SoundPlayerConsumer from './sound-player-consumer';
import SoundPlayer from './sound-player';
// What can I pass as the second arg here that will
// allow all of the tests below to pass?
jest.mock('./sound-player', function() {
return {
default: function() {
return {
playSoundFile: jest.fn()
};
}
};
});
it('The consumer should be able to call new() on SoundPlayer', () => {
const soundPlayerConsumer = new SoundPlayerConsumer();
expect(soundPlayerConsumer).toBeTruthy(); // Constructor ran with no errors
});
it('We can check if the consumer called the mocked class constructor', () => {
const soundPlayerConsumer = new SoundPlayerConsumer();
expect(SoundPlayer).toHaveBeenCalled();
});
it('We can check if the consumer called a method on the class instance', () => {
const soundPlayerConsumer = new SoundPlayerConsumer();
const coolSoundFileName = 'song.mp3';
soundPlayerConsumer.playSomethingCool();
expect(SoundPlayer.playSoundFile).toHaveBeenCalledWith(coolSoundFileName);
});
Что я могу передать в качестве второго аргумента jest.mock(), который позволит пройти все тесты в примере? Если тесты необходимо изменить, чтобы все было в порядке - пока они все еще проверяют одни и те же вещи.