我正在尝试使用Jest,Enzyme的useEffect和useCallback的React挂钩编写单元测试用例,但是我无法成功。有人可以帮我为下面的代码编写测试用例吗?
ModalComponent.jsx
const ModalComponent = ({ closeModal }) => {
const handleModal = useCallback((event) => {
if (event.keyCode === 27) {
closeModal(false);
}
}
useEffect(() => {
document.addEventListener('keydown', handleModal);
return () => document.removeEventListener('keydown', handleModal);
}, []);
return (
<Modal>
<Header onClose={closeModal} />
<Body />
<Footer />
</Modal>
);
}
ModalComponent.spec.jsx
describe('Modal Component', () => {
let props;
beforeEach(() => {
props = {
closeModal: jest.fn(),
};
};
it('should handle useEffect', () => {
jest.spyOn(React, 'useEffect').mockImplementation(f => f());
document.addEventListener('keydown', handleModal);
document.removeEventListener('keydown', handleModal);
const component = shallow(<ModalComponent />);
});
});
无法覆盖这些行document.addEventListener('keydown', handleModal);
,document.removeEventListener('keydown', handleModal);
,if(event.keyCode === 27)
,closeModal(false)
。如何涵盖测试用例?
答案 0 :(得分:0)
除非有必要,否则不应该对反应内部进行模拟,因为这会导致综合测试与框架的工作方式不一致并给出错误肯定。这尤其适用于useEffect
之类的钩子,因为它们具有隐藏状态并且可能无法如测试人员所期望的那样工作。
反应功能组件不会公开组件实例,应该通过声明结果来进行测试。可以通过间谍断言加强测试,以减少结果的歧义。
由于在document
上设置了侦听器,因此需要重点关注,例如:
jest.spyOn(document, 'addEventListener');
jest.spyOn(document, 'removeEventListener');
const onCloseSpy = jest.fn();
const component = mount(<ModalComponent closeModal={onCloseSpy} />);
expect(component.find(Header).prop('onClose')).toBe(onCloseSpy);
expect(document.addEventListener).toBeCalledTimes(1);
expect(document.addEventListener).toBeCalledWith('keydown', expect.any(Function));
document.dispatchEvent(new KeyboardEvent('keydown', {keyCode: 37}));
expect(onCloseSpy).not.toBeCalled();
document.dispatchEvent(new KeyboardEvent('keydown', {keyCode: 27}));
expect(onCloseSpy).toBeCalledWith(false);
// rerender to make sure listeners are set once
component.setProps({});
expect(document.addEventListener).toBeCalledTimes(1);
expect(document.removeEventListener).not.toBeCalled();
// unmount
component.unmount();
expect(document.removeEventListener).toBeCalledTimes(1);
const [, callback] = document.addEventListener.mock.calls[0];
expect(document.removeEventListener).toBeCalledWith('keydown', callback);