How to test child component render after api call on react testing library

Viewed 412

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")
    })
})
0 Answers
Related