Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Apollo Mocked Provider Warning on refetch #8900

Open
trevordammon opened this issue Oct 6, 2021 · 15 comments
Open

Apollo Mocked Provider Warning on refetch #8900

trevordammon opened this issue Oct 6, 2021 · 15 comments

Comments

@trevordammon
Copy link

I have seen a few other posts regarding fetching and MockedProvider. However I haven't seen anyone that is getting the same warning as me.

My code executes a mutation which that uses a refetch to query for data.

 const [add_emergency_contact] = useMutation(ADD_EMERGENCY_CONTACT, {
    refetchQueries: [GET_PERSON_QUERY],
 });

The code functions properly.

I am writing tests which mock add_emergency_contact and therefore invoke the refetch.

export function renderWithRouterMatch(
  ui,
  {
    path = '/',
    route = '/',
    history = createMemoryHistory({ initialEntries: [route] }),
  } = {},
) {
  return {
    ...render(
      <MockedProvider
        mocks={[getPerson, add_emergency_contact, update_emergency_contact]}
        addTypename={false}>
        <PeopleContextProvider
          value={{ personSuccessAlert, setPersonSuccessAlert }}>
          <Router history={history}>
            <Route path={path} component={ui} />
          </Router>
        </PeopleContextProvider>
      </MockedProvider>,
    ),
  };
}

describe('emergency contact tests', () => {
  afterEach(cleanup);
  test('add emergency contact', async () => {
    const {
      getByText,
      queryByText,
      getAllByTestId,
      getByTestId,
    } = renderWithRouterMatch(PersonRecord, {
      route: 'people/6d6ed1f4-8294-44de-9855-2999bdf9e3a7',
      path: 'people/:slug',
    });
    expect(getByText('Loading...')).toBeInTheDocument();
    // This gives Apollo time to make the request and get mock data
    await act(
      async () =>
        new Promise((resolve) => {
          setTimeout(resolve, 0);
        }),
      await waitForElementToBeRemoved(() => queryByText('Loading...')),
    );
    const addButton = getByText('Add +');

    fireEvent.click(addButton);
    const inputList = getAllByTestId('form-input');
    const firstNameInput = inputList[0];
    const lastNameInput = inputList[1];
    const primaryPhoneInput = inputList[2];
    const alternatePhoneInput = inputList[3];
    const emailInput = inputList[4];

    const relationship = getByTestId('selector-container');
    fireEvent.click(relationship);
    fireEvent.click(getByText('PARENT'));

    fireEvent.change(firstNameInput, { target: { value: 'Joe' } });
    fireEvent.change(lastNameInput, { target: { value: 'Smith' } });
    fireEvent.change(primaryPhoneInput, { target: { value: '6666666666' } });
    fireEvent.change(alternatePhoneInput, {
      target: { value: '6666666667' },
    });
    fireEvent.change(emailInput, {
      target: { value: '[email protected]' },
    });

    const submitButton = getByText('Submit');
    fireEvent.click(submitButton);

    const addEmergencyContactMutationMock = add_emergency_contact.newData;
    expect(addEmergencyContactMutationMock).toHaveBeenCalled();
  });
});

I pass in the mocks that I will be using (getPerson is the mocked query that should be called in the refetch).

My MockedProvider uses newData rather than result. I've tried using both and I haven't noticed a difference.

export const getPerson = {
  request: {
    query: GET_PERSON_QUERY,
    variables: { id_: '6d6ed1f4-8294-44de-9855-2999bdf9e3a7' },
  },
  newData: jest.fn(() => ({
    data: {
      people: [
        {
          person_id: {
            id_: '6d6ed1f4-8294-44de-9855-2999bdf9e3a7',
          },
          name: {
            first_name: 'Kitty',
            last_name: 'Forman',
            middle_name: 'Ann',
          },
          preferred_name: {
            first_name: 'Kit',
            middle_name: 'A',
            last_name: 'For',
          },
          emergency_contacts: [],
        },
      ],
    },
  })),
  // result: () => {
  //   return {
  //     data: {
  //       people: [
  //         {
  //           person_id: {
  //             id_: '6d6ed1f4-8294-44de-9855-2999bdf9e3a7',
  //           },
  //           name: {
  //             first_name: 'Kitty',
  //             last_name: 'Forman',
  //             middle_name: 'Ann',
  //           },
  //           preferred_name: {
  //             first_name: 'Kit',
  //             middle_name: 'A',
  //             last_name: 'For',
  //           },
  //           emergency_contacts: [],
  //         },
  //       ],
  //     },
  //   };
  // },
};

