React: Use Jest and React Testing Library to Test a Component and Mock the Axios get await Call

4/26/2021 11:42:42 PM

The code below creates a simple UserAvatar component that takes a user_id, makes an ajax call, and shows the resulting url. The test case mocks the Axios get call.


Component to test: UserAvatar.js

import React, { Component } from 'react';
import axios from "axios";

export default class UserAvatar extends Component
{
    constructor(props)
    {
        super(props);

        this.state = {
            url: "",
            loading: true
        };
    }

    componentDidMount()
    {        
        this.get_avatar();
    }

    
    get_avatar = async () =>
    {        
        console.log("get_avatar");

        if (this.props.user_id)
        {
            let api_url = "https://api.example/my-great-endpoint/users/profile/" + this.props.user_id + ".json";
            console.log("api_url", api_url);

            let self = this;            
            axios.get(api_url)
                .then(function (response)
                {                    
                    console.log("axios response", response);
                    
                    if (response && response.data.avatar_url)
                    {                        
                        self.setState({
                            url: response.data.avatar_url,
                            loading: false
                        });
                    }
                    else
                    {                        
                        self.setState({
                            loading: false
                        });
                    }
                })
                .catch(function (error)
                {
                    // handle error
                    console.log(error);

                    self.setState({                        
                        loading: false
                    });
                })
                .then(function ()
                {
                    // always executed
                });
        }
    }

    render()
    {
        console.log("render", this.state);

        if (this.state.loading)
        {
            return "";
        }

        if (!this.state.url)
        {
            return "";
        }

        
        return (
            <img alt="avatar" className="avatar" url={this.state.url} />
        )
    }
}

Test class: UserAvatar.test.js

import React from "react";
import axios from 'axios';
import { screen, render, waitFor } from "@testing-library/react";
import UserAvatar from "./UserAvatar";

jest.mock('axios');


it("should display user avatar", async () =>
{
    const mock_api_response = {
        data: {
            avatar_url: "https://cdn.example.com/some-made-up-path/avatars/1.jpg"
        }
    };
    axios.get.mockResolvedValue(mock_api_response);
    //axios.get.mockImplementation(() => Promise.resolve(mock_api_response))


    render(<UserAvatar user_id={1} />);
    //output initial html
    //screen.debug();

    //wait for axios call to complete and check for alt text in the final html
    //need to include the alt text since react testing library only wants to check for "things" users can see
    //if this fails to find the element, error is thrown
    //could also return the result and check for not null
    //const found_avatar = await waitFor(() => screen.getByAltText("avatar"));
    await waitFor(() => screen.getByAltText("avatar"));
    
    //output final html
    //screen.debug();


    //expect(found_avatar).not.toBeNull();
    expect(true).toBeTruthy();
});