Search code examples
javascriptreactjsunit-testingtestingaxios

Test a component that uses a custom hook that returns data to render elements


I'm currently trying to test a components that uses data provived by a custom hook and check if it renders all the elements in it.

AgentsContainer.js

import React from 'react';
import { useFetch } from '../../hooks/useFetch.js';
import AgentBox from './AgentBox/AgentBox.js';

function AgentsContainer() {
    const { agents, loading, error } = useFetch(
        'https://valorant-api.com/v1/agents'
    );

    return (
        <section>
            <div>
                {error && <div>Error: {error.message}</div>}

                {loading && <div>Loading...</div>}

                {agents?.map(agent => {
                    return (
                        agent.isPlayableCharacter && (
                            <AgentBox key={agent.uuid} data-testid='agent-card' {...agent} />
                        )
                    );
                })}
            </div>
        </section>
    );
}

export default AgentsContainer;

Also, notice that if I delete the question mark that is after the "agents" variable, it returns me an error saying "TypeError: Cannot read properties of undefined (reading 'map')".


useFetch.js

import { useState, useEffect } from 'react';
import axios from 'axios';

export function useFetch(url) {
    const [agents, setAgents] = useState([]);
    const [loading, setLoading] = useState(true);
    const [error, setError] = useState();

    useEffect(() => {
        setLoading(true);

        axios
            .get(url)

            .then(({ data: { data } }) => {
                setAgents(data);
            })

            .catch(error => setError(error))

            .finally(() => setLoading(false));
    }, []);

    return { agents, loading, error };
}

AgentsContainer.test.js

import React from 'react';
import { render, screen } from '@testing-library/react';
import AgentsContainer from './AgentsContainer.js';
import agentsMock from '../../mock/mock.js';
import axios from 'axios';

jest.mock('axios');

test('Renders Agents cards', async () => {
    axios.get.mockResolvedValue({
        data: agentsMock,
        loading: true,
        error: 'Something went wrong D:'
    });

    render(<AgentsContainer />);

    const agentsCards = await screen.findAllByTestId('agent-card');

    expect(agentsCards).toHaveLength(3);
});

Console

Unable to find an element by: [data-testid="agent-card"]

    Ignored nodes: comments, script, style
    <body>
      <div>
        <section>
          <div />
        </section>
      </div>
    </body>

      16 |      render(<AgentsContainer />);
      17 |
    > 18 |      const agentsCards = await screen.findAllByTestId('agent-card');
         |                                       ^
      19 |
      20 |      expect(agentsCards).toHaveLength(3);
      21 | });

The "mockAgents" that I was importing in the test file, is just an array of object, it has inside only 3 objects with multiple data inside, I don't put the mock here because it has so much data. But if you really need it, then just let me know, please :)


Solution

  • Ok I found the problem.

    I just changed the way I was mocking the JSON file and this solved the problem.


    AgentsContainer.test.js

    test('Should render Agents cards', async () => {
        axios.get.mockResolvedValue({
            data: { data: agentsMock }, // Here was the problem.
            loading: true,
            error: 'Something went wrong D:'
        });
    
        render(<AgentsContainer />);
    
        const agentsCards = await screen.findAllByTestId('agent-card');
    
        expect(agentsCards).toHaveLength(3);
    });