export const add_emergency_contact = {
  request: {
    query: ADD_EMERGENCY_CONTACT,
    variables: {
      id_: '6d6ed1f4-8294-44de-9855-2999bdf9e3a7',
      input: {
        name: {
          first_name: 'Joe',
          last_name: 'Smith',
        },
        relationship_code: 'PARENT',
        contact_info: {
          primary_phone: '6666666666',
          alternate_phone: '6666666667',
          email: '[email protected]',
        },
      },
    },
  },
  newData: jest.fn(() => ({
    data: {
      add_emergency_contact: {
        status: 201,
        error: 'none',
        person_id: {
          id_: '1',
        },
        emergency_contact: {
          emergency_contact_id: {
            id_: '6d6ed1f4-8294-44de-9855-2999bdf9e3a7',
          },
          name: {
            first_name: 'Joe',
            last_name: 'Smith',
          },
          relationship: {
            code: 'PARENT',
            display: null,
            description: null,
          },
          contact_info: {
            primary_phone: '6666666666',
            alternate_phone: '6666666667',
            email: '[email protected]',
            address: {
              line_1: null,
              line_2: null,
              city: null,
              state: null,
              zip_code: null,
            },
          },
        },
      },
    },
  })),
  // result: () => {
  //   return {
  //     data: {
  //       add_emergency_contact: {
  //         status: 201,
  //         error: 'none',
  //         person_id: {
  //           id_: '1',
  //         },
  //         emergency_contact: {
  //           emergency_contact_id: {
  //             id_: '6d6ed1f4-8294-44de-9855-2999bdf9e3a7',
  //           },
  //           name: {
  //             first_name: 'Joe',
  //             last_name: 'Smith',
  //           },
  //           relationship: {
  //             code: 'PARENT',
  //             display: null,
  //             description: null,
  //           },
  //           contact_info: {
  //             primary_phone: '6666666666',
  //             alternate_phone: '6666666667',
  //             email: '[email protected]',
  //             address: {
  //               line_1: null,
  //               line_2: null,
  //               city: null,
  //               state: null,
  //               zip_code: null,
  //             },
  //           },
  //         },
  //       },
  //     },
  //   };
  // },
};

I left the commented out code so you code see what I have attempted.

