Как протестировать componentDidUpdate()?
Это пример реализации:
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()
компонент render()
, чтобы проверить, обновляется ли он, когда должен, и наоборот, но я не смог найти правильный способ сделать это.
Каков правильный подход для тестирования метода componentDidUpdate()
в React?
PS: я использую шутку, энзим и React 15.
Ответы
Ответ 1
Я использую другой подход, но вы можете скопировать идею. Вам нужно внести изменения в реквизиты, я использовал функцию 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();
})
})
Я вижу, что розовая на странице тестирования покрытия исчезает в компонентеDidUpdate после запуска теста
Ответ 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)
})
})