I'm trying to test my App using react testing library and jest however the test cannot find the searched "robin" in the document. The BirdSearch.js component uses a redux slice and rtk query which I have set up a custom renderWithProviders as directed by redux's guidlines. I have also used msw to mock the server.
I wanted to test that the searched new bird was being added (it is in the application) but the test keeps saying it can't find it in the document and it's returning "null" instead of an empty string for the numberInput. Additionally it's throwing act() warnings for every single state update in SearchBird.js.
I'm still learning, so any feedback and advice would be appreciated!
App.test.js
import { screen } from "@testing-library/react";
import user from "@testing-library/user-event";
import { setupServer } from "msw/node";
import { rest } from "msw";
import { renderWithProviders } from "../utils/utils-for-tests";
import App from "../App";
const handlers = [
rest.get("http://localhost:3005/birds", (req, res, ctx) => {
return res(
ctx.json([
{ id: "1", name: "blue tit", number: "5" },
{ id: "2", name: "grey heron", number: "1" },
])
);
}),
rest.post("http://localhost:3005/birds", (req, res, ctx) => {
return res(
ctx.json({ id: "3", name: "robin", number: "2" }),
ctx.delay(150)
);
}),
];
const server = setupServer(...handlers);
beforeAll(() => server.listen());
afterEach(() => server.resetHandlers());
afterAll(() => server.close());
test("adds new bird when form is submitted", async () => {
renderWithProviders(<App />);
await screen.findAllByTestId("bird");
const birdInput = screen.getByRole("textbox", { name: /bird/i });
const numberInput = screen.getByRole("spinbutton", {
name: /number/i,
});
const button = screen.getByRole("button", { name: /add/i });
user.click(birdInput);
user.keyboard("robin");
user.click(numberInput);
user.keyboard("2");
user.click(button);
expect(await birdInput).toHaveValue("");
expect(await numberInput).toHaveValue("");
expect(await screen.findByText(/robin/i)).toBeInTheDocument();
expect(await screen.findByText(/2/i)).toBeInTheDocument();
});
** SearchBird.js component:**
import { useDispatch, useSelector } from "react-redux";
import { changeName, changeNumber } from "../store";
import { useAddBirdMutation } from "../store";
function SearchBird() {
const [addBird, results] = useAddBirdMutation();
const dispatch = useDispatch();
const { name, number } = useSelector((state) => {
return {
name: state.search.name,
number: state.search.number,
};
});
const handleSubmit = (event) => {
event.preventDefault();
addBird({ name, number });
dispatch(changeName(""));
dispatch(changeNumber(""));
};
const handleNameChange = (event) => {
dispatch(changeName(event.target.value));
};
const handleNumberChange = (event) => {
dispatch(changeNumber(event.target.value));
};
return (
<div className="bird-search">
<form onSubmit={handleSubmit}>
<div>
<label htmlFor="search">New Bird</label>
<input
id="search"
value={name}
type="text"
onChange={handleNameChange}
/>
</div>
<div>
<label htmlFor="number">Number Seen</label>
<input
id="number"
type="number"
value={number || ""}
onChange={handleNumberChange}
/>
</div>
<button>Add</button>
</form>
</div>
);
}
export default SearchBird;