jest and testing-library controlled input

Viewed 21

I'm trying to apply a unit test in my custom input component
If I pass the value prop in the <Input /> in the render function, the test fails.
Does anyone know the reason?
In controlled components like this input, what we can test to have valid unit tests?
Thanks

Input.tsx

import React, {ChangeEvent, FunctionComponent} from 'react';
import styles from './Input.module.css'

export interface InputProps {
    type?: string
    disabled?: boolean
    value?: string
    onChange?: (value: string) => void
}

const Input: FunctionComponent<InputProps> = ({
    type= 'text',
    disabled = false,
    value,
    onChange,
}) => {
    
    const handleOnChange = (e: ChangeEvent<HTMLInputElement>) => {
        const value = e.currentTarget.value
        if (onChange) {
            onChange(value)
        }
    }
    
    return (
        <div className={styles.inputWrapper}>
            <input
                className={styles.input}
                type={type}
                disabled={disabled}
                value={value}
                onChange={handleOnChange}
            />
        </div>
    );
}

export default Input;

Input.test.tsx

// PASS WITHOUT ANY ERRORS
it('should has the new value', async () => {
    const user = userEvent.setup()
    const onChangeMock = jest.fn();
    const { getByRole } = render(<Input onChange={onChangeMock} />)
    const input = getByRole('textbox')
    expect(input).toHaveValue('')
    await user.type(input, 'new input value')
    expect(input).toHaveValue('new input value')
})
 
// FAILS
it('should has the new value', async () => {
    const user = userEvent.setup()
    const onChangeMock = jest.fn();
    const { getByRole } = render(<Input value="" onChange={onChangeMock} />)
    const input = getByRole('textbox')
    expect(input).toHaveValue('')
    await user.type(input, 'new input value')
    expect(input).toHaveValue('new input value')
})
1 Answers

You can use rerender function that is returned from render.

With this, you send new value into your component, input has a new value and then you can assert for that value in the input.

In your case, your test needs to have also checking if onChange method is called when you do userEvent.type() or if that does not work you can use fireEvent.change(input...).

it('should has the new value', async () => {
  const user = userEvent.setup();
  const onChangeMock = jest.fn();
  const { getByRole, rerender } = render(<Input value="" onChange={onChangeMock} />);

  const input = getByRole('textbox');
  expect(input).toHaveValue('');

  rerender(<Input value="new input value" onChange={onChangeMock} />);

  expect(input).toHaveValue('new input value');
});
Related