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 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.
1const { ApolloServer, gql } = require('apollo-server');
2
3const typeDefs = gql`
4 type Query {
5 hello: String
6 }
7`;
8
9const server = new ApolloServer({
10 typeDefs,
11 mocks: true,
12});
13
14server.listen().then(({ url }) => {
15 console.log(`🚀 Server ready at ${url}`)
16});
Note: If
typeDefs
has custom scalar types,resolvers
must still contain theserialize
,parseValue
, andparseLiteral
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. By default, when using mocks, any existing resolvers are ignored. See the "Using existing resolvers with mocks" section below for more info on how to change this behavior.
For more sophisticated testing, mocks can be customized 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. By default, the functions in mocks
will overwrite the resolvers in resolvers
. In this example hello
and resolved
will both return 'Hello'
.
1const { ApolloServer, gql } = require('apollo-server');
2
3const typeDefs = gql`
4 type Query {
5 hello: String
6 resolved: String
7 }
8`;
9
10const resolvers = {
11 Query: {
12 resolved: () => 'Resolved',
13 },
14};
15
16const mocks = {
17 Int: () => 6,
18 Float: () => 22.1,
19 String: () => 'Hello',
20};
21
22const server = new ApolloServer({
23 typeDefs,
24 resolvers,
25 mocks,
26});
27
28server.listen().then(({ url }) => {
29 console.log(`🚀 Server ready at ${url}`)
30});
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:
1const mocks = {
2 Person: () => ({
3 name: casual.name,
4 age: () => casual.integer(0, 120),
5 }),
6};
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
:
1const { MockList } = require('apollo-server');
2
3const mocks = {
4 Person: () => ({
5 // a list of length between 2 and 6 (inclusive)
6 friends: () => new MockList([2,6]),
7 // a list of three lists each with two items: [[1, 1], [2, 2], [3, 3]]
8 listOfLists: () => new MockList(3, () => new MockList(2)),
9 }),
10};
In more complex schemas, MockList
is helpful for randomizing the number of entries returned in lists.
For example, this schema:
1type Query {
2 people: [Person]
3}
4
5type Person {
6 name: String
7 age: Int
8}
By default, the people
field will always return 2 entries. To change this, we can add a mock resolver that returns MockList
:
1const mocks = {
2 Query: () =>({
3 people: () => new MockList([0, 12]),
4 }),
5};
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
:
1const mocks = {
2 Person: () => ({
3 // the number of friends in the list now depends on numPages
4 paginatedFriends: (parent, args, context, info) => new MockList(args.numPages * PAGE_SIZE),
5 }),
6};
For some more background and flavor on this approach, read the "Mocking your server with one line of code" article on the Apollo blog.
Using existing resolvers with mocks
The default behavior for mocks is to overwrite the resolvers already present in the schema. To keep the existing resolvers, set the mockEntireSchema
option to false.
Note: mocking resolvers will not work if the
mocks
option isfalse
, even ifmockEntireSchema
is true.
1const { ApolloServer, gql } = require('apollo-server');
2
3const typeDefs = gql`
4 type Query {
5 hello: String
6 resolved: String
7 }
8`;
9
10const resolvers = {
11 Query: {
12 resolved: () => 'Resolved',
13 },
14};
15
16const mocks = {
17 Int: () => 6,
18 Float: () => 22.1,
19 String: () => 'Hello',
20};
21
22const server = new ApolloServer({
23 typeDefs,
24 resolvers,
25 mocks,
26 mockEntireSchema: false,
27});
28
29server.listen().then(({ url }) => {
30 console.log(`🚀 Server ready at ${url}`)
31});
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.
1const { buildClientSchema } = require('graphql');
2const introspectionResult = require('schema.json');
3const { ApolloServer } = require('apollo-server');
4
5const schema = buildClientSchema(introspectionResult.data);
6
7const server = new ApolloServer({
8 schema,
9 mocks: true,
10});
11
12server.listen().then(({ url }) => {
13 console.log(`🚀 Server ready at ${url}`)
14});
API
Under the hood, Apollo Server 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 the inverse of mockEntireSchema
. MockList
is exported directly from the graphql-tools
library.