Closed
Description
I am trying to figure out why following line of code would always work no matter what number I put.
waitForElement(() => expect(onChange).toHaveBeenCalledTimes(3));
I am trying to test that input has been called x number of times however input is controlled within the component itself. No matter what number provide it will always pass the test.
complete-react-testing.zip
With fireEvent, I expect it to be
waitForElement(() => expect(onChange).toHaveBeenCalledTimes(1));
With userEvent, I expect it to be
waitForElement(() => expect(onChange).toHaveBeenCalledTimes(5));
Here is my Component:
import React, { useState } from "react";
import axios from "axios";
import "./Pokemon.css";
const getPokemonByColor = (color) =>
`https://pokeapi.co/api/v2/pokemon-color/${color}/`;
const Pokemon = () => {
const [pokemons, setPokemons] = useState([]);
const [error, setError] = useState(null);
const [search, setSearch] = useState("");
const handleFetch = async (event) => {
event.preventDefault();
let result;
try {
result = await axios.get(getPokemonByColor(search));
setPokemons(result.data.pokemon_species.slice(0, 5));
} catch (error) {
setError(error);
}
};
const handleChange = (event) => {
setSearch(event.target.value);
};
return (
<div>
{error && <span>Something went wrong ...</span>}
<form onSubmit={handleFetch}>
<div>
<input
id="search"
type="text"
value={search}
onChange={handleChange}
placeholder="Pokemon Color"
className="search"
/>
</div>
<button className="search-button" type="submit" data-testid="button">
Fetch Pokemons
</button>
</form>
<ul className="pokemons">
{pokemons.length > 0 &&
pokemons.map((pokemon) => (
<li className="pokemon-item" key={pokemon.name}>
<a className="pokemon-link" href={pokemon.url}>
{pokemon.name}
</a>
</li>
))}
</ul>
</div>
);
};
export default Pokemon;
Here are my tests:
import React from "react";
import axios from "axios";
import {
render,
screen,
waitForElement,
fireEvent,
cleanup,
} from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import Pokemon from "./Pokemon";
jest.mock("axios");
afterEach(cleanup);
describe("search input tests", () => {
test("calls the onChange callback handler", () => {
const onChange = jest.fn();
const { getByRole } = render(<Pokemon />);
const input = getByRole("textbox");
expect(input.value).toBe("");
fireEvent.change(input, {
target: { value: "black" },
});
expect(input.value).toBe("black");
waitForElement(() => expect(onChange).toHaveBeenCalledTimes(3));
});
test("calls the onChange callback handler", async () => {
const onChange = jest.fn();
const { getByRole } = render(<Pokemon />);
const input = getByRole("textbox");
expect(input.value).toBe("");
await userEvent.type(input, {
target: { value: "black" },
});
waitForElement(() => expect(input.value).toBe("black"));
waitForElement(() => expect(onChange).toHaveBeenCalledTimes(7));
});
});
describe("api tests", () => {
test("fetches pokemons from an API and display them", async () => {
const pokemons = [
{
name: "snorlax",
url: "https://pokeapi.co/api/v2/pokemon-species/143/",
},
{
name: "murkrow",
url: "https://pokeapi.co/api/v2/pokemon-species/198/",
},
{
name: "unown",
url: "https://pokeapi.co/api/v2/pokemon-species/201/",
},
{
name: "sneasel",
url: "https://pokeapi.co/api/v2/pokemon-species/215/",
},
];
axios.get.mockImplementationOnce(() =>
Promise.resolve({ data: { pokemon_species: pokemons } })
);
render(<Pokemon />);
// screen.debug();
userEvent.click(screen.getByRole("button"));
expect(await screen.findAllByRole("listitem")).toHaveLength(4);
// screen.debug();
});
test("fetches stories from an API and fails", async () => {
axios.get.mockImplementationOnce(() => Promise.reject(new Error()));
render(<Pokemon />);
userEvent.click(screen.getByRole("button"));
const message = await screen.findByText(/Something went wrong/);
expect(message).toBeInTheDocument();
});
});
Metadata
Metadata
Assignees
Labels
No labels