Javascript 单元测试在组件外部进行
使用“中的代码”解决在零部件外部单击的问题:Javascript 单元测试在组件外部进行,javascript,unit-testing,reactjs,jestjs,enzyme,Javascript,Unit Testing,Reactjs,Jestjs,Enzyme,使用“中的代码”解决在零部件外部单击的问题: componentDidMount() { document.addEventListener('mousedown', this.handleClickOutside); } componentWillUnmount() { document.removeEventListener('mousedown', this.handleClickOutside); } setWrapperRef(node) { this.wr
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)
})
it('Handles click out of component',()=>{
道具={
行动:{
某物:jest.fn(),
}
}
常量包装器=装入(
,
)
expect(props.actions.something.mock.calls.length).toBe(0)
//快乐之路应该引发嘲笑
wrapper.instance().handleClick({
目标:“外部”,
})
expect(props.actions.something.mock.calls.length).toBe(1)//true
//不愉快的路径不应该在这里触发mock???
expect(道具、动作、某物、模拟、呼叫、长度)toBe(1)
})
我试过:
- 通过
wrapper.html()发送
调用节点并发送(不模拟.find
)事件。目标
ing.simulate
(不触发事件侦听器)单击内部元素上的
我确信我遗漏了一些小的东西,但我在任何地方都找不到这样的例子。使用
sinon
跟踪handleclickout
是否被调用。顺便说一下,我刚刚发布了我们的项目,需要在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();
})
从“sinon”导入sinon;
从“../src/Component”导入组件;
它('点击外部的手柄',()=>{
const handleClickOutside=sinon.spy(Component.prototype,'handleClickOutside');
常量包装器=装入(
任意链接
);
find('.any element out').last().simulate('click');
expect(handleClickOutside.called).toBeTruthy();
handleClickOutside.restore();
})
从“酶”导入{mount}
从“React”导入React
从“react dom”导入react dom
它('在组件内部单击时不应调用操作',()=>{
常量映射={}
document.addEventListener=jest.fn((事件,cb)=>{
映射[事件]=cb
})
常量道具={
行动:{
某物:jest.fn(),
}
}
const wrapper=mount()
穆斯敦地图({
目标:ReactDOM.findDOMNode(wrapper.instance()),
})
expect(props.actions.something).not.toHaveBeenCalled()
})
github上酶问题的解决方案。所选答案未涵盖
handleClickOutside的else路径
我在ref元素上添加了mousedown事件,以触发handleClickOutside
从“酶”导入{mount}
从“React”导入React
从“react dom”导入react dom
它('在组件内部单击时不应调用操作',()=>{
常量映射={}
document.addEventListener=jest.fn((事件,cb)=>{
映射[事件]=cb
})
常量道具={
行动:{
某物:jest.fn(),
}
}
//测试手柄的路径是否在外侧
const wrapper=mount()
穆斯敦地图({
目标:ReactDOM.findDOMNode(wrapper.instance()),
})
//handleClickOutside的测试路径
常量refWrapper=mount()
穆斯敦地图({
目标:ReactDOM.findDOMNode(refWrapper.instance()),
})
expect(props.actions.something).not.toHaveBeenCalled()
})
我发现可以避免使用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();
});
});
最简单的事情就是在身体上发送事件
mount();
window.document.body.dispatchEvent(新事件('click'))
据我所知,此测试已调用handleClickOutside
,但不测试它是否包含在wrapperRef
中的if条件?这不起作用。它的编写方式是在组件内部查找存在于组件外部的类。我想你可以导入一个在视图中的组件,该组件位于组件外部,以测试点击,但感觉应该有更好的方法。您可能希望尝试更改“外部单击”检测逻辑,以处理组件的某个根元素上的onBlur事件:虽然选择的答案是正确的,但我最终将此逻辑卸载到react onclickoutside库-是否问到相反的问题?在单元测试中,如何检测组件外部的点击?我认为只要将目标更改为类似于document.body
的内容就可以完成这个答案。
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"