如何测试 componentDidUpdate()?

Posted

技术标签:

【中文标题】如何测试 componentDidUpdate()?【英文标题】:How to test componentDidUpdate()? 【发布时间】:2019-03-26 16:06:39 【问题描述】:

这是一个示例实现:

export class Person extends Component 
  componentDidMount() 
    const  onLoadProfile, onLoadPolicy, person  = this.props
    onLoadProfile(person.profile.uri)
    onLoadPolicy(person.policy.uri)
  

  componentDidUpdate(prevProps) 
    const  onLoadProfile, onLoadPolicy, person  = this.props
    const prevPerson = prevProps.person.uri
    const curPerson = person.uri

    // If person has changed, update Person component
    if (prevPerson !== curPerson) 
      onLoadProfile(person.profile.uri)
      onLoadPolicy(person.policy.uri)
    
  

componentDidMount() 上,我已经设法像这样对其进行了测试:

describe('<Person />', () => 
  let props
  let mountedPerson
  const mockLoadProfile = jest.fn()
  const mockLoadPolicy = jest.fn()

  const person = () => 
    if (!mountedPerson) 
      mountedPerson = mount(<Person ...props />)
     
    return mountedPerson
  

  beforeEach(() => 
    props = 
      onLoadProfile = mockLoadProfile,
      onLoadPolicy = mockLoadPolicy
    
    mountedPerson = undefined
  )

  afterEach(() => 
    mockLoadProfile.mockClear()
    mockLoadPolicy.mockClear()
  )

  describe('componentDidMount', () => 
    it('loads profile', () => 
      person().instance().componentDidMount()
      expect(mockLoadProfile).toBeCalled()
    )

    it('loads policy', () => 
      person().instance().componentDidMount()
      expect(mockLoadPolicy).toBeCalled()
    )
  )
)

componentDidUpdate() 上,我需要组件尝试render() 两次,以验证它是否应该更新,反之亦然,但我找不到合适的方法来做到这一点。

在 React 中测试 componentDidUpdate() 方法的正确方法是什么?

PS.:我正在使用 jestenzymeReact 15

【问题讨论】:

【参考方案1】:

我使用了不同的方法,但你可以复制这个想法。你需要对 props 进行更改,我使用了 setProps() 函数:

describe('componentDidUpdate', () => 
    it('loads profile', () =>  
        const wrapper = shallow(<Person  ...props />) as any;
        wrapper.setProps( person:  uri: "something_different"  );
        expect(wrapper.instance().props.onLoadProfile).toBeCalled();
    )
)

运行测试后,我可以看到覆盖测试页面中的粉红色在 componentDidUpdate 中消失了

【讨论】:

如果你也碰巧在componentDidMount有同样的调用,你可以做类似expect(wrapper.instance().props.onLoadProfile).toHaveBeenCalledTimes(2);的事情,这取决于有多少道具改变了多少次。 setProps 已被弃用 @albanx setProps 很久以前在 React API 中已弃用。但是enzyme 方法是different one。【参考方案2】:

接受的答案是测试上述情况的最简单方法,但您也可以考虑将componentDidUpdate 逻辑从组件中提取出来,如下所示:

// Component definition
export class Person extends Component 
  componentDidUpdate(prevProps) 
    this.props.handleComponentDidUpdate(prevProps, this.currentProps)
  
  // Rest of component


// Component functions/handlers testing
describe('Person component props', () => 
  describe('handleComponentDidUpdate', () => 
    it('loads profile & policy if person changes', () => 
      const onLoadPolicy = jest.fn()
      const onLoadProfile = jest.fn()
      const prevProps = 
        person:  uri: 'some-person-uri-old' ,
        policy:  uri: 'some-policy-uri' ,
        profile:  uri: 'some-profile-uri' ,
        onLoadPolicy,
        onLoadProfile
      
      const props = 
        person:  uri: 'some-person-uri-new' , // person uri changes
        policy:  uri: 'some-policy-uri' ,
        profile:  uri: 'some-profile-uri' ,
        onLoadPolicy,
        onLoadProfile
      

      handleComponentDidUpdate(prevProps, props)

      expect(onLoadPolicy).toHaveBeenCalled()
      expect(onLoadProfile).toHaveBeenCalled()
    )
  )
)

通过这种方式,组件可以尽可能地笨拙,并且可以将应用逻辑提取到更易于测试的函数/处理程序中。这样,您可以将测试更多地集中在功能上(更容易测试),而不是组件(更难测试)。

至于使用Person 组件,您只需提供所需的道具,包括handleComponentDidUpdate

如果您仍然需要测试组件,您可以进行以下简单测试(注意,在此测试中,与上面的函数/处理程序测试不同,我们不关心应用程序的逻辑,如人员、配置文件、策略等):

// Component testing
describe('<Person/>', () => 
  it('should call handleComponentDidUpdate on prop change', () => 
    const handleComponentDidUpdate = jest.fn()
    const prevProps = 
      someProp: 'some-prop-prev',
      handleComponentDidUpdate
    
    const newprops = 
      someProp: 'some-prop-new',
      handleComponentDidUpdate
    

    const wrapper = shallow(<Person  ...prevProps  />)
    wrapper.setProps(newprops)

    expect(handleComponentDidUpdate).toHaveBeenCalledWith(prevProps, newProps)
  )
)

【讨论】:

以上是关于如何测试 componentDidUpdate()?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用钩子清理 componentDidUpdate 中的异步函数

componentDidUpdate 错误是 React 限制嵌套更新的数量以防止无限循环如何解决此问题

React app,componentDidUpdate - 跳转列表,无限循环

componentDidUpdate prevProps 给了我当前/新的道具

componentDidUpdate 中的 prevState 是 currentState?

mapStateToProps,但未调用componentDidUpdate