Now my tests all seem to pass however I am getting a warning when I run my tests. This warning has the same structure as my GET_PERSON_QUERY or getPerson mock.

    console.warn
      Unknown query {
        "kind": "Document",
        "definitions": [
          {
            "kind": "OperationDefinition",
            "operation": "query",
            "name": {
              "kind": "Name",
              "value": "People"
            },
            "variableDefinitions": [
              {
                "kind": "VariableDefinition",
                "variable": {
                  "kind": "Variable",
                  "name": {
                    "kind": "Name",
                    "value": "id_"
                  }
                },
                "type": {
                  "kind": "NonNullType",
                  "type": {
                    "kind": "NamedType",
                    "name": {
                      "kind": "Name",
                      "value": "String"
                    }
                  }
                },
                "directives": []
              }
            ],
            "directives": [],
            "selectionSet": {
              "kind": "SelectionSet",
              "selections": [
                {
                  "kind": "Field",
                  "name": {
                    "kind": "Name",
                    "value": "people"
                  },
                  "arguments": [
                    {
                      "kind": "Argument",
                      "name": {
                        "kind": "Name",
                        "value": "person_id"
                      },
                      "value": {
                        "kind": "Variable",
                        "name": {
                          "kind": "Name",
                          "value": "id_"
                        }
                      }
                    }
                  ],
                  "directives": [],
                  "selectionSet": {
                    "kind": "SelectionSet",
                    "selections": [
                      {
                        "kind": "Field",
                        "name": {
                          "kind": "Name",
                          "value": "name"
                        },
                        "arguments": [],
                        "directives": [],
                        "selectionSet": {
                          "kind": "SelectionSet",
                          "selections": [
                            {
                              "kind": "Field",
                              "name": {
                                "kind": "Name",
                                "value": "first_name"
                              },
                              "arguments": [],
                              "directives": []
                            },
                            {
                              "kind": "Field",
                              "name": {
                                "kind": "Name",
                                "value": "middle_name"
                              },
                              "arguments": [],
                              "directives": []
                            },
                            {
                              "kind": "Field",
                              "name": {
                                "kind": "Name",
                                "value": "last_name"
                              },
                              "arguments": [],
                              "directives": []
                            }
                          ]
                        }
                      },
                      {
                        "kind": "Field",
                        "name": {
                          "kind": "Name",
                          "value": "preferred_name"
                        },
                        "arguments": [],
                        "directives": [],
                        "selectionSet": {
                          "kind": "SelectionSet",
                          "selections": [
                            {
                              "kind": "Field",
                              "name": {
                                "kind": "Name",
                                "value": "first_name"
                              },
                              "arguments": [],
                              "directives": []
                            },
                            {
                              "kind": "Field",
                              "name": {
                                "kind": "Name",
                                "value": "middle_name"
                              },
                              "arguments": [],
                              "directives": []
                            },
                            {
                              "kind": "Field",
                              "name": {
                                "kind": "Name",
                                "value": "last_name"
                              },
                              "arguments": [],
                              "directives": []
                            }
                          ]
                        }
                      },
                      {
                        "kind": "Field",
                        "name": {
                          "kind": "Name",
                          "value": "person_id"
                        },
                        "arguments": [],
                        "directives": [],
                        "selectionSet": {
                          "kind": "SelectionSet",
                          "selections": [
                            {
                              "kind": "Field",
                              "name": {
                                "kind": "Name",
                                "value": "id_"
                              },
                              "arguments": [],
                              "directives": []
                            }
                          ]
                        }
                      },
                      {
                        "kind": "Field",
                        "name": {
                          "kind": "Name",
                          "value": "emergency_contacts"
                        },
                        "arguments": [],
                        "directives": [],
                        "selectionSet": {
                          "kind": "SelectionSet",
                          "selections": [
                            {
                              "kind": "Field",
                              "name": {
                                "kind": "Name",
                                "value": "name"
                              },
                              "arguments": [],
                              "directives": [],
                              "selectionSet": {
                                "kind": "SelectionSet",
                                "selections": [
                                  {
                                    "kind": "Field",
                                    "name": {
                                      "kind": "Name",
                                      "value": "first_name"
                                    },
                                    "arguments": [],
                                    "directives": []
                                  },
                                  {
                                    "kind": "Field",
                                    "name": {
                                      "kind": "Name",
                                      "value": "last_name"
                                    },
                                    "arguments": [],
                                    "directives": []
                                  }
                                ]
                              }
                            },
                            {
                              "kind": "Field",
                              "name": {
                                "kind": "Name",
                                "value": "emergency_contact_id"
                              },
                              "arguments": [],
                              "directives": [],
                              "selectionSet": {
                                "kind": "SelectionSet",
                                "selections": [
                                  {
                                    "kind": "Field",
                                    "name": {
                                      "kind": "Name",
                                      "value": "id_"
                                    },
                                    "arguments": [],
                                    "directives": []
                                  }
                                ]
                              }
                            },
                            {
                              "kind": "Field",
                              "name": {
                                "kind": "Name",
                                "value": "relationship"
                              },
                              "arguments": [],
                              "directives": [],
                              "selectionSet": {
                                "kind": "SelectionSet",
                                "selections": [
                                  {
                                    "kind": "Field",
                                    "name": {
                                      "kind": "Name",
                                      "value": "code"
                                    },
                                    "arguments": [],
                                    "directives": []
                                  }
                                ]
                              }
                            },
                            {
                              "kind": "Field",
                              "name": {
                                "kind": "Name",
                                "value": "contact_info"
                              },
                              "arguments": [],
                              "directives": [],
                              "selectionSet": {
                                "kind": "SelectionSet",
                                "selections": [
                                  {
                                    "kind": "Field",
                                    "name": {
                                      "kind": "Name",
                                      "value": "primary_phone"
                                    },
                                    "arguments": [],
                                    "directives": []
                                  },
                                  {
                                    "kind": "Field",
                                    "name": {
                                      "kind": "Name",
                                      "value": "alternate_phone"
                                    },
                                    "arguments": [],
                                    "directives": []
                                  },
                                  {
                                    "kind": "Field",
                                    "name": {
                                      "kind": "Name",
                                      "value": "email"
                                    },
                                    "arguments": [],
                                    "directives": []
                                  },
                                  {
                                    "kind": "Field",
                                    "name": {
                                      "kind": "Name",
                                      "value": "address"
                                    },
                                    "arguments": [],
                                    "directives": [],
                                    "selectionSet": {
                                      "kind": "SelectionSet",
                                      "selections": [
                                        {
                                          "kind": "Field",
                                          "name": {
                                            "kind": "Name",
                                            "value": "line_1"
                                          },
                                          "arguments": [],
                                          "directives": []
                                        },
                                        {
                                          "kind": "Field",
                                          "name": {
                                            "kind": "Name",
                                            "value": "line_2"
                                          },
                                          "arguments": [],
                                          "directives": []
                                        },
                                        {
                                          "kind": "Field",
                                          "name": {
                                            "kind": "Name",
                                            "value": "city"
                                          },
                                          "arguments": [],
                                          "directives": []
                                        },
                                        {
                                          "kind": "Field",
                                          "name": {
                                            "kind": "Name",
                                            "value": "state"
                                          },
                                          "arguments": [],
                                          "directives": []
                                        },
                                        {
                                          "kind": "Field",
                                          "name": {
                                            "kind": "Name",
                                            "value": "zip_code"
                                          },
                                          "arguments": [],
                                          "directives": []
                                        }
                                      ]
                                    }
                                  }
                                ]
                              }
                            }
                          ]
                        }
                      }
                    ]
                  }
                }
              ]
            }
          }
        ],
        "loc": {
          "start": 0,
          "end": 706
        }
      } requested in refetchQueries options.include array

      at Function.warn (node_modules/ts-invariant/lib/invariant.esm.js:35:27)
      at node_modules/@apollo/client/core/QueryManager.js:447:42
          at Map.forEach (<anonymous>)
      at QueryManager.Object.<anonymous>.QueryManager.getObservableQueries (node_modules/@apollo/client/core/QueryManager.js:445:31)
      at QueryManager.Object.<anonymous>.QueryManager.refetchQueries (node_modules/@apollo/client/core/QueryManager.js:657:18)
      at QueryManager.Object.<anonymous>.QueryManager.markMutationResult (node_modules/@apollo/client/core/QueryManager.js:200:18)
      at node_modules/@apollo/client/core/QueryManager.js:107:49
      at both (node_modules/@apollo/client/utilities/observables/asyncMap.js:16:53)
