javascript - Hur man korrekt testar kontrollerad inmatningskomponent som beror på useState med jest/enzyme


Jag vill testa en kontrollerad komponent med Jest/enzyme.

Jag har en <Input>-komponent som, givet max och min-props, kommer att automatiskt fylla i värdet när change-händelsen utlöses

// Input.tsx
const Input = ({value, onChange, max, min}) => {

  const handleChange = (evt) => {
    const newValue = Number(evt.target.value)

    if(min !== undefined && newValue < min) {
      onChange(min)
      return 
    }

    if(max !== undefined && newValue > max) {
      onChange(max)
      return
    }

    onChange(newValue)
  }

  return (
    <div>
      <label>My input</label>
      <input type="number" value={value} onChange={handleChange} />
    </div>
  )
}

Jag skulle vilja testa komponenten och dess olika change-användningsfall med jest.
Eftersom det är en helt kontrollerad komponent börjar jag skriva följande kod:

    const onChangeSpy = jest.fn()
    const Wrapper = () => {
      const [state] = React.useState(0)
      return (
        <Input
          value={state}
          onChange={onChangeSpy}
          min={0}
          max={50}
        />
      )
    }

    const wrapper = mount(<Wrapper />)
    wrapper
      .find('input')
      .simulate('change', { target: { value: 25 } })
      .simulate('change', { target: { value: 115 } })
    expect(onChangeSpy.mock.calls).toHaveLength(2) // pass

Men jag stöter på ett problem: value-egenskapen hos <Input> uppdateras aldrig eftersom jag aldrig använder React.setState. Mitt exempel är dumt och jag kanske inte behöver det, men i ett mer komplext verkligt scenario skulle jag vilja sätta upp ett tillstånd genom att utlösa händelser och sedan antingen testa mitt state-värde eller mitt onChangeSpy

Hur skulle jag kunna uppnå detta mål? Uppdatera tillståndet och kunna testa det?

Uppdatera

Jag hittade en lösning som fungerar för mig.
Den kombinerar useState och jest.fn()

    const onChangeSpy = jest.fn()
    const Wrapper = () => {
      const [state, setState] = React.useState(0)
      return (
        <Input
          value={state}
          // Call both spy and setState (not clean but working)
          onChange={(val) => {
            onChangeSpy(val)
            setState(val)
          }}
          min={0}
          max={50}
        />
      )
    }

    const wrapper = mount(<Wrapper />)
    wrapper
      .find('input')
      .simulate('change', { target: { value: 25 } })
      .simulate('change', { target: { value: 115 } })
    expect(onChangeSpy.mock.calls).toHaveLength(2) // pass
    expect(wrapper.find('input').props().value).toEqual('115') // pass

Relaterade artiklar