I want to test the child component render after click a display detail button. When click the button, it will call api getPokemonDetail to get the Pokemon detail and then change the PokemonDetail state.
The app is running well. But on my unit test, I can only get the Loading text after button click. I used axios-mock-adapter to mock axios request. If I disable the axios mock, it's running correct. Looks like the axios mock is not working after button click. How should I fix it? The below is my code.
Parent Component:
const getPokemonDetail = async (pokemonName) => {
const queryName = pokemonName ?? "ditto"
try {
const result = await axios.get(`https://pokeapi.co/api/v2/pokemon/${queryName}`)
console.log(result.data)
const { name, id, weight } = result.data
return Promise.resolve({ name, id, weight })
} catch (error) {
return undefined
}
}
const ParentComponent = (props) => {
const { pokemonName } = props
const [pokemonDetail, setPokemonDetail] = useState({
detail: null,
loading: true,
})
const retrieveDisplayStatus = async () => {
const getPokemonDetailResult = await getPokemonDetail(pokemonName)
if (getPokemonDetailResult) {
setPokemonDetail({
detail: getPokemonDetailResult,
loading: false,
})
}
}
const { showDetails, toggleDetails } = useToggleDetails(retrieveDisplayStatus)
return (
<>
<h2>Display Pokemon Detail</h2>
<button onClick={toggleDetails}>Display Detail</button>
<>
{showDetails ? (
<>{
pokemonDetail.loading ?
<div>Loading...</div> :
<ChildComponent pokemonDetail={pokemonDetail.detail} />
}</>
) : null}
</>
</>
)
}
Child Component:
const ChildComponent = (props) => {
const { pokemonDetail } = props
const { id, name, weight } = pokemonDetail
return (
<>
<div>ChildComponent</div>
<div data-testid="testId">id: {id}</div>
<div>name: {name}</div>
<div>weight: {weight}</div>
</>
)
}
export default ChildComponent
On the Parent component test:
import { render, screen } from "@testing-library/react"
import ParentComponent from "../ParentComponent"
import userEvent from "@testing-library/user-event"
import axios from "axios"
import MockAdapter from "axios-mock-adapter"
describe("test", () => {
let mock
beforeAll(() => {
mock = new MockAdapter(axios)
})
afterEach(() => {
mock.reset()
})
test("Render child component after api call", async () => {
render(<ParentComponent />)
const heading = screen.getByText("Display Pokemon Detail")
expect(heading).toBeInTheDocument()
const toggleButton = screen.getByRole("button", { name: /display/i })
expect(toggleButton).toBeInTheDocument()
userEvent.click(toggleButton)
const loadingText = await screen.findByText(new RegExp("Loading", "i"))
expect(loadingText).toBeInTheDocument()
// the below is not working, looks like the axios mock not working
mock.onGet(`https://pokeapi.co/api/v2/pokemon/ditto`).reply(200, { name: "ditto", id: 132, weight: 40 })
const childHeading = await screen.findByText("ChildComponent")
expect(childHeading).toBeInTheDocument()
const id = await screen.findByTestId("testId")
expect(id).toHaveTextContent("132")
})
})