简体   繁体   中英

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.

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM