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>
</>
);
};