Mocking

Mock your GraphQL data based on a schema.

The strongly-typed nature of a GraphQL API lends itself extremely well to mocking. This is an important part of a GraphQL-First development process, because it enables frontend developers to build out UI components and features without having to wait for a backend implementation.

Even when the UI is already built, it can let you test your UI without waiting on slow database requests, or build out a component harness using a tool like React Storybook without needing to start a real GraphQL server.

Default mock example

This example demonstrates mocking a GraphQL schema with just one line of code, using apollo-server‘s default mocking logic.

const { ApolloServer, gql } = require('apollo-server');

const typeDefs = gql`
type Query {
  hello: String
}
`;

const server = new ApolloServer({
  typeDefs,
  mocks: true,
});

server.listen().then(({ url }) => {
  console.log(`🚀 Server ready at ${url}`)
});

Note: If typeDefs has custom scalar types, resolvers must still contain the serialize, parseValue, and parseLiteral functions

Mocking logic simply looks at the type definitions and returns a string where a string is expected, a number for a number, etc. This provides the right shape of result. For more sophisticated testing, mocks can be customized them to a particular data model.

Customizing mocks

In addition to a boolean, mocks can be an object that describes custom mocking logic, which is structured similarly to resolvers with a few extra features aimed at mocking. Namely mocks accepts functions for specific types in the schema that are called when that type is expected. The functions in mocks would be used when no resolver in resolvers is specified. In this example hello will return 'Hello' and resolved will return 'Resolved'.

const { ApolloServer } = require('apollo-server');

const typeDefs = gql`
type Query {
  hello: String
  resolved: String
}
`;

const resolvers = {
  Query: {
    resolved: () => 'Resolved',
  },
};

const mocks = {
  Int: () => 6,
  Float: () => 22.1,
  String: () => 'Hello',
};

const server = new ApolloServer({
  typeDefs,
  resolvers,
  mocks,
});

server.listen().then(({ url }) => {
  console.log(`🚀 Server ready at ${url}`)
});

Similarly to resolvers, mocks allows the description of object types with the fields. Take note that the value corresponding to Person is a function that returns an object that contains fields pointing at more functions:

const mocks = {
  Person: () => ({
    name: casual.name,
    age: () => casual.integer(0, 120),
  }),
};

The previous example uses casual, a fake data generator for JavaScript, which returns a different result every time the field is called. In other scenarios, such as testing, a collection of fake objects or a generator that always uses a consistent seed are often necessary to provide consistent data.

Using MockList in resolvers

To automate mocking a list, return an instance of MockList:

const { MockList } = require('apollo-server');

const mocks = {
  Person: () => ({
    // a list of length between 2 and 6 (inclusive)
    friends: () => new MockList([2,6]),
    // a list of three lists each with two items: [[1, 1], [2, 2], [3, 3]]
    listOfLists: () => new MockList(3, () => new MockList(2)),
  }),
};

In more complex schemas, MockList is helpful for randomizing the number of entries returned in lists.

For example, this schema:

type Query {
  people: [Person]
}

type Person {
  name: String
  age: Int
}

By default, the people field will always return 2 entries. To change this, we can add a mock resolver that returns MockList:

const mocks = {
  Query: () =>({
    people: () => new MockList([0, 12]),
  }),
};

Now the mock data will contain between zero and 12 summary entries.

Accessing arguments in mock resolvers

The mock functions on fields are actually just GraphQL resolvers, which can use arguments and context:

const mocks = {
  Person: () => ({
    // the number of friends in the list now depends on numPages
    paginatedFriends: (root, args, context, info) => new MockList(args.numPages * PAGE_SIZE),
  }),
};

For some more background and flavor on this approach, read the “Mocking your server with one line of code” article on the Apollo blog.

Mocking a schema using introspection

The GraphQL specification allows clients to introspect the schema with a special set of types and fields that every schema must include. The results of a standard introspection query can be used to generate an instance of GraphQLSchema which can be mocked as explained above.

This helps when you need to mock a schema defined in a language other than JS, for example Go, Ruby, or Python.

To convert an introspection query result to a GraphQLSchema object, you can use the buildClientSchema utility from the graphql package.

const { buildClientSchema } = require('graphql');
const introspectionResult = require('schema.json');
const { ApolloServer } = require('apollo-server');

const schema = buildClientSchema(introspectionResult);

const server = new ApolloServer({
  schema,
  mocks: true,
});

server.listen().then(({ url }) => {
  console.log(`🚀 Server ready at ${url}`)
});

API

Under the hood, Apollo Sever uses a library for building GraphQL servers, called graphql-tools. The mocking functionality is provided by the function addMockFunctionsToSchema. The mocks object is passed directly to the function and preserveResolvers is always true. MockList is exported directly from the graphql-tools library.

Edit on GitHub
// search box