我如何向下钻取子组件并模拟点击。
//父组件
_handleChildClick = () => {
this.setState({
enabled: false
})
}
<div>
<Child
onChildClick={this._handleChildClick}
/>
</div>
//子组件
<div>
<button className="toggle"
onClick={props.onChildClick}
></button>
</div>
//test.js
const renderedComponent = shallow(<Parent />)
console.log(renderedComponent.debug()) // i am not able to drill down
// renderedComponent.find('toggle').simulate('click') wont work !!!
如果我使用mount因为我的组件最初是一些api调用,它将具有loader组件
即使我尝试了以下片段,父母甚至都没有来
it('test with mount', async () => {
const a = await mount(<Parent />)
console.log(a.debug()) // showing the loader only
})
我该如何解决这个问题,任何帮助表示赞赏:)
// App.js
import React, {Component, Fragment} from 'react'
import Child from './child'
class App extends Component{
state = {
data: null,
enable: false
}
componentDidMount(){
this.getData()
}
getData = async () => {
const response = await fetch('http://www.example.com');
const data = await response.json();
this.setState({
data
})
}
_handleChildClick = () => {
this.setState({
enable: true
})
}
render(){
const {data, enable} = this.state
if(!data){
return (
<div>
Loading
</div>
)
}else{
<Fragment>
<Child
handleChildClick={this._handleChildClick}
/>
</Fragment>
}
}
}
export default App
import React from 'react';
const child = () => {
return(
<div>
<button
className="toggle"
onClick={props.handleChildClick}
>
Toggle
</button>
</div>
)
}
export default child
// App.test.js
import React from 'react';
import {enzyme} from 'enzyme';
import App from './App';
describe("App test cases", () => {
it('should trigger _handleChildClick', async () => {
window.fetch = jest.fn().mockImplementation(() => ({
status: 200,
json: () => new Promise((resolve, reject) => {
resolve(
{
name: "some data"
}
)
})
}))
const mountWrapper = await mount(<App />)
mountWrapper.update()
console.log("mountWrapper", mountWrapper.debug()) // showing the loader one
setTimeout(() => {
console.log("mountWrapper", mountWrapper.debug()) // nothing showing
// expect(mountWrapper.find('.toggle').length).toEqual(1)
},0)
})
})
最佳答案
浅渲染(用于当前测试)仅深一层。这意味着您将无法使用浅层渲染器模拟render()
方法或子组件的行为。有关更多信息,请参见文档here。
如果要对该代码示例进行有效的单元测试,则不应尝试模拟其子行为。相反,您应该分别测试<Parent />
和<Child />
。这样可以防止Child
组件中的更改影响Parent
组件中的测试结果,反之亦然。这几乎就是浅层渲染器存在的全部原因!从文档中:
浅呈现对于约束自己以一个单元测试组件,以及确保测试不会间接断言子组件的行为很有用。
我会为子组件编写此测试,并为其onChildClick属性使用模拟功能:
test('triggers its onChildClick prop when clicked', () => {
const mock = jest.fn()
const wrapper = shallow(<Child onChildClick={mock} />)
wrapper.find('.toggle').simulate('click')
expect(mock).toHaveBeenCalledTimes(1)
})
我将为父级编写此测试,并传入数据以确保呈现子级:
test('sets its state when its child is clicked', (done) => {
const wrapper = shallow(<App data={{ test: 'test' }}/>)
expect(wrapper.state('enable')).toBe(false)
wrapper.find('Child').props().onChildClick()
expect(wrapper.state('enable')).toBe(true)
})
刚刚尝试了这两个测试,它们都可以正常工作。我在这里测试组件的全部功能,除了将过程分为多个单元。单击按钮时,子级将触发其onChildClick道具,并且在父级中触发该道具将
enable
的状态设置为true
。完整的DOM渲染(使用
mount(<Parent />)
)更加混乱,我只真正发现它对于测试使用DOM api的组件很有用(无论如何,这在React中不会发生太多)。再次查看documentation以获得更完整的说明!如果您想测试应用程序的大规模功能(看起来像您一样),建议您使用像Cypress这样的端到端测试框架。
另外,最后一件事...您正在使用
wrapper.find('toggle')
,但是如果要通过其className
查找节点,则需要执行wrapper.find('.toggle')
。希望这可以帮助!