4

I cannot find any articles or documentation on how to test multiple synchronous fetch requests in a useEffect. I am fetching data and then before second fetch starts I set a "loading data" tooltip on a button. Once the second fetch is complete the tooltip turns either into "cannot use this feature" or there is no tooltip at all. I am not sure how to step into those states of the test where jest is before or after a fetch call.

The problem is my test doesn't see the "loading data" tooltip to begin with even though it appears when I test it manually. I'm having difficulties understand when to await for the second call and when it actually happens and when it finishes...

Just to clarify getAccountInfo is a fetch request function which returns an object with accountInfo property.

The error:

TestingLibraryElementError: Unable to find an element with the text: /loading data/. This could be because the text is broken up by multiple elements. In this case, you can provide a function for your text matcher to make your matcher more flexible.

Here's my test

import React from 'react';
import * as utils from '../utils';
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import fetch from 'jest-fetch-mock';

const getAccountInfoSpy = jest.spyOn(utils, 'getAccountInfo');
const testId = 'ABCDEF';

describe('AccountInfo', () => {
  beforeAll(() => fetch.enableMocks());
  afterAll(() => fetch.disableMocks());
  beforeEach(() => jest.clearAllMocks());
  
  it('displays "loading data" tooltip on hover' () => {
    fetch.mockResponse(
      JSON.stringify({
        orgId: testId,
        name: 'Adam',
      }),
      { status: 200 },
    );

    const { getByRole, findByText } = render(
      <AccountInfo />
    );

    const importButton = getByRole('button', { name: 'Import' });
    fireEvent.mouseEnter(importButton);

    expect(await findByText(/loading data/)).toBeInTheDocument();

    await waitFor(() =>
      expect(getAccountInfoSpy).toHaveBeenCalledWith(testId),
    );

    expect(findByText(/cannot use this feature/).toBeInTheDocument();
  });
});

Here's the AccountInfo component

const AccountInfo = () => {
  const { customerId } = useCustomerContext();
  const [isLoading, setIsLoading] = useState(true);
  const [accountInfo, setAccountInfo] = useState({});
  const [isAccountInfoLoading, setIsAccountInfoLoading] = useState(false);
  
  useEffect(() => {
    const fetchAccountData = async () => {
      const rawRes = await fetch(`/customer/${customerId}`);
      const res = await rawRes.json();
      setIsLoading(false);
      
      if (res.orgId) {
        setIsAccountInfoLoading(true);
        try {
          const accountInfoRes = await getAccountInfo(res.orgId);
          setAccountInfo(accountInfoRes.accountInfo);
        } catch (error) {
          console.log('error', error);
        } finally {
          setIsAccountInfoLoading(false);
        }
      }
    }
    fetchAccountData();
  });
  
  function renderTooltip() {
    if (isAccountInfoLoading) {
      return 'loading data';
    } else {
      return !accountInfo.active
        ? 'cannot use this feature'
        : undefined;
    }
  }
  
  return (
    <>
      <Button tooltip={renderTooltip()}>
        Import
      </Button>
    </>
  );
};
LazioTibijczyk
  • 1,701
  • 21
  • 48

0 Answers0