Skip to content

Commit

Permalink
Add option to mock the entire schema(i.e. set preserveResolvers) (#1546)
Browse files Browse the repository at this point in the history
* add mockEntireSchema as configuration for preserveResolvers

* add mockEntireSchema to api reference

* add changelog
  • Loading branch information
Evans Hauser committed Aug 16, 2018
1 parent 25f568b commit efc5302
Show file tree
Hide file tree
Showing 7 changed files with 134 additions and 5 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Expand Up @@ -4,6 +4,8 @@ All of the packages in the `apollo-server` repo are released with the same versi

### vNEXT

- Add option to mock the entire schema(i.e. sets preserveResolvers) [PR #1546](https://github.com/apollographql/apollo-server/pull/1546)

### v2.0.2

- Release with Lerna 3
Expand Down
4 changes: 4 additions & 0 deletions docs/source/api/apollo-server.md
Expand Up @@ -57,6 +57,10 @@ new ApolloServer({

A boolean enabling the default mocks or object that contains definitions

* `mockEntireSchema`: <`Boolean`>

A boolean controlling whether existing resolvers are overridden by mocks. Defaults to true, meaning that all resolvers receive mocked values.

* `schemaDirectives`: <`Object`>

Contains definition of schema directives used in the `typeDefs`
Expand Down
38 changes: 38 additions & 0 deletions docs/source/features/mocking.md
Expand Up @@ -143,6 +143,44 @@ const mocks = {

For some more background and flavor on this approach, read the ["Mocking your server with one line of code"](https://medium.com/apollo-stack/mocking-your-server-with-just-one-line-of-code-692feda6e9cd) 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` field to false.

```js line=26
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,
mockEntireSchema: false,
});

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

## Mocking a schema using introspection

The GraphQL specification allows clients to introspect the schema with a [special set of types and fields](https://facebook.github.io/graphql/#sec-Introspection) that every schema must include. The results of a [standard introspection query](https://github.com/graphql/graphql-js/blob/master/src/utilities/introspectionQuery.js) can be used to generate an instance of GraphQLSchema which can be mocked as explained above.
Expand Down
11 changes: 8 additions & 3 deletions packages/apollo-server-core/src/ApolloServer.ts
Expand Up @@ -86,6 +86,7 @@ export class ApolloServerBase {
typeDefs,
introspection,
mocks,
mockEntireSchema,
extensions,
engine,
subscriptions,
Expand Down Expand Up @@ -178,11 +179,15 @@ export class ApolloServerBase {
});
}

if (mocks) {
if (mocks || typeof mockEntireSchema !== 'undefined') {
addMockFunctionsToSchema({
schema: this.schema,
preserveResolvers: true,
mocks: typeof mocks === 'boolean' ? {} : mocks,
mocks:
typeof mocks === 'boolean' || typeof mocks === 'undefined'
? {}
: mocks,
preserveResolvers:
typeof mockEntireSchema === 'undefined' ? false : !mockEntireSchema,
});
}

Expand Down
1 change: 1 addition & 0 deletions packages/apollo-server-core/src/types.ts
Expand Up @@ -56,6 +56,7 @@ export interface Config
context?: Context<any> | ContextFunction<any>;
introspection?: boolean;
mocks?: boolean | IMocks;
mockEntireSchema?: boolean;
engine?: boolean | EngineReportingOptions;
extensions?: Array<() => GraphQLExtension>;
persistedQueries?: PersistedQueryOptions | false;
Expand Down
79 changes: 79 additions & 0 deletions packages/apollo-server-integration-testsuite/src/ApolloServer.ts
Expand Up @@ -271,6 +271,7 @@ export function testApolloServer<AS extends ApolloServerBase>(
expect(result.data).toEqual({ testString: 'test string' });
expect(result.errors).toBeUndefined();
});

it('allows mocks as boolean', async () => {
const typeDefs = gql`
type Query {
Expand Down Expand Up @@ -305,6 +306,84 @@ export function testApolloServer<AS extends ApolloServerBase>(
expect(result.data).toEqual({ hello: 'mock city' });
expect(result.errors).toBeUndefined();
});

it('allows mocks as an object without overriding the existing resolvers', async () => {
const typeDefs = gql`
type User {
first: String
last: String
}
type Query {
user: User
}
`;
const resolvers = {
Query: {
user: () => ({
first: 'James',
last: 'Heinlen',
}),
},
};
const { url: uri } = await createApolloServer({
typeDefs,
resolvers,
mocks: {
User: () => ({
last: () => 'mock city',
}),
},
});

const apolloFetch = createApolloFetch({ uri });
const result = await apolloFetch({
query: '{user{first last}}',
});
expect(result.data).toEqual({
user: { first: 'Hello World', last: 'mock city' },
});
expect(result.errors).toBeUndefined();
});

// Need to fix bug in graphql-tools to enable mocks to override the existing resolvers
it.skip('allows mocks as an object with overriding the existing resolvers', async () => {
const typeDefs = gql`
type User {
first: String
last: String
}
type Query {
user: User
}
`;
const resolvers = {
Query: {
user: () => ({
first: 'James',
last: 'Heinlen',
}),
},
};
const { url: uri } = await createApolloServer({
typeDefs,
resolvers,
mocks: {
User: () => ({
last: () => 'mock city',
}),
},
mockEntireSchema: false,
});

const apolloFetch = createApolloFetch({ uri });
const result = await apolloFetch({
query: '{user{first last}}',
});
expect(result.data).toEqual({
user: { first: 'James', last: 'mock city' },
});
expect(result.errors).toBeUndefined();
});
});
});

Expand Down
4 changes: 2 additions & 2 deletions packages/apollo-server-integration-testsuite/src/index.ts
Expand Up @@ -442,7 +442,7 @@ export default (createApp: CreateAppFunc, destroyApp?: DestroyAppFunc) => {
},
});
return req.then(res => {
expect(res.status).toEqual(200);
expect(res.statusCode).toEqual(200);
expect(res.body.errors).toBeDefined();
expect(res.body.errors.length).toEqual(1);
expect(res.body.errors[0].message).toEqual(
Expand All @@ -465,7 +465,7 @@ export default (createApp: CreateAppFunc, destroyApp?: DestroyAppFunc) => {
}),
});
return req.then(res => {
expect(res.status).toEqual(200);
expect(res.statusCode).toEqual(200);
expect(res.body.errors).toBeDefined();
expect(res.body.errors.length).toEqual(1);
expect(res.body.errors[0].message).toEqual('PersistedQueryNotFound');
Expand Down

0 comments on commit efc5302

Please sign in to comment.