javascriptreactjsaxiosjestjsreact-test-renderer

TypeError: Cannot destructure property 'data' of '(intermediate value)' as it is undefined - React Testing Library


I'm encountering an issue while testing a React component using React Testing Library. The component involves fetching data using Axios. The tests fail with the following error:

TypeError: Cannot destructure property 'data' of '(intermediate value)' as it is undefined.

      11 |
      12 |         const fetchFollowers = async () => {
    > 13 |             const { data } = await axios.get("https://randomuser.me/api/?results=5")
         |                     ^
      14 |             setFollowers(data.results)
      15 |         }
      16 |

      at fetchFollowers (src/components/FollowersList/FollowersList.js:13:21)

Before I show the Test Suites, I just followed the tutorial of this git repository u can easily clone.

https://github.com/harblaith7/React-Testing-Library-Net-Ninja

So my Test Suite looks like this:

FollowerList.test.js:

import { render, screen, fireEvent } from '@testing-library/react';
import { BrowserRouter } from 'react-router-dom';
import FollowersList from "../FollowersList";

const MockFollowersList = () => {
    return (
        <BrowserRouter>
            <FollowersList />
        </BrowserRouter>
    )
}

describe("FollowersList", () => {

    beforeEach(() => {
        // console.log("RUNS BEFORE EACH TEST")
        jest.mock("../../../__mocks__/axios")
    })

    // beforeAll(() => {
    //     console.log("RUNS ONCE BEFORE ALL TESTS")
    // })

    // afterEach(() => {
    //     console.log("RUNS AFTER EACH TEST")
    // })

    // afterAll(() => {
    //     console.log("RUNS ONCE AFTER ALL TESTS")
    // })

    it('should fetch and render input element', async () => {
        render(
            <MockFollowersList />
        );
        const followerDivElement = await screen.findByTestId(`follower-item-0`)
        expect(followerDivElement).toBeInTheDocument();
    });
    
    it('should fetch and render input element2', async () => {
        render(
            <MockFollowersList />
        );
    
        const followerDivElement = await screen.findByTestId(`follower-item-0`)
        expect(followerDivElement).toBeInTheDocument();
    });
})

axios.js in mocks:

const mockResponse = {
    data: {
        results: [
            {
                name: {
                    first: "Laith",
                    last: "Harb"
                },
                picture: {
                    large: "https://randomuser.me/api/portraits/men/59.jpg"
                },
                login: {
                    username: "ThePhonyGOAT"
                }
            }
        ]
    }
}


export default {
    get: jest.fn().mockResolvedValue(mockResponse)
}

I'm working behind a proxy, but I don't think this is the problem here. Would be grateful for advice!

Greetings


Solution

  • The mocked version of axios in __mocks__/axios.js is being read but the problem is that react-scripts is adding the jest configuration resetMocks: true when runing the tests.

    This effectively resets all your mock implementations, removing all your fake implementations prior to executing tests.

    You can override this configuration in package.json:

    "jest": {
        "resetMocks": false
    }
    

    Another solution, if you don't want to change this configuration, would be to mock the implementation in your test:

    import axios from 'axios';
    [...]
    
    it('should fetch and render input element', async () => {
        axios.get = jest.fn().mockResolvedValue(<your_mock_response>);
    
        render(
            <MockFollowersList />
        );
        const followerDivElement = await screen.findByTestId(`follower-item-0`)
        expect(followerDivElement).toBeInTheDocument();
    });
    

    Since this mock is executed after the reset performed by the jest configuration, it allows you to add the fake implementation.