使用this answer中的代码解决组件外部的点击问题:
componentDidMount() {
document.addEventListener('mousedown', this.handleClickOutside);
}
componentWillUnmount() {
document.removeEventListener('mousedown', this.handleClickOutside);
}
setWrapperRef(node) {
this.wrapperRef = node;
}
handleClickOutside(event) {
if (this.wrapperRef && !this.wrapperRef.contains(event.target)) {
this.props.actions.something() // Eg. closes modal
}
}
我无法弄清楚如何对不愉快的路径进行单元测试,以便警报不会运行,到目前为止我所得到的:
it('Handles click outside of component', () => {
props = {
actions: {
something: jest.fn(),
}
}
const wrapper = mount(
<Component {... props} />,
)
expect(props.actions.something.mock.calls.length).toBe(0)
// Happy path should trigger mock
wrapper.instance().handleClick({
target: 'outside',
})
expect(props.actions.something.mock.calls.length).toBe(1) //true
// Unhappy path should not trigger mock here ???
expect(props.actions.something.mock.calls.length).toBe(1)
})
我试过了:
wrapper.html()
.find
一个节点并通过发送(不会模拟event.target
).simulate
click
内部元素(不触发事件监听器)我确定我错过了一些小事,但我无法在任何地方找到这样的例子。
答案 0 :(得分:21)
import { mount } from 'enzyme'
import React from 'react'
import ReactDOM from 'react-dom'
it('Should not call action on click inside the component', () => {
const map = {}
document.addEventListener = jest.fn((event, cb) => {
map[event] = cb
})
const props = {
actions: {
something: jest.fn(),
}
}
const wrapper = mount(<Component {... props} />)
map.mousedown({
target: ReactDOM.findDOMNode(wrapper.instance()),
})
expect(props.actions.something).not.toHaveBeenCalled()
})
来自this酶问题的解决方案在github上。
答案 1 :(得分:2)
所选答案未涵盖handleClickOutside
的else路径
我在ref元素上添加了mousedown事件,以触发handleClickOutside
的else路径
import { mount } from 'enzyme'
import React from 'react'
import ReactDOM from 'react-dom'
it('Should not call action on click inside the component', () => {
const map = {}
document.addEventListener = jest.fn((event, cb) => {
map[event] = cb
})
const props = {
actions: {
something: jest.fn(),
}
}
//test if path of handleClickOutside
const wrapper = mount(<Component {... props} />)
map.mousedown({
target: ReactDOM.findDOMNode(wrapper.instance()),
})
//test else path of handleClickOutside
const refWrapper = mount(<RefComponent />)
map.mousedown({
target: ReactDOM.findDOMNode(refWrapper.instance()),
})
expect(props.actions.something).not.toHaveBeenCalled()
})
答案 2 :(得分:0)
我发现可以避免使用ReactDOM.findDOMNode
的情况/解决方案。请看下面的例子:
import React from 'react';
import { shallow } from 'enzyme';
const initFireEvent = () => {
const map = {};
document.addEventListener = jest.fn((event, cb) => {
map[event] = cb;
});
document.removeEventListener = jest.fn(event => {
delete map[event];
});
return map;
};
describe('<ClickOutside />', () => {
const fireEvent = initFireEvent();
const children = <button type="button">Content</button>;
it('should call actions.something() when clicking outside', () => {
const props = {
actions: {
something: jest.fn(),
}
};
const onClick = jest.fn();
mount(<ClickOutside {...props}>{children}</ClickOutside>);
fireEvent.mousedown({ target: document.body });
expect(props.actions.something).toHaveBeenCalledTimes(1);
});
it('should NOT call actions.something() when clicking inside', () => {
const props = {
actions: {
something: jest.fn(),
}
};
const wrapper = mount(
<ClickOutside onClick={onClick}>{children}</ClickOutside>,
);
fireEvent.mousedown({
target: wrapper.find('button').instance(),
});
expect(props.actions.something).not.toHaveBeenCalled();
});
});
版本:
"react": "^16.8.6",
"jest": "^25.1.0",
"enzyme": "^3.11.0",
"enzyme-adapter-react-16": "^1.15.2"
答案 3 :(得分:0)
最简单的事情就是在主体上调度事件
mount(<MultiTagSelect {...props} />);
window.document.body.dispatchEvent(new Event('click'));
答案 4 :(得分:-1)
使用sinon
跟踪是否调用handleClickOutside
。顺便说一下,我刚刚发布了我需要在Nav
组件中进行单元测试的项目。实际上,当您单击外部时,应关闭所有子菜单。
import sinon from 'sinon';
import Component from '../src/Component';
it('handle clicking outside', () => {
const handleClickOutside = sinon.spy(Component.prototype, 'handleClickOutside');
const wrapper = mount(
<div>
<Component {... props} />
<div><a class="any-element-outside">Anylink</a></div>
</div>
);
wrapper.find('.any-element-outside').last().simulate('click');
expect(handleClickOutside.called).toBeTruthy();
handleClickOutside.restore();
})