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

Add option to mock the entire schema(i.e. set preserveResolvers) #1546

Merged
merged 4 commits into from Aug 16, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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