I have the following Chat box that sends the chat when someone clicks on Enter. This is working as expected in normal life but RTL is disagreeing.
import React, { useState } from "react";
export default function Test() {
const [chatText, setChatText] = useState("");
function sendChat() {
setChatText("");
}
return (
<div>
<textarea
rows={2}
value={chatText}
onChange={(e) => {
setChatText(e.target.value);
}}
onKeyDown={(e) => {
if (e.key === "Enter" && !e.shiftKey) {
e.stopPropagation();
e.preventDefault();
sendChat();
}
}}
aria-label="chat-input"
/>
<button onClick={sendChat}>Send</button>
</div>
);
}
This is working fine. You send a text and the chat box clears when you press Enter
.
The following is the test I have written in RTL, but it is not working.
import React from "react";
import { render, screen, waitFor, act } from "@testing-library/react";
import "@testing-library/jest-dom";
import user from "@testing-library/user-event";
import Test from "./index";
describe("Chat", () => {
test("clear text on Enter", async () => {
render(<Test />);
let textBox = screen.getByLabelText("chat-input");
await act(async () => {
textBox.focus();
expect(textBox).toHaveFocus();
await user.keyboard("hello");
await user.keyboard("{Enter}");
await user.keyboard("hello");
await waitFor(() => {
expect(textBox).toHaveValue("hello");
});
});
});
});
Is the test I’ve written wrong or is something wrong with the code?
RTL is not triggering the clear on Enter part, instead is showing hellohello
2
Answers
Just remove the
act
wrapperDone some digging around and it may have to do something with user.keyboard in general. This might work better instead for you:
Sidenote, I highly recommend explicitly defining your onChange and onKeyDown functions rather than making them anonymous arrow functions. ie:
The reason is that as your app scales, anonymous arrow functions are less performant than declarative ones because they have to be re-initialized every render. This alone has its use cases, but generally because your input is controlled it’s being re-rendered every onChange which means it’s reinitializing those anonymous arrow functions over and over again.