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.
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?
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)
})
})
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.