Batman
Batman

Reputation: 6353

Apollo MockedProvider not returning expected data

I wrote a hook that calls apollo useQuery. It's pretty simple:

useDecider:

import { useState } from 'react';
import { useQuery, gql } from '@apollo/client';

export const GET_DECIDER = gql`
  query GetDecider($name: [String]!) {
    deciders(names: $name) {
      decision
      name
      value
    }
  }
`;

export const useDecider = name => {
  const [enabled, setEnabled] = useState(false);

  useQuery(GET_DECIDER, {
    variables: {
      name
    },
    onCompleted: data => {
      const decision = data?.deciders[0]?.decision;
      setEnabled(decision);
    },

    onError: error => {
      return error;
    }
  });

  return {
    enabled
  };
};

I'm trying to test it now and the MockedProvider is not returning the expected data:

import React from 'react';
import { render, screen } from '@testing-library/react';
import '@testing-library/jest-dom';
import { MockedProvider } from '@apollo/client/testing';
import { useDecider, GET_DECIDER } from './useDecider';

const getMock = (value = false, decider = '') => [
  {
    request: {
      query: GET_DECIDER,
      variables: {
        name: decider
      }
    },
    result: () => {
      console.log('APOLLO RESULT');

      return {
        data: {
          deciders: [
            {
              decision: value,
              name: decider,
              value: 10
            }
          ]
        }
      };
    }
  }
];

const FakeComponent = ({ decider }) => {
  const { enabled } = useDecider(decider);
  return <div>{enabled ? 'isEnabled' : 'isDisabled'}</div>;
};

const WrappedComponent = ({ decider, value }) => (
  <MockedProvider mocks={getMock(value, decider)} addTypename={false}>
    <FakeComponent decider={decider} />
  </MockedProvider>
);

describe('useDecider', () => {
  it('when decider returns true', () => {
    // should return true
    render(<WrappedComponent decider="fake_decider" value={true} />);
    screen.debug();
    const result = screen.getByText('isEnabled');
    expect(result).toBeInTheDocument();
  });
});

Upvotes: 5

Views: 8431

Answers (2)

plus-
plus-

Reputation: 46543

From https://www.apollographql.com/docs/react/development-testing/testing/#testing-the-success-state

To test how your component is rendered after its query completes, you can await a zero-millisecond timeout before performing your checks. This delays the checks until the next "tick" of the event loop, which gives MockedProvider an opportunity to populate the mocked result

try adding before your expect call

  await act(async () => {
    await new Promise((resolve) => setTimeout(resolve, 0));
  });

Upvotes: 5

jack.benson
jack.benson

Reputation: 2363

I simplified your hook implementation and put together a working example:

import { useQuery, gql } from "@apollo/client";

export const GET_DECIDER = gql`
  query GetDecider($name: [String]!) {
    deciders(names: $name) {
      decision
      name
      value
    }
  }
`;

export const useDecider = (name) => {
  const { data } = useQuery(GET_DECIDER, { variables: { name } });
  return { enabled: data?.deciders[0]?.decision || false };
};

Note that in the test I also updated your getBy to an await findBy:

describe("useDecider", () => {
  it("when decider returns true", async () => {
    // should return true
    render(<WrappedComponent decider="fake_decider" value={true} />);
    screen.debug();
    const result = await screen.findByText("isEnabled");
    expect(result).toBeInTheDocument();
  });
});

This is because you need to wait for your API call to complete before the data will be on the page, hence you would not expect the data to be there on the first render.

enter image description here

Upvotes: 3

Related Questions