На самом деле это рекомендуется для юнит-тестов, которые чаще всего насмехаются, если не все зависимости.Крошечная вещь mocking работает для всего модуля - поэтому ему нужно дополнительные усилия , если вам нужно смоделировать определенный export
, но оставить еще один живой.
Вы простонадо издеваться над BackHandler
компонентом.Но если вы напишите что-то вроде
jest.mock('react-native');
// ...
Вы получите сообщение о том, что
BackHandler.addEventListener не является функцией
Это потому, что base jest.mock()
заменяет каждый экспорт на jest.fn()
фиктивную функцию.Но BackHandler
изначально не является функцией, это объект.
Поэтому вам нужно смоделировать модуль вручную, указав значение для BackHandler
:
import { BackHandler } from 'react-native'; // it's needed to direct access mocked version
jest.mock('react-native', () => {
BackHandler: {
addEventListener: jest.fn(),
removeEventListener: jest.fn(),
}
});
describe('Sample', () => {
it('binds to BackHandler on mount and clean up on destroy', () => {
const wrapper = shallow(<Sample />);
expect(BackHandler.addEventListener).toHaveBeenCalledWith('hardwareBackPress');
wrapper.unmount();
expect(BackHandler.removeEventListener).toHaveBeenCalledWith('hardwareBackPress');
});
Для имитации hardwareBackPress
I 'Я бы предложил несколько разных способов:
, чтобы смоделировать addEventListener
/ removeEventListener
с реальным обратным вызовом при сохранении (этот подход понятен, но требует дополнительного кода - а также он нуждается в очисткемежду тестами)
const callbacks = {};
function helperTriggerListeners(eventName, event) {
(callbacks[eventName] || []).forEach(callback => callback(event));
}
jest.mock('react-native', () => {
BackHandler: {
addEventListener: jest.fn().mockImplementation((eventName, callback) => {
callbacks[eventName] = callbacks[eventName] || [];
callbacks[eventName].psuh(callback);
}),
removeEventListener: jest.fn().mockImplementation((eventName, callback) => {
const indexOf = (callbacks[eventName] || []).indexOf(callback);
if (indexOf != -1) {
callbacks[eventName] = callbacks[eventName].splice(indexOf, 1);
}
}),
}
});
beforeEach(() => {
// really important to ensure it's clean from data made in older runs
callbacks = {};
BackHandler.addEventListener.mockClear();
BackHandler.removeEventListener.mockClear();
});
it('...', () => {
helperTriggerListeners('hardwareBackPress', { /* mocked event if required */});
expect(someOtherMockedService.someMethod).toHaveBeenCalled();
принять обратный вызов прямо из addEventListener
макет журнала:
beforeEach(() => {
// really important otherwise you may call callbacks for component already unmounted
BackHandler.addEventListener.mockClear();
BackHandler.removeEventListener.mockClear();
});
it('reacts on hardwareBackPress', () => {
const wrapper = shallow(<Sample />);
BackHandler.addEventListener.mock.calls.forEach(oneCall => {
if (oneCall[0] === 'hardwareBackPress') oneCall[1]({ /*mocked Event object*/ });
})
expect(someOtherMockedService.someMethod).toHaveBeenCalled();