(Apollo client v3) useLazyQuery custom hook testing

I was struggling with a test issue for my custom useLazyQuery hook. My first test is passing but the second one is failing. What am doing wrong for the second test?

Here is the useLazyFetchCoin.tsx

export const useLazyFetchCoin = () => {
  const [coins, setCoins] = useState<ICoin[]>([]);

  useEffect(() => {
    const coins = localStorage.getItem('coinsInfo');
    if (coins) {
      setCoins(JSON.parse(coins));
    }
  }, []);

  const [getData, { loading, error }] = useLazyQuery(GET_COIN_PRICE_QUERY, {
    fetchPolicy: 'network-only',
    notifyOnNetworkStatusChange: true,
    onCompleted: (data) => {
      const hasSameCoin = coins.some((f) => f.id === data.markets[0]?.id);
      if (data.markets.length && !hasSameCoin) {
        const allCoins = [...coins, data.markets[0]];
        setCoins(allCoins);
        localStorage.setItem('coinsInfo', JSON.stringify(allCoins));
      } else if (data.markets.length <= 0) {
        alertNotification('Coin not found !', Notification.ERROR);
      }
      if (hasSameCoin) {
        alertNotification('This coin already exists on your list !', Notification.WARNING);
      }
    }
  });

  return { coins, setCoins, getData, loading, error };
};

Here is the test file

describe('useLazyFetchCoin custom hook', () => {
  const QueryMock = [
    {
      request: {
        query: GET_COIN_PRICE_QUERY,
        variables: { code: 'BNB' }
      },
      result: {
        data: {
          markets: [
            {
              id: 'binance_bnb_eur',
              baseSymbol: 'BNB',
              ticker: {
                lastPrice: '414.90000000'
              }
            }
          ]
        }
      }
    }
  ];

  const QueryWrongCodeMock = [
    {
      request: {
        query: GET_COIN_PRICE_QUERY,
        variables: { code: 'asd' }
      },
      result: {
        data: {
          markets: []
        }
      }
    }
  ];

  function getHookWrapper(mocks: any, code: string) {
    const wrapper = ({ children }: any) => (
      <MockedProvider mocks={mocks} addTypename={false}>
        {children}
      </MockedProvider>
    );
    const { result, waitForNextUpdate } = renderHook(() => useLazyFetchCoin(), {
      wrapper
    });

    expect(typeof result.current.coins).toBe('object');
    expect(result.current.loading).toBeFalsy();
    expect(result.current.error).toBeUndefined();

    // call the lazy function
    act(() => {
      result.current.getData({
        variables: { code }
      });
    });

    return { result, waitForNextUpdate };
  }

  it('should return an array of coins', async () => {
    // Working correctly
    const { result, waitForNextUpdate } = getHookWrapper(QueryMock, 'BNB');

    await waitForNextUpdate();

    expect(result.current.loading).toBeFalsy();
    expect(result.current.coins[0]).toEqual({
      id: 'binance_bnb_eur',
      baseSymbol: 'BNB',
      ticker: {
        lastPrice: '414.90000000'
      }
    });
  });

  it('should return an empty array when requesting a wrong code', async () => {
    // Not working
    const { result, waitForNextUpdate } = getHookWrapper(QueryWrongCodeMock, 'asd');

    await waitForNextUpdate();

    expect(result.current.loading).toBeFalsy();
    expect(result.current.coins[0]).toEqual([]);
  });
});

I got this error message for the second test.

Expected: []
Received: {"baseSymbol": "BNB", "id": "binance_bnb_eur", "ticker": {"lastPrice": "414.90000000"}}

I don’t get it because I’m using different queries for each test.

Also, the second test should receive an empty array when you pass a wrong code such as ‘asd’.

How can write a proper test for it?

I am not familiar with testing, but did you try to console.log to see what is passed to your useLazyFetchCoin?

Because from what I am seeing if I am understanding correctly, in your second test, you don’t seem to even pass the variables to send to the query to fetch the wrong coin.

But like I said, I am not familiar with testing so hope it points something out.