1

I've just set up a mock test of an api call but now am wanting to know how I could actually test this mocked data against my component. My api call will render a random set of information hence the mock. I want to render my Weather component and test if the data from the mocked api is being displayed. At the moment I'm just testing the returning values I've mocked at the start of the test.

Here is my test:

import axios from 'axios';
import { fetchWeatherData } from '../../__mocks__/WeatherMocks';
import { render, screen, waitFor } from '@testing-library/react';
import Weather from '../Weather';
jest.mock('axios');
const mockedAxios = axios as jest.Mocked<typeof axios>;

describe('mock api calls', () => {
  afterEach(() => {
    // jest.resetAllMocks();
  });

  test('mock returned api data', async () => {
    mockedAxios.get.mockResolvedValue({
      data: {
        result: {
          weather: {
            forcast: 'Sunny',
            max: 28,
            min: 17,
            description: 'Clear skys all day with a warm summber breaze ariving in the afternoon',
          },
        },
      },
    });
    const { getByText } = render(<Weather />);
    await waitFor(() => {
      fetchWeatherData();
      expect(
        getByText('Clear skys all day with a warm summber breaze ariving in the afternoon'),
      ).toBeInTheDocument();
      expect(getByText('Sunny')).toBeInTheDocument();
    });
  });
});

and my Weather component:

import axios from 'axios';
import { useEffect, useState } from 'react';
import { IWeather } from '../interfaces/IWeather';
import { MdWbSunny } from 'react-icons/md';
import { IoIosPartlySunny } from 'react-icons/io';
import { BsFillCloudSnowFill } from 'react-icons/bs';
import { Title, Text } from '@mantine/core';

const Weather = () => {
  const [weather, setWeather] = useState<IWeather | null>();

  const fetchWeatherData = async () => {
    const response = await axios.get('http://mock-api-call/weather/get-weather');
    setWeather(response.data.result.weather);
  };

  useEffect(() => {
    fetchWeatherData();
  }, []);

  return (
    <div className="container">
      <>
        <Title order={2}>
          {weather?.forcast === 'Sunny' ? (
            <MdWbSunny />
          ) : weather?.forcast === 'Snowing' ? (
            <BsFillCloudSnowFill />
          ) : (
            <IoIosPartlySunny />
          )}
        </Title>
      </>
      <Text size="xl" data-testid="forcast">
      {weather?.forcast}
      </Text>
      <Text size="lg" data-testid="temp">
      Temp: {`${weather?.min} to ${weather?.max}`}
      </Text>
      <Text size="md" data-testid="description">
     {weather?.description}
     </Text>
    </div>
  );
};

export default Weather;
goatstash
  • 37
  • 4

1 Answers1

0

You need to render your component, then check that the DOM generated by the component, when the API call is mocked, contains what the mock returns :

import { render, waitFor } from '@testing-library/react';
import axios from 'axios';
import { fetchWeatherData } from '../../__mocks__/WeatherMocks';
import Weather from '../Weather';

jest.mock('axios');
const mockedAxios = axios as jest.Mocked<typeof axios>;
    
describe('mock api calls', () => {
  afterEach(() => {
    // jest.resetAllMocks();
  });
    
  test('mock returned api data', async () => {
    mockedAxios.get.mockResolvedValue({
      data: {
        result: {
          weather: {
            forcast: 'Sunny',
            max: 28,
            min: 17,
            description: 'Clear skys all day with a warm summber breaze ariving in the afternoon',
          },
        },
      },
    });
    
    // render the component, get a reference on react-testing-library object
    // see https://testing-library.com/docs/react-testing-library/api#render-result
    const rtl = render(<Weather />);

    // wait for the mocked API call to complete and your component to render
    await waitFor(() => {
      // now you can assert on the Weather's rendered DOM
      expect(rtl.getByText('Clear skys all day with a warm summber breaze ariving in the afternoon').toBeTruthy();
      // you should be able to assert on API mocked call
      // not sure about the syntax
      expect(mockedAxios.get).toHaveBeenCalled();
      // assert on other things
      expect(...
    });
  });
});
Florian Motteau
  • 3,467
  • 1
  • 22
  • 42
  • Ok so in looking into that documentation I have added a data-testid to my Weather component, I'll update that code here. I'm rendering as const { getAllByTestId } = render(); But am confused by the awaitFor() and how and where I should call my fetchWeatherData() function – goatstash Jun 28 '22 at 07:52
  • I suggest you rely more on things a real user would see, use data-testid only if you have no other choice. Also I find it more convenient to get the full RTL object, so I don't have to add functions (like getAllByTestId) each time I want to use another one. – Florian Motteau Jun 28 '22 at 07:56
  • I have updated my code and tests are passing. Could you advise if I am on the right path? – goatstash Jun 28 '22 at 08:09
  • It seems OK to me! Don't forget to console.log(prettyDOM(rtl.container)) if you want to check the generated DOM (prettyDOM is from react-testing-library) – Florian Motteau Jun 28 '22 at 08:12
  • Thank you that's worked great. Do you know how I would go about testing React icons? Or any good documentation? – goatstash Jun 28 '22 at 09:46
  • You could test for specific classes or id, depending on how your icon library works, like eg expect(rtl.container.querySelector('svg#icon-home')).toBeTruthy() – Florian Motteau Jun 28 '22 at 09:55