我如何向下钻取子组件并模拟点击。

//父组件

_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')

希望这可以帮助!

09-10 10:33
查看更多