From e3d5be954f9109999ad5c0dbccd8c5f5bc0833b8 Mon Sep 17 00:00:00 2001 From: Jake Dawkins Date: Mon, 5 Nov 2018 11:22:30 -0800 Subject: [PATCH] Introduce `apollo-server-testing` package. (#1909) --- package-lock.json | 6 ++ package.json | 1 + .../apollo-server-core/src/ApolloServer.ts | 35 ++++++++ packages/apollo-server-testing/CHANGELOG.md | 5 ++ packages/apollo-server-testing/README.md | 7 ++ packages/apollo-server-testing/jest.config.js | 3 + packages/apollo-server-testing/package.json | 32 ++++++++ .../src/__tests__/createTestClient.test.ts | 81 +++++++++++++++++++ .../src/__tests__/tsconfig.json | 5 ++ .../src/createTestClient.ts | 28 +++++++ packages/apollo-server-testing/src/index.ts | 1 + packages/apollo-server-testing/tsconfig.json | 12 +++ tsconfig.build.json | 1 + 13 files changed, 217 insertions(+) create mode 100644 packages/apollo-server-testing/CHANGELOG.md create mode 100644 packages/apollo-server-testing/README.md create mode 100644 packages/apollo-server-testing/jest.config.js create mode 100644 packages/apollo-server-testing/package.json create mode 100644 packages/apollo-server-testing/src/__tests__/createTestClient.test.ts create mode 100644 packages/apollo-server-testing/src/__tests__/tsconfig.json create mode 100644 packages/apollo-server-testing/src/createTestClient.ts create mode 100644 packages/apollo-server-testing/src/index.ts create mode 100644 packages/apollo-server-testing/tsconfig.json diff --git a/package-lock.json b/package-lock.json index a5be2d97812..ea6c5e67cb2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2264,6 +2264,12 @@ "apollo-server-plugin-base": { "version": "file:packages/apollo-server-plugin-base" }, + "apollo-server-testing": { + "version": "file:packages/apollo-server-testing", + "requires": { + "apollo-server-core": "file:packages/apollo-server-core" + } + }, "apollo-tracing": { "version": "file:packages/apollo-tracing", "requires": { diff --git a/package.json b/package.json index 7b337d45081..57c8daaaddb 100644 --- a/package.json +++ b/package.json @@ -54,6 +54,7 @@ "apollo-server-lambda": "file:packages/apollo-server-lambda", "apollo-server-micro": "file:packages/apollo-server-micro", "apollo-server-plugin-base": "file:packages/apollo-server-plugin-base", + "apollo-server-testing": "file:packages/apollo-server-testing", "apollo-tracing": "file:packages/apollo-tracing", "graphql-extensions": "file:packages/graphql-extensions" }, diff --git a/packages/apollo-server-core/src/ApolloServer.ts b/packages/apollo-server-core/src/ApolloServer.ts index f4c57d8243c..ec8bad60913 100644 --- a/packages/apollo-server-core/src/ApolloServer.ts +++ b/packages/apollo-server-core/src/ApolloServer.ts @@ -45,6 +45,13 @@ import { } from './playground'; import { generateSchemaHash } from './utils/schemaHash'; +import { + processGraphQLRequest, + GraphQLRequestContext, + GraphQLRequest, +} from './requestPipeline'; + +import { Headers } from 'apollo-server-env'; const NoIntrospection = (context: ValidationContext) => ({ Field(node: FieldDefinitionNode) { @@ -502,4 +509,32 @@ export class ApolloServerBase { ...this.requestOptions, } as GraphQLOptions; } + + public async executeOperation(request: GraphQLRequest) { + let options; + + try { + options = await this.graphQLServerOptions(); + } catch (e) { + e.message = `Invalid options provided to ApolloServer: ${e.message}`; + throw new Error(e); + } + + if (typeof options.context === 'function') { + options.context = (options.context as () => never)(); + } + + const requestCtx: GraphQLRequestContext = { + request, + context: options.context || Object.create(null), + cache: options.cache!, + response: { + http: { + headers: new Headers(), + }, + }, + }; + + return processGraphQLRequest(options, requestCtx); + } } diff --git a/packages/apollo-server-testing/CHANGELOG.md b/packages/apollo-server-testing/CHANGELOG.md new file mode 100644 index 00000000000..a64c146b38f --- /dev/null +++ b/packages/apollo-server-testing/CHANGELOG.md @@ -0,0 +1,5 @@ +# Changelog + +### vNEXT + +* `apollo-server-testing`: Added createTestClient function diff --git a/packages/apollo-server-testing/README.md b/packages/apollo-server-testing/README.md new file mode 100644 index 00000000000..a9ecec5d2b8 --- /dev/null +++ b/packages/apollo-server-testing/README.md @@ -0,0 +1,7 @@ +# apollo-server-testing + +[![npm version](https://badge.fury.io/js/apollo-server-testing.svg)](https://badge.fury.io/js/apollo-server-testing) +[![Build Status](https://circleci.com/gh/apollographql/apollo-server.svg?style=svg)](https://circleci.com/gh/apollographql/apollo-server) + +This is the testing module of the Apollo community GraphQL Server. [Read the docs.](https://www.apollographql.com/docs/apollo-server/) +[Read the CHANGELOG.](https://github.com/apollographql/apollo-server/blob/master/CHANGELOG.md) diff --git a/packages/apollo-server-testing/jest.config.js b/packages/apollo-server-testing/jest.config.js new file mode 100644 index 00000000000..a383fbc925f --- /dev/null +++ b/packages/apollo-server-testing/jest.config.js @@ -0,0 +1,3 @@ +const config = require('../../jest.config.base'); + +module.exports = Object.assign(Object.create(null), config); diff --git a/packages/apollo-server-testing/package.json b/packages/apollo-server-testing/package.json new file mode 100644 index 00000000000..7d93995a33f --- /dev/null +++ b/packages/apollo-server-testing/package.json @@ -0,0 +1,32 @@ +{ + "name": "apollo-server-testing", + "version": "2.2.0-alpha.0", + "description": "Test utils for apollo-server", + "main": "dist/index.js", + "types": "dist/index.d.ts", + "repository": { + "type": "git", + "url": "https://github.com/apollographql/apollo-server/tree/master/packages/apollo-server-testing" + }, + "keywords": [ + "GraphQL", + "Apollo", + "Server", + "Javascript" + ], + "author": "Jonas Helfer ", + "license": "MIT", + "bugs": { + "url": "https://github.com/apollographql/apollo-server/issues" + }, + "homepage": "https://github.com/apollographql/apollo-server#readme", + "engines": { + "node": ">=6" + }, + "dependencies": { + "apollo-server-core": "file:../apollo-server-core" + }, + "peerDependencies": { + "graphql": "^0.12.0 || ^0.13.0 || ^14.0.0" + } +} diff --git a/packages/apollo-server-testing/src/__tests__/createTestClient.test.ts b/packages/apollo-server-testing/src/__tests__/createTestClient.test.ts new file mode 100644 index 00000000000..e3fd1c7e06d --- /dev/null +++ b/packages/apollo-server-testing/src/__tests__/createTestClient.test.ts @@ -0,0 +1,81 @@ +import { ApolloServerBase, gql } from 'apollo-server-core'; +import createTestClient from '../createTestClient'; + +describe('createTestClient', () => { + const typeDefs = gql` + type Query { + test(echo: String): String + # this resolver uses context + hello: String + } + + type Mutation { + increment: Int! + } + `; + + const resolvers = { + Query: { + test: (_, { echo }) => echo, + hello: (_, __, { person }) => { + return `hello ${person}`; + }, + }, + Mutation: { + increment: () => 1, + }, + }; + + const myTestServer = new ApolloServerBase({ + typeDefs, + context: () => ({ person: 'tom' }), + resolvers, + }); + + it('allows queries', async () => { + const query = `{ test(echo: "foo") }`; + const client = createTestClient(myTestServer); + const res = await client.query({ query }); + expect(res.data).toEqual({ test: 'foo' }); + }); + + it('allows mutations', async () => { + const mutation = `mutation increment { increment }`; + const client = createTestClient(myTestServer); + const res = await client.mutate({ mutation }); + expect(res.data).toEqual({ increment: 1 }); + }); + + it('allows variables to be passed', async () => { + const query = `query test($echo: String){ test(echo: $echo) }`; + const client = createTestClient(myTestServer); + const res = await client.query({ query, variables: { echo: 'wow' } }); + expect(res.data).toEqual({ test: 'wow' }); + }); + + it('resolves with context', async () => { + const query = `{ hello }`; + const client = createTestClient(myTestServer); + const res = await client.query({ query }); + expect(res.data).toEqual({ hello: 'hello tom' }); + }); + + it('allows query documents as input', async () => { + const query = gql` + { + test(echo: "foo") + } + `; + const client = createTestClient(myTestServer); + const clientRes = await client.query({ query }); + expect(clientRes.data).toEqual({ test: 'foo' }); + + const mutation = gql` + mutation increment { + increment + } + `; + const mutationRes = await client.mutate({ mutation }); + expect(mutationRes.data).toEqual({ increment: 1 }); + }); +}); diff --git a/packages/apollo-server-testing/src/__tests__/tsconfig.json b/packages/apollo-server-testing/src/__tests__/tsconfig.json new file mode 100644 index 00000000000..2f3a365cbfc --- /dev/null +++ b/packages/apollo-server-testing/src/__tests__/tsconfig.json @@ -0,0 +1,5 @@ +{ + "extends": "../../../../tsconfig.test.base", + "include": ["**/*"], + "references": [] +} diff --git a/packages/apollo-server-testing/src/createTestClient.ts b/packages/apollo-server-testing/src/createTestClient.ts new file mode 100644 index 00000000000..15c82a18170 --- /dev/null +++ b/packages/apollo-server-testing/src/createTestClient.ts @@ -0,0 +1,28 @@ +import { ApolloServerBase } from 'apollo-server-core'; +import { print, DocumentNode } from 'graphql'; + +type StringOrAst = string | DocumentNode; +interface QueryOrMutation { + query?: StringOrAst; + mutation?: StringOrAst; +} + +export default (server: ApolloServerBase) => { + const executeOperation = server.executeOperation.bind(server); + const test = ({ query, mutation, ...args }: QueryOrMutation) => { + const operation = query || mutation; + + if ((!query && !mutation) || (query && mutation)) { + throw new Error('Either `query` or `mutation` must be passed'); + } + + return executeOperation({ + // Convert ASTs, which are produced by `graphql-tag` but not currently + // used by `executeOperation`, to a String using `graphql/language/print`. + query: typeof operation === 'string' ? operation : print(operation), + ...args, + }); + }; + + return { query: test, mutate: test }; +}; diff --git a/packages/apollo-server-testing/src/index.ts b/packages/apollo-server-testing/src/index.ts new file mode 100644 index 00000000000..acd8c5f2b2b --- /dev/null +++ b/packages/apollo-server-testing/src/index.ts @@ -0,0 +1 @@ +export { default as createTestClient } from './createTestClient'; diff --git a/packages/apollo-server-testing/tsconfig.json b/packages/apollo-server-testing/tsconfig.json new file mode 100644 index 00000000000..dcf69da0397 --- /dev/null +++ b/packages/apollo-server-testing/tsconfig.json @@ -0,0 +1,12 @@ +{ + "extends": "../../tsconfig.base", + "compilerOptions": { + "rootDir": "./src", + "outDir": "./dist" + }, + "include": ["src/**/*"], + "exclude": ["**/__tests__", "**/__mocks__"], + "references": [ + { "path": "../apollo-server-core" } + ] +} diff --git a/tsconfig.build.json b/tsconfig.build.json index 09db1dd58d5..39809dba39e 100644 --- a/tsconfig.build.json +++ b/tsconfig.build.json @@ -22,6 +22,7 @@ { "path": "./packages/apollo-server-lambda" }, { "path": "./packages/apollo-server-micro" }, { "path": "./packages/apollo-server-plugin-base" }, + { "path": "./packages/apollo-server-testing" }, { "path": "./packages/apollo-tracing" }, { "path": "./packages/graphql-extensions" }, ]