これは実装例です:
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()
を2回試行する必要がありますが、その逆も同様です。
ReactでcomponentDidUpdate()
メソッドをテストする正しいアプローチは何ですか?
PS .: jest、enzymeおよびReact 15を使用しています。
別のアプローチを使用していますが、アイデアをコピーできます。小道具を変更する必要があります。私は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で消えていることがわかります。
受け入れられた答えは、上記のケースをテストする最も簡単な方法ですが、次のようにコンポーネントから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)
})
})