@jasnross
Copy link

jasnross commented Oct 6, 2021

We're also seeing this. It doesn't seem to negatively impact anything as far as I can tell, but it's a bit noisy to see in the test output.

Our prior expectation regarding refetchQueries was that it should refetch the query if the query is currently active, but if there is no active query it just skips the refetch.

We have a number of reusable components that use it this way so the fact that the query is not active is not really a concern to us... we just want it to refetch the query if active, and otherwise just do nothing.

Is there some way to just disable the console.warn here?

@salvadortorrubiaNexplore
Copy link

salvadortorrubiaNexplore commented Nov 18, 2021

You avoid this warnings in tests with this function:

export const disableNotRequiredWarnings = () => {
  const originalWarn = console.warn.bind(console.warn);
  beforeAll(() => {
    console.warn = (msg: any) =>
      !msg.toString().includes('refetchQueries') && originalWarn(msg);
  });
  afterAll(() => {
    console.warn = originalWarn;
  });
};

@vdhpieter
Copy link

vdhpieter commented Dec 9, 2021

@salvadortorrubiaNexplore that's not really a good solution IMO

This warning is driving me crazy and polluting our test output with thousands of rows... (the whole document node get's printed).

@benjamn Is there anyway to solve this? Best way would be to turn this off for the MockedProvider IMO

@vinigaviraghi
Copy link

@trevordammon did you try to change the refetchQuery of your mutation to this?

 const [add_emergency_contact] = useMutation(ADD_EMERGENCY_CONTACT, {
    refetchQueries: [
        { query: GET_PERSON_QUERY }
    ],
 });

@theBrianCui
Copy link

We found a workaround for this by mocking the useMutation hook and then modifying the mutation options to exclude refetchQueries. Note, you may have to modify the code in the sample below to get it working.

jest.mock('@apollo/client', () => {
  const originalModule = jest.requireActual('@apollo/client');

  return {
    __esModule: true,
    ...originalModule,
    useMutation: jest.fn().mockImplementation((document, options) => {
      const noRefetch = { ...options, refetchQueries: [] };
      return originalModule.useMutation(document, noRefetch);
    }),
  };
});

@vdhpieter
Copy link

@theBrianCui that's already a more elegant solution, but still not great IMO

@benjamn any input how this can be solved better? I'm open to contributing but would like some direction on how to fix this

@bcarriereupgrade
Copy link

You can also create your own useMutation function "wrapper", use that instead of using Apollo useMutation directly, and then mock that with empty refetch queries.

I ran into this (harmless but annoying!) issue and we already had a specialized hook that wrapped useMutation so no code change in my situation.

@lauriharpf
Copy link

These warnings seem to have been introduced in version 3.4.0, in this pull request: #7813

@lawrence-witt
Copy link

lawrence-witt commented Nov 15, 2022

@vinigaviraghi worth mentioning that for this to work you must supply all the variables you require for the query, if the query takes any:

 const [add_emergency_contact] = useMutation(ADD_EMERGENCY_CONTACT, {
    refetchQueries: [
        { query: GET_PERSON_QUERY, variables: { ... } }
    ],
 });

@Fitzpaa
Copy link

Fitzpaa commented May 11, 2023

Is there a better solution to this yet? Seems like there should be a way to just disable that warning.

@modisulak
Copy link

I was able to fix this by editing the refetchQuery. Switched to using the refetchQuery which is new in ApolloClient 3.4
https://www.apollographql.com/docs/react/data/refetching/#clientrefetchqueries
await client.refetchQueries({ include: 'active', });

Adding Active, has gotten ridden of my console warns and my application works as expected re-fetching the queries again.

@malininss
Copy link

The problem is still here. Is there some kind of solution in development? This is clearly a bug
Even if I add a mock for the refetch request, this warning appears

@jonnytullis
Copy link

Still seeing this in the latest version 3.9.5. It would be nice to reduce noise in our CI testing pipelines.

@MatheoJaouen
Copy link

It there any update on this? I would prefer to avoid passing variables again.
theBrianCUI's solution seems to be working on an older version only, refetchQueries is no longer passed threw useMutation options apparently but only in the callback function, tricky to mock.
Thank you.

@asoov
Copy link

asoov commented Aug 7, 2024

Still seeing this. Even if I add a mock for the query needed to be refetched this happens. Clearly a bug. Would be nice if this could be addressed +1

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests