use-immer icon indicating copy to clipboard operation
use-immer copied to clipboard

Passing event directly results in strange values inside state change function while running tests

Open stefan-fast opened this issue 2 years ago • 4 comments
trafficstars

I came across an issue when writing tests with testing library where text typed into an text area becomes completly messed up when directly passing the event into setter function created by useImmer:

export default function App() {
  const [test, setTest] = useImmer({ text: "" });

  return (
    <div className="App">
      <Form.Group controlId="formDescription">
        <Form.Label>{"TestInput"}</Form.Label>
        <Form.Control
          as="textarea"
          type="text"
          placeholder={"Enter input"}
          value={test.text}
          onChange={(event) => {
            const value = event.target.value;
            setTest((draft) => {
              draft.text = event.target.value; // wrong value for event.target.value inside test; gets really messed up
              //draft.text = value; // works fine
            });
          }}
        />
      </Form.Group>
    </div>
  );
}

On the other hand, when using useState the following works just fine:

export default function App() {
  const [foo, setFoo] = useState({ text: "" });

  return (
    <div className="App">
      <Form.Group controlId="formDescription">
        <Form.Label>{"TestInput"}</Form.Label>
        <Form.Control
          as="textarea"
          type="text"
          placeholder={"Enter input"}
          value={test.text}
          onChange={(event) => {
            setFoo((prevState) => {
              const newState = { ...prevState };
              newState.text = event.target.value; // works fine
              return newState;
            });
          }}
        />
      </Form.Group>
    </div>
  );

The test:

import { render } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import App from "./App";
import { screen } from "@testing-library/dom";

test("fill in", async () => {
  const user = userEvent.setup({ document });
  render(<App />);

  const description = "This is a test description.";

  await user.type(
    screen.getByRole("textbox", { name: "TestInput" }),
    description
  );
  expect(screen.getByText(description)).not.toBeNull();
});

Instead of This is a test description. the text area somehow contains Ti sats ecito. when running the test.

Using the text area manually in a browser seems to always work fine though. I am not sure if there can anything be done here and if this only happens in combination with testing library.

CSB: https://codesandbox.io/s/billowing-dew-0mdbjx

stefan-fast avatar Jan 26 '23 13:01 stefan-fast

@stefan-fast were you able to find any root cause for this?

yashug avatar Apr 13 '23 10:04 yashug

I experience the same issue, any plan to solve this issue?

ofersinnovid avatar Feb 01 '24 13:02 ofersinnovid

I have the same issue. @stefan-fast thank you for solution!

aushev-vadim avatar Apr 17 '24 18:04 aushev-vadim

@stefan-fast mind sharing what the solution was?

wondering if it could be a similar issue as https://github.com/downshift-js/downshift/issues/1597: multiple relevant event handlers being triggered simultaneously.

mweststrate avatar Jun 10 '24 20:06 mweststrate