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

Breaking change from 3.0.2 to 3.1.0 [ MockedProvider ] #6803

Closed
tyagow opened this issue Aug 8, 2020 · 22 comments
Closed

Breaking change from 3.0.2 to 3.1.0 [ MockedProvider ] #6803

tyagow opened this issue Aug 8, 2020 · 22 comments

Comments

@tyagow
Copy link

tyagow commented Aug 8, 2020

Intended outcome:
Be able to mock a query using MockProvider

import { MockedProvider } from '@apollo/client/testing';
import { GET_TEACHERS_AND_ADMINS_OF_MY_DISTRICT_QUERY } from '../queries';

const mocks = [
  {
    request: {
      query: GET_TEACHERS_AND_ADMINS_OF_MY_DISTRICT_QUERY,
    },
    result: {
      loading: false,
      error: null,
      data: {
        teachersAndAdminsOfMyDistrict: [
          {
          [...]
...
      <MockedProvider mocks={mocks} addTypename={false}>
        <ComponentThatUsesTheQuery  />
      </MockedProvider>

Actual outcome:

After updating to 3.1.0 tests broke with:

    No more mocked responses for the query: {
      teachersAndAdminsOfMyDistrict {
      [...]

How to reproduce the issue:
Described in the first section but if more info is needed I can add here.

Versions

  System:
    OS: Linux 5.4 Ubuntu 20.04.1 LTS (Focal Fossa)
  Binaries:
    Node: 10.19.0 - /usr/bin/node
    npm: 6.14.4 - /usr/bin/npm
  Browsers:
    Chrome: 84.0.4147.105
    Firefox: 79.0
  npmPackages:
    @apollo/client: ^3.1.0 => 3.1.0 
    apollo-upload-client: ^14.1.0 => 14.1.0 
@mikevercoelen
Copy link

+1

We're also experiencing this issue

@mikevercoelen
Copy link

@tyagow as a work around, you can mock useQuery like so:

import * as Apollo from '@apollo/client';

jest.spyOn(Apollo, 'useQuery').mockImplementation(() => {
    return {
        loading: false,
        error: undefined,
        data: { MOCK_DATA },
        refetch: jest.fn()
    }
});

@tyagow
Copy link
Author

tyagow commented Aug 13, 2020

@tyagow as a work around, you can mock useQuery like so:

import * as Apollo from '@apollo/client';

jest.spyOn(Apollo, 'useQuery').mockImplementation(() => {
    return {
        loading: false,
        error: undefined,
        data: { MOCK_DATA },
        refetch: jest.fn()
    }
});

Thank you, great idea!
In the end, I used the new mock wrapper we created that uses the schema.graphql to auto-generate responses, here is a draft:

const mergeResolvers = (target, input) => {
  const inputTypenames = Object.keys(input);
  const merged = inputTypenames.reduce(
    (accum, key) => {
      const inputResolver = input[key];
      if (target[key]) {
        const targetResolver = target[key];
        const resolvedInput = inputResolver();
        const resolvedTarget = targetResolver();
        if (
          !!resolvedTarget &&
          !!resolvedInput &&
          isDict(resolvedTarget) &&
          isDict(resolvedInput)
        ) {
          const newValue = { ...resolvedTarget, ...resolvedInput };
          return {
            ...accum,
            [key]: () => newValue,
          };
        }
      }
      return { ...accum, [key]: inputResolver };
    },
    { ...target }
  );
  return merged;
};
const buildSchema = mocks => {
  const schemaStr = print(schemaGQL) + clientDefs;
  const schema = makeExecutableSchema({
    typeDefs: schemaStr,
    resolverValidationOptions: {
      requireResolversForResolveType: false,
    },
  });

  return addMocksToSchema({ schema, mocks, preserveResolvers: true });
};

export const ApolloProviderWithMock = ({ customResolvers, client, children }) => {
  const mocks = mergeResolvers(globalMocks, customResolvers);
  const schema = buildSchema(mocks);

  let apolloClient = client;

  if (!client) {
    apolloClient = new ApolloClient({
      fetch,
      link: new SchemaLink({ schema }),
      cache: new InMemoryCache({ possibleTypes }),
      typeDefs: schema,
    });
  }

  return <ApolloProvider client={apolloClient}>{children}</ApolloProvider>;
};

Then in a test I just need to wrap the component being tested with it. Also, I can set specific values for specific queries

const customerResolver = {
  Query: () => ({
    SomeQuery: () => ({
      [...]
    })
  })
}
<ApolloProviderWithMock customerResolver={customerResolver}>
  <Component>
</ApolloProviderWithMock>

@bryancuster
Copy link

I am actually unable to get MockedProvider working at all on any 3.x version of @apollo/client.

import { render } from '@testing-library/react'
import '@testing-library/jest-dom/extend-expect'
import { MockedProvider } from '@apollo/client/testing'
import { Route, MemoryRouter } from 'react-router-dom'

...

describe('pipeline: none', () => {
  test('does not render environment section', async () => {
    const { getByText } = render(
      <MockedProvider
        mocks={[
          {
            request: {
              query: MARKETPLACE_OFFERING_QUERY,
              variables: {
                guid
              }
            },
            result: {
              data: {
                offering: { guid, name: 'mock offering' }
              }
            }
          }
        ]}
        addTypename={false}
      >
        <MemoryRouter initialEntries={['builder/123/456']}>
          <Route path="builder/:offering_guid/:plan_guid">
            <Builder />
          </Route>
        </MemoryRouter>
      </MockedProvider>
    )

    await new Promise(resolve => setTimeout(resolve, 0)) // wait for response

    expect(getByText('mock offering')).toBeInTheDocument()
  })
})

Leaving out this, the loading state is always true. With it the component is able to log out loading: true and then loading: false.

    await new Promise(resolve => setTimeout(resolve, 0)) // wait for response

The assertion fails, data is always undefined in the component even when loading: false from the useQuery.

@Markus-ipse
Copy link

My team seem to have run into the same problem :(

@unHuesio
Copy link

Same here, the mock provider seems to stopped working in some cases while running the styleguidist server, and when generating the static version of the styleguidist, some cases do work. A bit unstable, and now we are currently deciding if we should revert, or look for a solution.

@Markus-ipse
Copy link

Markus-ipse commented Aug 17, 2020

In my case it was the same problem as described here: #6771

I added logging to my component that did the mutations and saw that the variables contained a field with an explicit undefined instead of omitting the field. So I just explicitly added undefined for the variable in my mock as well and it started working!

e.g.
From:

    {
      request: {
        query: UPDATE_ITEM,
        variables: {
          teamId: 'team-1',
          itemId: 'item-1',
        },
    },

To:

    {
      request: {
        query: UPDATE_ITEM,
        variables: {
          teamId: 'team-1',
          itemId: 'item-1',
          optionalField: undefined
        },
    },

@emmanuelkant
Copy link

emmanuelkant commented Aug 18, 2020

In my case I added the prop like that, <MockedProvider mocks={mock} addTypename={true}> and the error stopped. I realized that the error message was with the data with __typename. Like this:

products {
  name
  description
  price
  __typename
}

So I tried this and worked for me. However, the error still is a mystery for me.

@tyagow tyagow changed the title Breaking change from 3.0.2 to 3.1.0 Breaking change from 3.0.2 to 3.1.0 [ MockedProvider ] Aug 19, 2020
@aleksandr-omise
Copy link

Get this error - No more mocked responses for the query: mutation. Seems like MockedProvider broken or poorly documented.

@deltek-rossjackson
Copy link

I've resolved this with my post on this one

defaultOptions={{
                                watchQuery: { fetchPolicy: 'no-cache' },
                                query: { fetchPolicy: 'no-cache' },
                            }}

@joshjg
Copy link
Contributor

joshjg commented Sep 8, 2020

In my case it was the same problem as described here: #6771

I added logging to my component that did the mutations and saw that the variables contained a field with an explicit undefined instead of omitting the field. So I just explicitly added undefined for the variable in my mock as well and it started working!

I found the issue to be the same as @Markus-ipse

The change in behavior appears to have been introduced here, by switching to a different deep equal function: 2593f8f#diff-fab0a81f7f7c1e746fd7f86a7a1458c9 and 26849a8
(cc: @benjamn)

The previous isEqual implementation ignored undefined object properties. Unfortunately, we were relying on that behavior so hundreds of our tests are now failing in 3.1.x.

benjamn added a commit that referenced this issue Oct 1, 2020
See benjamn/wryware#21 for explanation and
motivation. Should help with #6771, #6803, #6688, #6378, and #7081, and
possibly other regressions that began in @apollo/[email protected].
benjamn added a commit that referenced this issue Oct 1, 2020
See benjamn/wryware#21 for explanation and
motivation. Should help with #6771, #6803, #6688, #6378, and #7081, and
possibly other regressions that began in @apollo/[email protected].
@benjamn
Copy link
Member

benjamn commented Oct 1, 2020

This behavior should be fixed/improved in @apollo/[email protected] (just published to npm), thanks to #7108. Please give it another try after updating!

@AdrienLemaire
Copy link

AdrienLemaire commented Oct 8, 2020

Getting the same No more mocked responses for the query error.
Bumping to 3.3.0-beta.9 didn't resolve it.
Adding defaultOptions with fetchPolicy: "no-cache" didn't help either.

example

test:

describe("ProfileHeader", () => {
  it.only("show a profile header", async () => {
    const { container } = renderApollo(<ProfileHeader />, {
      defaultOptions: {
        query: { fetchPolicy: "no-cache" },
        watchQuery: { fetchPolicy: "no-cache" },
      },
    });
    await waitFor(() => {
      expect(container).toMatchSnapshot();
    });
  });

renderApollo

import { MockedProvider, MockedResponse } from "@apollo/client/testing";

const renderApollo = (
  node: any,
  {
    mocks,
    addTypename,
    defaultOptions,
    cache,
    resolvers,
    ...options
  }: RenderApolloOptions = {}
): RenderResult => {
  return render(
    <MockedProvider
      mocks={mocks}
      addTypename={addTypename}
      defaultOptions={defaultOptions}
      cache={cache}
      resolvers={resolvers}
    >
      {node}
    </MockedProvider>,
    options
  );
};

Component:

const ProfileHeader: React.FC = () => {
  const [queryExecutor, { loading, error, data }] = useLazyQuery<TMe>(
    PROFILE_QUERY,
    {
      // fetchPolicy: "cache-only", // <!== If changing the fetchPolicy here, the test pass!
      fetchPolicy: "cache-and-network",
      nextFetchPolicy: "cache-first",
    }
  );

It would seem like MockedProvider doesn't replace my useLazyQuery options with the defaultOptions passed from the test.
Just in case, I also tried to replace useLazyQuery with useQuery, and am also getting the same error

EDIT: My issue is unrelated to this thread, sorry for the noise
While I still don't know how we're supposed to write tests for queries using fetchPolicy: "cache-and-network" (I would very much like to test the different loading phases of my component), I could get my test to pass with a jest.spy

// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
jest.spyOn(Apollo, "useLazyQuery").mockImplementation(() => {
  return [
    jest.fn(),
    {
      data: null,
      error: undefined,
      loading: false,
    },
  ];
});

@betweenparentheses
Copy link

betweenparentheses commented Oct 15, 2020

Still experiencing this issue, even with setting fetchPolicy: no-cache, even with using the new beta version. The Dog example from the docs fails on my environment with direct copy/paste, "no more mocked responses". https://www.apollographql.com/docs/react/development-testing/testing/

worth noting that addTypename was set to FALSE but it's still expecting a __typename in one spot

Screen Shot 2020-10-15 at 9 39 59 AM

UPDATE:

I was getting these errors because I had missed the necessity of cleanup between test runs.

in create-react-app, I needed

import { cleanup, render } from '@testing-library/react';


afterEach(cleanup)

FURTHER UPDATE: cleanup was not sufficient, the same specs were intermittently getting this error in CI even when passing locally. It was necessary to version bump to the beta.

@manukapoor
Copy link

This behavior should be fixed/improved in @apollo/[email protected] (just published to npm), thanks to #7108. Please give it another try after updating!

This fixes my issue @benjamn , do we have any visibility into a release schedule? This is blocking our development and it'd be great to have an estimate. Thanks!

@btferus5
Copy link

btferus5 commented Oct 28, 2020

I was having this issue on any 3.x.x version (my mocks have correct variables + __typenames and all that junk, this seemed like a legitimate bug with MockedProvider), upgrading to @apollo/[email protected] did NOT fix it for me, but upgrading to @apollo/[email protected] DID fix it for me.

edit: just wanted to say that this didn't fix everything, still had some tests that were failing that definitely should pass (spent hours checking typenames + variables, 100% sure things are accurate). We had the most trouble with components that had 2 different queries running in the same file as well as queries with empty variables), it always got confused.
ended up doing this in our jest

jest.mock('@apollo/client', () => ({
...jest.requireActual('@apollo/client'),
useQuery: (query, options) => jest.requireActual('@apollo/client').useQuery(query, {
  ...options,
  fetchPolicy: 'no-cache'
  })
})
)



basically just forcing no-cache for testing purposes

@mbrowne
Copy link

mbrowne commented Dec 11, 2020

The current apollo-client release is 3.3.5, and this seems to be fixed now.

@hwillson
Copy link
Member

hwillson commented May 5, 2021

It doesn't sound like there is an outstanding issue here, so closing. Thanks!

@hwillson hwillson closed this as completed May 5, 2021
@findlay-hannam
Copy link

I'm still getting this on version 3.3.21

@mbrowne
Copy link

mbrowne commented Jul 29, 2021

@findlay-hannam Are you running multiple queries in a single test? Maybe you actually need to add more mocks. (But it's also possible there's still a bug somewhere.)

@findlay-hannam
Copy link

I am running multiple queries, but the tests pass when I set the fetchPolicy to 'no-cache'. I'm currently using the workaround @btferus5 suggested

@cheukribbon
Copy link

Have similar issue with fetchPolicy

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Feb 15, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests