Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React Testing Library - fireEvent doesn't change input value

🙂 I'm learning testing in React, but fireEvent doesn't change value on my input. Unfotunanently, I don't know why?

I'm rendering BuyPlace component. In this component I have form which has Input components (these components are simply label with input and I'm passing props to this compoments on form).

On screen.debug() I can see that my components is rendered corretly with this form and all of these inputs.

Also, my input is catched corretly in my test, I checked this.

This is my test:

test("should change input value", async () => {
render(
<HashRouter>
<UserContext.Provider value={{ user: true }}>
<BuyPlace />
</UserContext.Provider>
</HashRouter>
);
const nameInputEl = screen.getByPlaceholderText("Podaj własną nazwę");
fireEvent.change(nameInputEl, {
target: { value: "Michał" },
});
await waitFor(() => {
expect(nameInputEl.value).toBe("Michał");
});
});

Test is not passing. Ofcourse my app is working corretly, but on test it doesn't work.

This is handleInputChange on my component:

const handleInputChange = (e: React.ChangeEvent<HTMLInputElement> | React.ChangeEvent<HTMLTextAreaElement>) => {
setInputValues((prevValues) => {
return {
...prevValues,
[e.target.name]: e.target.value,
}
});
};

Every solution which I found is not working... My value on input is always empty string. Can someone help me with this? I want to learn to write good tests, but I don't know where is the problem.

EDIT I saw something interesting on screen.debug().

My input on test is rendered without onchange attribute, this is normal on tests? Check this out:

                   <input
                    id="name"
                    name="name"
                    placeholder="Podaj własną nazwę"
                    type="text"
                    value=""
                  />

On my rendered parent component I have handleInputChange and this function is passing to the Input components. On live everything is working but on test is not... Maybe this is why fireEvent is not working?

But why on test my input doesn't have onchange attribute?

EDIT 2 SOLUTION

Wow, after 3 days I found where the problem was!

The problem was in setState function which changes values. I had:

const myValues = (object with values);

setState((previousValues) => {
...previousValues,
[e.target.name]: e.target.value
})

But after changing on this:

setState({
...myValues,
[e.target.name]: e.target.value
})

My test is passing. So I can't use previousState callback on setState - this is why my test was incorrect. But... why? This is a question for me!

like image 827
MaaagicianPL Avatar asked Mar 27 '26 11:03

MaaagicianPL


2 Answers

It's recommended to use userEvent over fireEvent. Especially if you are using Material-UI, as there's been issues with using fireEvent rather userEvent

Note by testing library documentation

Most projects have a few use cases for fireEvent, but the majority of the time you should probably use @testing-library/user-event.

Instead of fireEvent.change you would do something as such

userEvent.type(nameInputEl, 'Michal');
like image 66
Jonathan Southern Avatar answered Mar 29 '26 23:03

Jonathan Southern


Hope you are aware this does not return anything yet

this piece is from you question;

setState((previousValues) => {
...previousValues,
[e.target.name]: e.target.value
})

you need to wrap it like below;

setState((previousValues) => ({
...previousValues,
[e.target.name]: e.target.value
}))
like image 41
ilkerkaran Avatar answered Mar 30 '26 01:03

ilkerkaran



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!