[英]How to use enzyme and jest to detect change React state
I have a simple React component, when user click the button I want to increase the internal value of state and render in an input button.我有一个简单的 React 组件,当用户单击按钮时,我想增加 state 的内部值并在输入按钮中呈现。
The component works, but I am not able to write a test with enzyme, basically the internal value is not being updated.该组件有效,但我无法用酶编写测试,基本上内部值没有被更新。
I think it is connected with setState being asynch, do you have any idea how to fix my test?我认为这与 setState 异步有关,您知道如何修复我的测试吗?
import * as React from 'react'
type TestCounterProps = Readonly<{
defaultValue: number
onClick: (value: number) => void
}>
export const TestCounter = ({ defaultValue, onClick }: TestCounterProps) => {
const [value, setValue] = React.useState(defaultValue)
const handleIncrease = () => {
setValue(value + 1)
onClick(value)
}
return (
<div>
<input value={value} readOnly />
<button onClick={handleIncrease}>Click to increase</button>
</div>
)
}
Test:测试:
import * as React from 'react'
import { mount } from 'enzyme'
import { TestCounter } from './TestCounter'
describe('TestCounter', () => {
it('should increase counter by 1 when user click button', () => {
const cbClick = jest.fn()
const container = mount(<TestCounter defaultValue={0} onClick={cbClick} />)
const input = container.find('input')
const button = container.find('button')
button.simulate('click')
container.update()
expect(input.props().value).toBe(1) // issue here still 0 <<<
expect(cbClick).toBeCalledWith(1)
})
})
I have a similar example/component, I am going to past it here so could be useful as example:我有一个类似的示例/组件,我将在这里跳过它,因此可以用作示例:
import * as React from 'react'
type CounterProps = Readonly<{
initialCount: number
onClick: (count: number) => void
}>
export default function Counter({ initialCount, onClick }: CounterProps) {
const [count, setCount] = React.useState(initialCount)
const handleIncrement = () => {
setCount((prevState) => {
const newCount = prevState + 1
onClick(newCount)
return newCount
})
}
const handleIncrementWithDelay = () => {
setTimeout(() => {
setCount((prevState) => {
const newCount = prevState + 1
onClick(newCount)
return newCount
})
}, 2000)
}
return (
<div>
Current value: {count}
<button onClick={handleIncrement}>Increment</button>
<button onClick={handleIncrementWithDelay}>Increment with delay</button>
</div>
)
}
The test:考试:
import * as React from 'react'
import { mount, ReactWrapper } from 'enzyme'
import Counter from './Counter'
import { act } from 'react-dom/test-utils'
const COUNT_UPDATE_DELAY_MS = 2000
const waitForComponentToPaint = async (wrapper: ReactWrapper) => {
await act(async () => {
await new Promise((resolve) => setTimeout(resolve, 0))
wrapper.update()
})
}
describe('Counter', () => {
beforeAll(() => {
jest.useFakeTimers()
})
afterAll(() => {
jest.useRealTimers()
})
it('should display initial count', () => {
const cbClick = jest.fn()
const wrapper = mount(<Counter initialCount={5} onClick={cbClick} />)
expect(wrapper.text()).toContain('Current value: 5')
expect(cbClick).not.toBeCalled()
})
it('should increment after "Increment" button is clicked', () => {
const cbClick = jest.fn()
const wrapper = mount(<Counter initialCount={5} onClick={cbClick} />)
wrapper.find('button').at(0).simulate('click')
expect(wrapper.text()).toContain('Current value: 6')
expect(cbClick).toHaveBeenCalledWith(6)
})
it('should increment with delay after "Increment with delay" button is clicked', () => {
const cbClick = jest.fn()
const wrapper = mount(<Counter initialCount={5} onClick={cbClick} />)
waitForComponentToPaint(wrapper)
wrapper.find('button').at(1).simulate('click')
jest.advanceTimersByTime(COUNT_UPDATE_DELAY_MS + 1000)
expect(wrapper.text()).toContain('Current value: 6')
expect(cbClick).toHaveBeenCalledWith(6)
})
})
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.