2

I'm trying to mock only a small portion of the Contact type below. My resolvers return data from a REST endpoint for all fields in Contact except for test. For demo purposes, I want to be able to retain the server data for all other fields, but only mock the test field.

I have the following GraphQL schema defined:

const typeDefs = `
    type Contact {
        id: String,
        first_name: String
        last_name: String
        middle_name: String
        date_of_birth: String
        test: String
    }

    type Query {
        contacts: [Contact!]!
        Contact(id: String!): Contact!
    }
`;

I have the following mocks defined:

const mocks = {
    Contact: () => ({
        test: () => "This data is mocked!"
    })
};

And the following resolvers defined:

const resolvers = {
  Query: {
    contacts: async (parent, args, { dataSources }) =>
      dataSources.MYAPI.getAllContacts(),
    Contact: async (parent, { id }, { dataSources }) =>
      dataSources.MYAPI.getContact(id)
  }
};

Then I initialize the server with:

const server = new ApolloServer({
  typeDefs,
  resolvers,
  mocks,
  dataSources: () => {
    return {
      MYAPI: new MYAPI()
    };
  },
  mockEntireSchema: false
});

The above does not work. I added the mockEntireSchema:true configuration which prevented my server response from being overridden, but the test attribute still returns the default String mock of Hello World instead of my attempted mock of This data is mocked!.

I know the mock is set up correctly because I can remove the mockEntireSchema config and my mock data appears correctly.

Is this even possible or does the behavior of mockEntireSchema and mocks in general not support this?

Tom Nolan
  • 1,916
  • 4
  • 32
  • 51
  • Same issue here: opened an issue on `apollo-server` https://github.com/apollographql/apollo-server/issues/2421 – Marc Mar 17 '19 at 21:49

3 Answers3

1

According to the documentation, you want to keep mockEntireSchema as false and create a mocks object that has the components in it that you still WANT to mock. All other resolvers will be used as they exist. Any mocks that you HAVE defined, though, will be used, so the query resolvers that return Contact types will never be used, since you have defined Contact as a mock.

Dan Crews
  • 3,067
  • 17
  • 20
  • What you describe is not what is happening. Regardless of whether I use `mockEntireSchema` true or false, Apollo mocks all "endpoints". The only difference is that if I select `mockEntireSchema: true`, it overwrites the existing resolvers with my mock resolvers. If it's false, it ignores the mock resolvers I supply in favor of the existing resolvers, which it then mocks with defaults (Hello world, etc). – Marc Mar 17 '19 at 21:47
1

I now believe that this is actually a bug in Apollo https://github.com/apollographql/graphql-tools/issues/1114. When you use preserveResolvers: true or mockEntireSchema: false (they are the same), it will not overwrite existing resolvers, however, I filtered those resolvers out based on my mock configuration, so they are not loaded in the first place.

This makes the partial mocking work in principle. The bug however is that nested () => MockList(100) calls throw an error in the graphql package because graphql interprets the MockList object as "not an iterable". This doesn't happen with preserveResolvers: false

Marc
  • 6,773
  • 10
  • 44
  • 68
0

I haven't tried it but to me it seems like it should work (what you describe). But since it doesn't, a possible workaround would be to just add a field resolver for the test field:

const resolvers = {
  Contact: {
    test: () => "This data is not mocked but the effect is the same!"
  },
  Query: {
    contacts: async (parent, args, { dataSources }) =>
      dataSources.MYAPI.getAllContacts(),
    Contact: async (parent, { id }, { dataSources }) =>
      dataSources.MYAPI.getContact(id)
  }
};
Mikael Lirbank
  • 4,355
  • 2
  • 28
  • 25