如何测试 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.:我正在使用 jest、enzyme 和 React 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 给了我当前/新的道具