score:3

Accepted answer

Option 1. Use msw to mock by intercepting requests on the network level.

Option 2. If you don't want to install any package and setup, you can use jest.spyOn(object, 'method').mockResolvedValueOnce() to create a mock resolved/rejected value for axios.get() method.

The below example uses option 2.

App.tsx:

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

interface IJoke {
  category: string;
  joke: string;
}

export const App = () => {
  const [data, setData] = useState<IJoke | undefined>(undefined);
  const [isLoading, setIsLoading] = useState<boolean>(true);

  useEffect(() => {
    axios
      .get('https://v2.jokeapi.dev/joke/Programming?type=single')
      .then((res: AxiosResponse<IJoke>) => {
        setData(res.data);
      })
      .catch((err) => console.log(err))
      .finally(() => setIsLoading(false));
  }, []);

  return (
    <div className="App">
      {isLoading ? (
        <h2>Loading...</h2>
      ) : (
        <div className="info">
          <div className="info__cat">{data?.category ? `category: ${data.category}` : 'bad category'}</div>
          <div className="info__joke">{data?.joke ? `joke: ${data?.joke}` : 'bad data'}</div>
        </div>
      )}
    </div>
  );
};

App.test.tsx:

import { App } from './App';
import axios, { AxiosResponse } from 'axios';
import { act, render, screen } from '@testing-library/react';
import '@testing-library/jest-dom/extend-expect';
import React from 'react';

describe('70450576', () => {
  afterEach(() => {
    jest.restoreAllMocks();
  });
  test('should render category and joke', async () => {
    const mAxiosResponse = {
      data: { category: 'smart', joke: 'sam' },
    } as AxiosResponse;
    jest.spyOn(axios, 'get').mockResolvedValueOnce(mAxiosResponse);
    render(<App />);
    expect(screen.getByText('Loading...')).toBeInTheDocument();
    expect(await screen.findByText('category: smart')).toBeInTheDocument();
    expect(await screen.findByText('joke: sam')).toBeInTheDocument();
  });
});

Test result:

 PASS  examples/70450576/App.test.tsx (8.874 s)
  70450576
    ✓ should render category and joke (43 ms)

----------|---------|----------|---------|---------|-------------------
File      | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
----------|---------|----------|---------|---------|-------------------
All files |   91.67 |    72.22 |      80 |   90.91 |                   
 App.tsx  |   91.67 |    72.22 |      80 |   90.91 | 19                
----------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        9.393 s, estimated 10 s

score:0

You can't access to state and setState internally that with react-testing-library. This is because RTL wants you to test your component as a user would. You should try to reproduce the set of actions that change the state. Use render function of react-testing-libraryfor rendering components, pass the mocked state and setState to this component. Use axiosMock from axios to mock the axios. In this approach you can check the mocked values as a real local states.

import { render } from "react-testing-library";
import axiosMock from "axios";

This link could be helpful:

async-axios-react-testing-library


Related Query

More Query from same tag