From 7535c0f154a0dca981840fa45bd543229bd7802b Mon Sep 17 00:00:00 2001 From: Slava Kim Date: Thu, 26 May 2016 14:10:15 -0700 Subject: [PATCH 1/2] Remove apolloServer from the repo --- src/apolloServer.js | 246 +----- test/testApolloServer.js | 513 ------------ test/testApolloServerHTTP.js | 1437 ---------------------------------- test/tests.js | 2 - 4 files changed, 3 insertions(+), 2195 deletions(-) delete mode 100644 test/testApolloServer.js delete mode 100644 test/testApolloServerHTTP.js diff --git a/src/apolloServer.js b/src/apolloServer.js index 998c555ff14..ba20dffc391 100644 --- a/src/apolloServer.js +++ b/src/apolloServer.js @@ -1,247 +1,7 @@ -import { - makeExecutableSchema, - buildSchemaFromTypeDefinitions, - addErrorLoggingToSchema, - addCatchUndefinedToSchema, - addResolveFunctionsToSchema, - addTracingToResolvers, -} from './schemaGenerator'; -import { addMockFunctionsToSchema } from './mock'; -import graphqlHTTP from 'express-widgetizer'; -import { GraphQLSchema, formatError } from 'graphql'; +// This file only exists for backwards-compatibility -// TODO this implementation could use a bit of refactoring. -// it turned from a simple function into something promise-based, -// which means the structure is now quite awkward. - -export default function apolloServer(options, ...rest) { - if (!options) { - throw new Error('GraphQL middleware requires options.'); - } - if (rest.length > 0) { - throw new Error(`apolloServer expects exactly one argument, got ${rest.length + 1}`); - } - // Resolve the Options to get OptionsData. - - return (req, res) => { - let tracerLogger; - - // TODO instrument ApolloServer's schema creation as well, so you know how long - // it takes. May be a big waste of time to recreate the schema for every request. - - return new Promise(resolve => { - resolve(typeof options === 'function' ? options(req) : options); - }).then(optionsData => { - // Assert that optionsData is in fact an Object. - if (!optionsData || typeof optionsData !== 'object') { - throw new Error( - 'GraphQL middleware option function must return an options object.' - ); - } - - // Assert that schema is required. - if (!optionsData.schema) { - throw new Error( - 'GraphQL middleware options must contain a schema.' - ); - } - const { - schema, // required - resolvers, // required if mocks is not false and schema is not GraphQLSchema - connectors, // required if mocks is not false and schema is not GraphQLSchema - logger, - tracer, - printErrors, - mocks = false, - allowUndefinedInResolve = true, - pretty, // pass through - graphiql = false, // pass through - validationRules, // pass through - context = {}, // pass through, but add tracer if applicable - rootValue, // pass through - } = optionsData; - - // would collide with formatError from graphql otherwise - const formatErrorFn = optionsData.formatError; - - // TODO: currently relies on the fact that start and end both exist - // and appear in the correct order and exactly once. - function processInterval(supertype, subtype, tstamp, intervalMap) { - if (subtype === 'start') { - // eslint-disable-next-line no-param-reassign - intervalMap[supertype] = tstamp; - } - if (subtype === 'end') { - // eslint-disable-next-line no-param-reassign - intervalMap[supertype] = tstamp - intervalMap[supertype]; - } - } - - let executableSchema; - if (mocks) { - // TODO: mocks doesn't yet work with a normal GraphQL schema, but it should! - // have to rewrite these functions - const myMocks = mocks || {}; - executableSchema = buildSchemaFromTypeDefinitions(schema); - addResolveFunctionsToSchema(executableSchema, resolvers || {}); - addMockFunctionsToSchema({ - schema: executableSchema, - mocks: myMocks, - }); - } else { - // this is just basics, makeExecutableSchema should catch the rest - // TODO: should be able to provide a GraphQLschema and still use resolvers - // and connectors if you want, but at the moment this is not possible. - if (schema instanceof GraphQLSchema) { - if (logger) { - addErrorLoggingToSchema(schema, logger); - } - if (printErrors) { - addErrorLoggingToSchema(schema, { log: (e) => console.error(e.stack) }); - } - if (!allowUndefinedInResolve) { - addCatchUndefinedToSchema(schema); - } - executableSchema = schema; - } else { - if (!resolvers) { - // TODO: test this error - throw new Error('resolvers is required option if mocks is not provided'); - } - executableSchema = makeExecutableSchema({ - typeDefs: schema, - resolvers, - connectors, - logger, - allowUndefinedInResolve, - }); - if (printErrors) { - addErrorLoggingToSchema(executableSchema, { log: (e) => console.error(e.stack) }); - } - } - } - - // Tracer-related stuff ------------------------------------------------ - - tracerLogger = { log: undefined, report: undefined }; - if (tracer) { - tracerLogger = tracer.newLoggerInstance(); - tracerLogger.log('request.info', { - headers: req.headers, - baseUrl: req.baseUrl, - originalUrl: req.originalUrl, - method: req.method, - httpVersion: req.httpVersion, - remoteAddr: req.connection.remoteAddress, - }); - if (context.tracer) { - throw new Error('Property tracer on context already defined, cannot attach Tracer'); - } else { - context.tracer = tracerLogger; - } - if (!executableSchema._apolloTracerApplied) { - addTracingToResolvers(executableSchema); - } - } - - // TODO: move to proper place, make less fragile ... - // calculate timing information from events - function timings(events) { - const resolverDurations = []; - const intervalMap = {}; - - // split by event.type = [ , ] - events.forEach(e => { - const [supertype, subtype] = e.type.split('.'); - switch (supertype) { - case 'request': - case 'parse': - case 'validation': - case 'execution': - case 'parseBody': - case 'parseParams': - processInterval(supertype, subtype, e.timestamp, intervalMap); - break; - case 'resolver': - if (subtype === 'end') { - resolverDurations.push({ - type: 'resolve', - functionName: e.data.functionName, - duration: e.timestamp - events[e.data.startEventId].timestamp, - }); - } - break; - default: - console.error(`Unknown event type ${supertype}`); - } - }); - - const durations = []; - Object.keys(intervalMap).forEach((key) => { - durations.push({ - type: key, - functionName: null, - duration: intervalMap[key], - }); - }); - return durations.concat(resolverDurations); - } - - let extensionsFn = function extensionsFn() { - try { - return { - timings: timings(tracerLogger.report().events), - tracer: tracerLogger.report().events.map(e => ({ - id: e.id, - type: e.type, - ts: e.timestamp, - data: e.data, - })).filter(x => x.type !== 'initialization'), - }; - } catch (e) { - console.error(e); - console.error(e.stack); - } - return {}; - }; - - // XXX ugly way of only passing extensionsFn when tracer is defined. - if (!tracer || req.headers['x-apollo-tracer-extension'] !== 'on') { - extensionsFn = undefined; - } - - // end of Tracer related stuff ------------------------------------------- - - // graphQLHTTPOptions - return { - schema: executableSchema, - pretty, - formatError: formatErrorFn, - validationRules, - context, - rootValue, - graphiql, - logFn: tracerLogger.log, - extensionsFn, - }; - }).then((graphqlHTTPOptions) => { - return graphqlHTTP(graphqlHTTPOptions)(req, res); - }).catch(error => { - // express-graphql catches its own errors, this is just for - // errors in Apollo-server. - // XXX we should probably care about formatErrorFn and pretty. - res.status(error.status || 500); - const result = { errors: [error] }; - result.errors = result.errors.map(formatError); - res - .set('Content-Type', 'application/json') - .send(JSON.stringify(result)); - return result; - }).then((result) => { - // send traces to Apollo Tracer - tracerLogger.submit(); - }); - }; +export default function apolloServer() { + throw new Error('apolloServer has been moved to a separate module. See: https://github.com/apollostack/apollo-server'); } export { apolloServer }; diff --git a/test/testApolloServer.js b/test/testApolloServer.js deleted file mode 100644 index d591d0dfe6c..00000000000 --- a/test/testApolloServer.js +++ /dev/null @@ -1,513 +0,0 @@ -import { apolloServer } from '../src/apolloServer'; -import { MockList } from '../src/mock'; -import { makeExecutableSchema } from '../src/schemaGenerator'; -import { Tracer } from '../src/tracing'; -import { expect } from 'chai'; -import express from 'express'; -import request from 'supertest-as-promised'; - -const testSchema = ` - type RootQuery { - usecontext: String - useTestConnector: String - species(name: String): String - stuff: String - errorField: String - undefinedField: String - } - schema { - query: RootQuery - } - `; -const testResolvers = { - __schema: () => { - return { stuff: 'stuff', species: 'ROOT' }; - }, - RootQuery: { - usecontext: (r, a, ctx) => { - return ctx.usecontext; - }, - useTestConnector: (r, a, ctx) => { - return ctx.connectors.TestConnector.get(); - }, - species: (root, { name }) => root.species + name, - errorField: () => { - throw new Error('throws error'); - }, - }, -}; -class TestConnector { - get() { - return 'works'; - } -} -const testConnectors = { - TestConnector, -}; - -const server = apolloServer({ - schema: testSchema, - resolvers: testResolvers, - connectors: testConnectors, -}); - -// XXX this app key is not really a secret. It's here so we can either log it -// or filter it out. -const t1 = new Tracer({ TRACER_APP_KEY: 'BDE05C83-E58F-4837-8D9A-9FB5EA605D2A' }); - -const serverWithTracer = apolloServer({ - schema: testSchema, - resolvers: testResolvers, - connectors: testConnectors, - tracer: t1, -}); - -const jsSchema = makeExecutableSchema({ - typeDefs: testSchema, - resolvers: testResolvers, - connectors: testConnectors, -}); -const vanillaServerWithTracer = apolloServer({ - schema: jsSchema, - tracer: t1, -}); - -describe('ApolloServer', () => { - it('can serve a basic request', () => { - const app = express(); - app.use('/graphql', server); - const expected = { - stuff: 'stuff', - useTestConnector: 'works', - species: 'ROOTuhu', - }; - return request(app).get( - '/graphql?query={stuff useTestConnector species(name: "uhu")}' - ).then((res) => { - return expect(res.body.data).to.deep.equal(expected); - }); - }); - it('can add tracer', () => { - const app = express(); - app.use('/graphql', serverWithTracer); - const expected = { - stuff: 'stuff', - useTestConnector: 'works', - species: 'ROOTuhu', - }; - return request(app) - .get( - '/graphql?query={stuff useTestConnector species(name: "uhu")}' - ) - .set('X-Apollo-Tracer-Extension', 'on') - .then((res) => { - // TODO: this test is silly. actually test the output - expect(res.body.extensions.timings.length).to.equal(9); - return expect(res.body.data).to.deep.equal(expected); - }); - }); - it('does not return traces unless you ask it to', () => { - const app = express(); - app.use('/graphql', serverWithTracer); - const expected = { - stuff: 'stuff', - useTestConnector: 'works', - species: 'ROOTuhu', - }; - return request(app) - .get( - '/graphql?query={stuff useTestConnector species(name: "uhu")}' - ) - .then((res) => { - // eslint-disable-next-line no-unused-expressions - expect(res.body.extensions).to.be.undefined; - return expect(res.body.data).to.deep.equal(expected); - }); - }); - it('can add tracer to a graphql-js schema', () => { - const app = express(); - app.use('/graphql', vanillaServerWithTracer); - const expected = { - stuff: 'stuff', - useTestConnector: 'works', - species: 'ROOTuhu', - }; - return request(app).get( - '/graphql?query={stuff useTestConnector species(name: "uhu")}' - ) - .set('X-Apollo-Tracer-Extension', 'on') - .then((res) => { - // TODO: this test is silly. actually test the output - expect(res.body.extensions.timings.length).to.equal(9); - return expect(res.body.data).to.deep.equal(expected); - }); - }); - - it('logs tracer events', () => { - const realSendReport = t1.sendReport; - let interceptedReport; - t1.sendReport = (report) => { interceptedReport = report; }; - - const app = express(); - app.use('/graphql', serverWithTracer); - const expected = { - stuff: 'stuff', - useTestConnector: 'works', - species: 'ROOTuhu', - }; - return request(app).get( - '/graphql?query={stuff useTestConnector species(name: "uhu")}' - ) - .set('X-Apollo-Tracer-Extension', 'on') - .then((res) => { - // TODO can have race conditions here if executing tests in parallel? - // probably better to set up separate tracer instance for this. - t1.sendReport = realSendReport; - // TODO: this test is silly. actually test the output - expect(res.body.extensions.timings.length).to.equal(9); - expect(interceptedReport.events.length).to.equal(24); - return expect(res.body.data).to.deep.equal(expected); - }); - }); - - it('throws an error if schema is shorthand and resolvers not defined', () => { - const app = express(); - const verySadServer = apolloServer({ - schema: testSchema, - }); - app.use('/graphql', verySadServer); - return request(app).get( - '/graphql?query={stuff}' - ).then((res) => { - expect(res.status).to.equal(500); - return expect(res.error.text).to.equal( - '{"errors":[{"message":"resolvers is required option if mocks is not provided"}]}' - ); - }); - }); - it('can mock a schema', () => { - const app = express(); - const mockServer = apolloServer({ - schema: testSchema, - mocks: { - RootQuery: () => ({ - stuff: () => 'stuffs', - useTestConnector: () => 'utc', - species: 'rawr', - }), - }, - }); - app.use('/graphql', mockServer); - const expected = { - stuff: 'stuffs', - useTestConnector: 'utc', - species: 'rawr', - }; - return request(app).get( - '/graphql?query={stuff useTestConnector species(name: "uhu")}' - ).then((res) => { - return expect(res.body.data).to.deep.equal(expected); - }); - }); - it('can mock a schema with unions', () => { - const app = express(); - const schema = ` - enum SomeEnum { - X - Y - Z - } - type A { - a: SomeEnum! - } - type B { - b: Int! - } - union C = A | B - type Query { - someCs: [C] - } - schema { - query: Query - } - `; - const mockServer = apolloServer({ - schema, - resolvers: { - C: { - __resolveType(data, ctx, info) { - return info.schema.getType(data.typename); - }, - }, - }, - mocks: { - Int: () => 10, - SomeEnum: () => 'X', - Query: () => ({ - someCs: () => new MockList(40), - }), - }, - }); - app.use('/graphql', mockServer); - return request(app).get( - '/graphql?query={someCs {... on A {a} ... on B {b}}}' - ).then((res) => { - const someCs = res.body.data.someCs; - expect(someCs).to.include({a: 'X'}); - return expect(someCs).to.include({b: 10}); - }); - }); - it('can log errors', () => { - const app = express(); - let lastError; - const loggy = { log: (e) => { lastError = e.originalMessage; } }; - const logServer = apolloServer({ - schema: testSchema, - resolvers: testResolvers, - connectors: testConnectors, - logger: loggy, - }); - app.use('/graphql', logServer); - return request(app).get( - '/graphql?query={errorField}' - ).then(() => { - return expect(lastError).to.equal('throws error'); - }); - }); - - it('can log errors with a graphQL-JS schema', () => { - const app = express(); - let lastError; - const loggy = { log: (e) => { lastError = e.originalMessage; } }; - const jsSchema = makeExecutableSchema({ - typeDefs: testSchema, - resolvers: testResolvers, - connectors: testConnectors, - }); - const logServer = apolloServer({ - schema: jsSchema, - logger: loggy, - }); - app.use('/graphql', logServer); - return request(app).get( - '/graphql?query={errorField}' - ).then(() => { - return expect(lastError).to.equal('throws error'); - }); - }); - it('can forbid undefined errors', () => { - const app = express(); - let lastError; - const loggy = { log: (e) => { lastError = e.originalMessage; } }; - const logServer = apolloServer({ - schema: testSchema, - resolvers: testResolvers, - connectors: testConnectors, - logger: loggy, - allowUndefinedInResolve: false, - }); - app.use('/graphql', logServer); - return request(app).get( - '/graphql?query={undefinedField}' - ).then(() => { - return expect(lastError).to.equal( - 'Resolve function for "RootQuery.undefinedField" returned undefined' - ); - }); - }); - it('can forbid undefined with a graphQL-JS schema', () => { - const app = express(); - let lastError; - const loggy = { log: (e) => { lastError = e.originalMessage; } }; - const jsSchema = makeExecutableSchema({ - typeDefs: testSchema, - resolvers: testResolvers, - connectors: testConnectors, - }); - const logServer = apolloServer({ - schema: jsSchema, - allowUndefinedInResolve: false, - logger: loggy, - }); - app.use('/graphql', logServer); - return request(app).get( - '/graphql?query={undefinedField}' - ).then(() => { - return expect(lastError).to.equal( - 'Resolve function for "RootQuery.undefinedField" returned undefined' - ); - }); - }); - it('can print errors for you with a shorthand schema', () => { - const app = express(); - let lastError; - const realConsoleError = console.error; - console.error = (e) => { lastError = e; }; - const printServer = apolloServer({ - schema: testSchema, - resolvers: testResolvers, - connectors: testConnectors, - allowUndefinedInResolve: false, - printErrors: true, - }); - app.use('/graphql', printServer); - return request(app).get( - '/graphql?query={undefinedField}' - ).then(() => { - return expect(lastError).to.match(/Error/); - }).finally(() => { - console.error = realConsoleError; - }); - }); - it('can print errors for you with a graphQL-JS schema', () => { - const app = express(); - let lastError; - const realConsoleError = console.error; - console.error = (e) => { lastError = e; }; - const jsSchema = makeExecutableSchema({ - typeDefs: testSchema, - resolvers: testResolvers, - connectors: testConnectors, - }); - const logServer = apolloServer({ - schema: jsSchema, - allowUndefinedInResolve: false, - printErrors: true, - }); - app.use('/graphql', logServer); - return request(app).get( - '/graphql?query={undefinedField}' - ).then(() => { - return expect(lastError).to.match(/Error/); - }).finally(() => { - console.error = realConsoleError; - }); - }); - it('can forbid undefined with a graphQL-JS schema', () => { - const app = express(); - let lastError; - const loggy = { log: (e) => { lastError = e.originalMessage; } }; - const jsSchema = makeExecutableSchema({ - typeDefs: testSchema, - resolvers: testResolvers, - connectors: testConnectors, - }); - const logServer = apolloServer({ - schema: jsSchema, - allowUndefinedInResolve: false, - logger: loggy, - }); - app.use('/graphql', logServer); - return request(app).get( - '/graphql?query={undefinedField}' - ).then(() => { - return expect(lastError).to.equal( - 'Resolve function for "RootQuery.undefinedField" returned undefined' - ); - }); - }); - // TODO: test wrong arguments error messages - it('throws an error if you call it with more than one arg', () => { - return expect(() => apolloServer(1, 2)).to.throw( - 'apolloServer expects exactly one argument, got 2' - ); - }); - - // express-graphql tests: - - describe('(express-grapqhl) Useful errors when incorrectly used', () => { - it('requires an option factory function', () => { - expect(() => { - apolloServer(); - }).to.throw( - 'GraphQL middleware requires options.' - ); - }); - - it('requires option factory function to return object', async () => { - var app = express(); - - app.use('/graphql', apolloServer(() => null)); - - var caughtError; - var response; - try { - response = await request(app).get('/graphql?query={test}'); - } catch (error) { - caughtError = error; - } - - expect(response.status).to.equal(500); - expect(JSON.parse(response.error.text)).to.deep.equal({ - errors: [ - { message: - 'GraphQL middleware option function must return an options object.' } - ] - }); - }); - - it('requires option factory function to return object or promise of object', async () => { - var app = express(); - - app.use('/graphql', apolloServer(() => Promise.resolve(null))); - - var caughtError; - var response; - try { - response = await request(app).get('/graphql?query={test}'); - } catch (error) { - caughtError = error; - } - - expect(response.status).to.equal(500); - expect(JSON.parse(response.error.text)).to.deep.equal({ - errors: [ - { message: - 'GraphQL middleware option function must return an options object.' } - ] - }); - }); - - it('requires option factory function to return object with schema', async () => { - var app = express(); - - app.use('/graphql', apolloServer(() => ({}))); - - var caughtError; - var response; - try { - response = await request(app).get('/graphql?query={test}'); - } catch (error) { - caughtError = error; - } - - expect(response.status).to.equal(500); - expect(JSON.parse(response.error.text)).to.deep.equal({ - errors: [ - { message: 'GraphQL middleware options must contain a schema.' } - ] - }); - }); - - it('requires option factory function to return object or promise of object with schema', async () => { - var app = express(); - - app.use('/graphql', apolloServer(() => Promise.resolve({}))); - - var caughtError; - var response; - try { - response = await request(app).get('/graphql?query={test}'); - } catch (error) { - caughtError = error; - } - - expect(response.status).to.equal(500); - expect(JSON.parse(response.error.text)).to.deep.equal({ - errors: [ - { message: 'GraphQL middleware options must contain a schema.' } - ] - }); - }); - }); -}); diff --git a/test/testApolloServerHTTP.js b/test/testApolloServerHTTP.js deleted file mode 100644 index 8f9f17f0f4d..00000000000 --- a/test/testApolloServerHTTP.js +++ /dev/null @@ -1,1437 +0,0 @@ -/* - * Below are the HTTP tests from express-graphql. We're using them here to make - * sure apolloServer still works if used in the place of express-graphql. - */ - -import { apolloServer } from '../src/apolloServer'; -const graphqlHTTP = apolloServer; - - // TODO: test that it accepts a promise as input object. - // XXX: how annoying will it be to keep these tests up to date for every - // release of graphql-http? - -/* @flow */ -/** - * Copyright (c) 2015, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ - -// 80+ char lines are useful in describe/it, so ignore in this file. -/* eslint-disable max-len */ - -import { expect } from 'chai'; -import { describe, it } from 'mocha'; -import { stringify } from 'querystring'; -import zlib from 'zlib'; -import multer from 'multer'; -import bodyParser from 'body-parser'; -import request from 'supertest-as-promised'; -import express4 from 'express'; // modern -import express3 from 'express3'; // old but commonly still used -import { - GraphQLSchema, - GraphQLObjectType, - GraphQLNonNull, - GraphQLString, - GraphQLError, - BREAK -} from 'graphql'; - -var QueryRootType = new GraphQLObjectType({ - name: 'QueryRoot', - fields: { - test: { - type: GraphQLString, - args: { - who: { - type: GraphQLString - } - }, - resolve: (root, { who }) => 'Hello ' + (who || 'World') - }, - thrower: { - type: new GraphQLNonNull(GraphQLString), - resolve: () => { throw new Error('Throws!'); } - }, - context: { - type: GraphQLString, - resolve: (obj, args, context) => context, - } - } -}); - -var TestSchema = new GraphQLSchema({ - query: QueryRootType, - mutation: new GraphQLObjectType({ - name: 'MutationRoot', - fields: { - writeTest: { - type: QueryRootType, - resolve: () => ({}) - } - } - }) -}); - -function urlString(urlParams) { - var string = '/graphql'; - if (urlParams) { - string += ('?' + stringify(urlParams)); - } - return string; -} - -function catchError(p) { - return p.then( - (res) => { - // workaround for unkown issues with testing against npm package of express-graphql. - // the same code works when testing against the source, I'm not sure why. - if (res && res.error) { - return { response: res }; - } - throw new Error('Expected to catch error.'); - }, - error => { - if (!(error instanceof Error)) { - throw new Error('Expected error to be instanceof Error.'); - } - return error; - } - ); -} - -function promiseTo(fn) { - return new Promise((resolve, reject) => { - fn((error, result) => error ? reject(error) : resolve(result)); - }); -} - -describe('test harness', () => { - - it('expects to catch errors', async () => { - var caught; - try { - await catchError(Promise.resolve()); - } catch (error) { - caught = error; - } - expect(caught && caught.message).to.equal('Expected to catch error.'); - }); - - it('expects to catch actual errors', async () => { - var caught; - try { - await catchError(Promise.reject('not a real error')); - } catch (error) { - caught = error; - } - expect(caught && caught.message).to.equal('Expected error to be instanceof Error.'); - }); - - it('resolves callback promises', async () => { - var resolveValue = {}; - var result = await promiseTo(cb => cb(null, resolveValue)); - expect(result).to.equal(resolveValue); - }); - - it('rejects callback promises with errors', async () => { - var rejectError = new Error(); - var caught; - try { - await promiseTo(cb => cb(rejectError)); - } catch (error) { - caught = error; - } - expect(caught).to.equal(rejectError); - }); - -}); - -[[ express4, 'modern' ], [ express3, 'old' ]].forEach(([ express, version ]) => { - describe(`GraphQL-HTTP (apolloServer) tests for ${version} express`, () => { - describe('GET functionality', () => { - it('allows GET with query param', async () => { - var app = express(); - - app.use(urlString(), graphqlHTTP({ - schema: TestSchema - })); - - var response = await request(app) - .get(urlString({ - query: '{test}' - })); - - expect(response.text).to.equal( - '{"data":{"test":"Hello World"}}' - ); - }); - - it('allows GET with variable values', async () => { - var app = express(); - - app.use(urlString(), graphqlHTTP({ - schema: TestSchema - })); - - var response = await request(app) - .get(urlString({ - query: 'query helloWho($who: String){ test(who: $who) }', - variables: JSON.stringify({ who: 'Dolly' }) - })); - - expect(response.text).to.equal( - '{"data":{"test":"Hello Dolly"}}' - ); - }); - - it('allows GET with operation name', async () => { - var app = express(); - - app.use(urlString(), graphqlHTTP(() => ({ - schema: TestSchema - }))); - - var response = await request(app) - .get(urlString({ - query: ` - query helloYou { test(who: "You"), ...shared } - query helloWorld { test(who: "World"), ...shared } - query helloDolly { test(who: "Dolly"), ...shared } - fragment shared on QueryRoot { - shared: test(who: "Everyone") - } - `, - operationName: 'helloWorld' - })); - - expect(JSON.parse(response.text)).to.deep.equal({ - data: { - test: 'Hello World', - shared: 'Hello Everyone', - } - }); - }); - - it('Reports validation errors', async () => { - var app = express(); - - app.use(urlString(), graphqlHTTP({ schema: TestSchema })); - - var error = await catchError( - request(app) - .get(urlString({ - query: `{ test, unknownOne, unknownTwo }` - })) - ); - - expect(error.response.status).to.equal(400); - expect(JSON.parse(error.response.text)).to.deep.equal({ - errors: [ - { - message: 'Cannot query field "unknownOne" on type "QueryRoot".', - locations: [ { line: 1, column: 9 } ] - }, - { - message: 'Cannot query field "unknownTwo" on type "QueryRoot".', - locations: [ { line: 1, column: 21 } ] - } - ] - }); - }); - - it('Errors when missing operation name', async () => { - var app = express(); - - app.use(urlString(), graphqlHTTP({ schema: TestSchema })); - - var error = await catchError( - request(app) - .get(urlString({ - query: ` - query TestQuery { test } - mutation TestMutation { writeTest { test } } - ` - })) - ); - - expect(error.response.status).to.equal(400); - expect(JSON.parse(error.response.text)).to.deep.equal({ - errors: [ - { message: 'Must provide operation name if query contains multiple operations.' } - ] - }); - }); - - it('Errors when sending a mutation via GET', async () => { - var app = express(); - - app.use(urlString(), graphqlHTTP({ schema: TestSchema })); - - var error = await catchError( - request(app) - .get(urlString({ - query: 'mutation TestMutation { writeTest { test } }' - })) - ); - - expect(error.response.status).to.equal(405); - expect(JSON.parse(error.response.text)).to.deep.equal({ - errors: [ - { message: 'Can only perform a mutation operation from a POST request.' } - ] - }); - }); - - it('Errors when selecting a mutation within a GET', async () => { - var app = express(); - - app.use(urlString(), graphqlHTTP({ schema: TestSchema })); - - var error = await catchError( - request(app) - .get(urlString({ - operationName: 'TestMutation', - query: ` - query TestQuery { test } - mutation TestMutation { writeTest { test } } - ` - })) - ); - - expect(error.response.status).to.equal(405); - expect(JSON.parse(error.response.text)).to.deep.equal({ - errors: [ - { message: 'Can only perform a mutation operation from a POST request.' } - ] - }); - }); - - it('Allows a mutation to exist within a GET', async () => { - var app = express(); - - app.use(urlString(), graphqlHTTP({ schema: TestSchema })); - - var response = await request(app) - .get(urlString({ - operationName: 'TestQuery', - query: ` - mutation TestMutation { writeTest { test } } - query TestQuery { test } - ` - })); - - expect(response.status).to.equal(200); - expect(JSON.parse(response.text)).to.deep.equal({ - data: { - test: 'Hello World' - } - }); - }); - - it('Allows passing in a context', async () => { - var app = express(); - - app.use(urlString(), graphqlHTTP({ - schema: TestSchema, - context: 'testValue' - })); - - var response = await request(app) - .get(urlString({ - operationName: 'TestQuery', - query: ` - query TestQuery { context } - ` - })); - - expect(response.status).to.equal(200); - expect(JSON.parse(response.text)).to.deep.equal({ - data: { - context: 'testValue' - } - }); - }); - - it('Allows returning an options Promise', async () => { - var app = express(); - - app.use(urlString(), graphqlHTTP(() => Promise.resolve({ - schema: TestSchema, - }))); - - var response = await request(app) - .get(urlString({ - query: '{test}' - })); - - expect(response.text).to.equal( - '{"data":{"test":"Hello World"}}' - ); - }); - - }); - - describe('POST functionality', () => { - it('allows POST with JSON encoding', async () => { - var app = express(); - - app.use(urlString(), graphqlHTTP({ - schema: TestSchema - })); - - var response = await request(app) - .post(urlString()).send({ query: '{test}' }); - - expect(response.text).to.equal( - '{"data":{"test":"Hello World"}}' - ); - }); - - it('Allows sending a mutation via POST', async () => { - var app = express(); - - app.use(urlString(), graphqlHTTP({ schema: TestSchema })); - - var response = await request(app) - .post(urlString()) - .send({ query: 'mutation TestMutation { writeTest { test } }' }); - - expect(response.status).to.equal(200); - expect(response.text).to.equal( - '{"data":{"writeTest":{"test":"Hello World"}}}' - ); - }); - - it('allows POST with url encoding', async () => { - var app = express(); - - app.use(urlString(), graphqlHTTP({ - schema: TestSchema - })); - - var response = await request(app) - .post(urlString()) - .send(stringify({ query: '{test}' })); - - expect(response.text).to.equal( - '{"data":{"test":"Hello World"}}' - ); - }); - - it('supports POST JSON query with string variables', async () => { - var app = express(); - - app.use(urlString(), graphqlHTTP({ - schema: TestSchema - })); - - var response = await request(app) - .post(urlString()) - .send({ - query: 'query helloWho($who: String){ test(who: $who) }', - variables: JSON.stringify({ who: 'Dolly' }) - }); - - expect(response.text).to.equal( - '{"data":{"test":"Hello Dolly"}}' - ); - }); - - it('supports POST JSON query with JSON variables', async () => { - var app = express(); - - app.use(urlString(), graphqlHTTP({ - schema: TestSchema - })); - - var response = await request(app) - .post(urlString()) - .send({ - query: 'query helloWho($who: String){ test(who: $who) }', - variables: { who: 'Dolly' } - }); - - expect(response.text).to.equal( - '{"data":{"test":"Hello Dolly"}}' - ); - }); - - it('supports POST url encoded query with string variables', async () => { - var app = express(); - - app.use(urlString(), graphqlHTTP({ - schema: TestSchema - })); - - var response = await request(app) - .post(urlString()) - .send(stringify({ - query: 'query helloWho($who: String){ test(who: $who) }', - variables: JSON.stringify({ who: 'Dolly' }) - })); - - expect(response.text).to.equal( - '{"data":{"test":"Hello Dolly"}}' - ); - }); - - it('supports POST JSON query with GET variable values', async () => { - var app = express(); - - app.use(urlString(), graphqlHTTP({ - schema: TestSchema - })); - - var response = await request(app) - .post(urlString({ - variables: JSON.stringify({ who: 'Dolly' }) - })) - .send({ query: 'query helloWho($who: String){ test(who: $who) }' }); - - expect(response.text).to.equal( - '{"data":{"test":"Hello Dolly"}}' - ); - }); - - it('supports POST url encoded query with GET variable values', async () => { - var app = express(); - - app.use(urlString(), graphqlHTTP({ - schema: TestSchema - })); - - var response = await request(app) - .post(urlString({ - variables: JSON.stringify({ who: 'Dolly' }) - })) - .send(stringify({ - query: 'query helloWho($who: String){ test(who: $who) }' - })); - - expect(response.text).to.equal( - '{"data":{"test":"Hello Dolly"}}' - ); - }); - - it('supports POST raw text query with GET variable values', async () => { - var app = express(); - - app.use(urlString(), graphqlHTTP({ - schema: TestSchema - })); - - var response = await request(app) - .post(urlString({ - variables: JSON.stringify({ who: 'Dolly' }) - })) - .set('Content-Type', 'application/graphql') - .send('query helloWho($who: String){ test(who: $who) }'); - - expect(response.text).to.equal( - '{"data":{"test":"Hello Dolly"}}' - ); - }); - - it('allows POST with operation name', async () => { - var app = express(); - - app.use(urlString(), graphqlHTTP(() => ({ - schema: TestSchema - }))); - - var response = await request(app) - .post(urlString()) - .send({ - query: ` - query helloYou { test(who: "You"), ...shared } - query helloWorld { test(who: "World"), ...shared } - query helloDolly { test(who: "Dolly"), ...shared } - fragment shared on QueryRoot { - shared: test(who: "Everyone") - } - `, - operationName: 'helloWorld' - }); - - expect(JSON.parse(response.text)).to.deep.equal({ - data: { - test: 'Hello World', - shared: 'Hello Everyone', - } - }); - }); - - it('allows POST with GET operation name', async () => { - var app = express(); - - app.use(urlString(), graphqlHTTP(() => ({ - schema: TestSchema - }))); - - var response = await request(app) - .post(urlString({ - operationName: 'helloWorld' - })) - .set('Content-Type', 'application/graphql') - .send(` - query helloYou { test(who: "You"), ...shared } - query helloWorld { test(who: "World"), ...shared } - query helloDolly { test(who: "Dolly"), ...shared } - fragment shared on QueryRoot { - shared: test(who: "Everyone") - } - `); - - expect(JSON.parse(response.text)).to.deep.equal({ - data: { - test: 'Hello World', - shared: 'Hello Everyone', - } - }); - }); - - it('allows other UTF charsets', async () => { - var app = express(); - - app.use(urlString(), graphqlHTTP(() => ({ - schema: TestSchema - }))); - - var req = request(app) - .post(urlString()) - .set('Content-Type', 'application/graphql; charset=utf-16'); - req.write(new Buffer('{ test(who: "World") }', 'utf16le')); - var response = await req; - - expect(JSON.parse(response.text)).to.deep.equal({ - data: { - test: 'Hello World' - } - }); - }); - - it('allows gzipped POST bodies', async () => { - var app = express(); - - app.use(urlString(), graphqlHTTP(() => ({ - schema: TestSchema - }))); - - var data = { query: '{ test(who: "World") }' }; - var json = JSON.stringify(data); - var gzippedJson = await promiseTo(cb => zlib.gzip(json, cb)); - - var req = request(app) - .post(urlString()) - .set('Content-Type', 'application/json') - .set('Content-Encoding', 'gzip'); - req.write(gzippedJson); - var response = await req; - - expect(JSON.parse(response.text)).to.deep.equal({ - data: { - test: 'Hello World' - } - }); - }); - - it('allows deflated POST bodies', async () => { - var app = express(); - - app.use(urlString(), graphqlHTTP(() => ({ - schema: TestSchema - }))); - - var data = { query: '{ test(who: "World") }' }; - var json = JSON.stringify(data); - var deflatedJson = await promiseTo(cb => zlib.deflate(json, cb)); - - var req = request(app) - .post(urlString()) - .set('Content-Type', 'application/json') - .set('Content-Encoding', 'deflate'); - req.write(deflatedJson); - var response = await req; - - expect(JSON.parse(response.text)).to.deep.equal({ - data: { - test: 'Hello World' - } - }); - }); - - it('allows for pre-parsed POST bodies', async () => { - // Note: this is not the only way to handle file uploads with GraphQL, - // but it is terse and illustrative of using express-graphql and multer - // together. - - // A simple schema which includes a mutation. - var UploadedFileType = new GraphQLObjectType({ - name: 'UploadedFile', - fields: { - originalname: { type: GraphQLString }, - mimetype: { type: GraphQLString } - } - }); - - var TestMutationSchema = new GraphQLSchema({ - query: new GraphQLObjectType({ - name: 'QueryRoot', - fields: { - test: { type: GraphQLString } - } - }), - mutation: new GraphQLObjectType({ - name: 'MutationRoot', - fields: { - uploadFile: { - type: UploadedFileType, - resolve(rootValue) { - // For this test demo, we're just returning the uploaded - // file directly, but presumably you might return a Promise - // to go store the file somewhere first. - return rootValue.request.file; - } - } - } - }) - }); - - var app = express(); - - // Multer provides multipart form data parsing. - var storage = multer.memoryStorage(); - app.use(urlString(), multer({ storage }).single('file')); - - // Providing the request as part of `rootValue` allows it to - // be accessible from within Schema resolve functions. - app.use(urlString(), graphqlHTTP(req => { - return { - schema: TestMutationSchema, - rootValue: { request: req } - }; - })); - - var response = await request(app) - .post(urlString()) - .field('query', `mutation TestMutation { - uploadFile { originalname, mimetype } - }`) - .attach('file', __filename); - - expect(JSON.parse(response.text)).to.deep.equal({ - data: { - uploadFile: { - originalname: 'testApolloServerHTTP.js', - mimetype: 'application/javascript' - } - } - }); - }); - - it('allows for pre-parsed POST using application/graphql', async () => { - var app = express(); - app.use(bodyParser.text({ type: 'application/graphql' })); - - app.use(urlString(), graphqlHTTP({ schema: TestSchema })); - - var req = request(app) - .post(urlString()) - .set('Content-Type', 'application/graphql'); - req.write(new Buffer('{ test(who: "World") }')); - var response = await req; - - expect(JSON.parse(response.text)).to.deep.equal({ - data: { - test: 'Hello World' - } - }); - }); - - it('does not accept unknown pre-parsed POST string', async () => { - var app = express(); - app.use(bodyParser.text({ type: '*/*' })); - - app.use(urlString(), graphqlHTTP({ schema: TestSchema })); - - var req = request(app) - .post(urlString()); - req.write(new Buffer('{ test(who: "World") }')); - var error = await catchError(req); - - expect(error.response.status).to.equal(400); - expect(JSON.parse(error.response.text)).to.deep.equal({ - errors: [ { message: 'Must provide query string.' } ] - }); - }); - - it('does not accept unknown pre-parsed POST raw Buffer', async () => { - var app = express(); - app.use(bodyParser.raw({ type: '*/*' })); - - app.use(urlString(), graphqlHTTP({ schema: TestSchema })); - - var req = request(app) - .post(urlString()) - .set('Content-Type', 'application/graphql'); - req.write(new Buffer('{ test(who: "World") }')); - var error = await catchError(req); - - expect(error.response.status).to.equal(400); - expect(JSON.parse(error.response.text)).to.deep.equal({ - errors: [ { message: 'Must provide query string.' } ] - }); - }); - }); - - describe('Pretty printing', () => { - it('supports pretty printing', async () => { - var app = express(); - - app.use(urlString(), graphqlHTTP({ - schema: TestSchema, - pretty: true - })); - - var response = await request(app) - .get(urlString({ - query: '{test}' - })); - - expect(response.text).to.equal( - '{\n' + - ' "data": {\n' + - ' "test": "Hello World"\n' + - ' }\n' + - '}' - ); - }); - - it('supports pretty printing configured by request', async () => { - var app = express(); - - app.use(urlString(), graphqlHTTP(req => { - return { - schema: TestSchema, - pretty: req.query.pretty === '1' - }; - })); - - var defaultResponse = await request(app) - .get(urlString({ - query: '{test}' - })); - - expect(defaultResponse.text).to.equal( - '{"data":{"test":"Hello World"}}' - ); - - var prettyResponse = await request(app) - .get(urlString({ - query: '{test}', - pretty: 1 - })); - - expect(prettyResponse.text).to.equal( - '{\n' + - ' "data": {\n' + - ' "test": "Hello World"\n' + - ' }\n' + - '}' - ); - - var unprettyResponse = await request(app) - .get(urlString({ - query: '{test}', - pretty: 0 - })); - - expect(unprettyResponse.text).to.equal( - '{"data":{"test":"Hello World"}}' - ); - }); - }); - - describe('Error handling functionality', () => { - it('handles field errors caught by GraphQL', async () => { - var app = express(); - - app.use(urlString(), graphqlHTTP({ - schema: TestSchema - })); - - var response = await request(app) - .get(urlString({ - query: '{thrower}', - })); - - expect(response.status).to.equal(200); - expect(JSON.parse(response.text)).to.deep.equal({ - data: null, - errors: [ { - message: 'Throws!', - locations: [ { line: 1, column: 2 } ] - } ] - }); - }); - - it('allows for custom error formatting to sanitize', async () => { - var app = express(); - - app.use(urlString(), graphqlHTTP({ - schema: TestSchema, - formatError(error) { - return { message: 'Custom error format: ' + error.message }; - } - })); - - var response = await request(app) - .get(urlString({ - query: '{thrower}', - })); - - expect(response.status).to.equal(200); - expect(JSON.parse(response.text)).to.deep.equal({ - data: null, - errors: [ { - message: 'Custom error format: Throws!', - } ] - }); - }); - - it('allows for custom error formatting to elaborate', async () => { - var app = express(); - - app.use(urlString(), graphqlHTTP({ - schema: TestSchema, - formatError(error) { - return { - message: error.message, - locations: error.locations, - stack: 'Stack trace' - }; - } - })); - - var response = await request(app) - .get(urlString({ - query: '{thrower}', - })); - - expect(response.status).to.equal(200); - expect(JSON.parse(response.text)).to.deep.equal({ - data: null, - errors: [ { - message: 'Throws!', - locations: [ { line: 1, column: 2 } ], - stack: 'Stack trace', - } ] - }); - }); - - it('handles syntax errors caught by GraphQL', async () => { - var app = express(); - - app.use(urlString(), graphqlHTTP({ - schema: TestSchema, - })); - - var error = await catchError( - request(app) - .get(urlString({ - query: 'syntaxerror', - })) - ); - - expect(error.response.status).to.equal(400); - expect(JSON.parse(error.response.text)).to.deep.equal({ - errors: [ { - message: 'Syntax Error GraphQL request (1:1) ' + - 'Unexpected Name \"syntaxerror\"\n\n1: syntaxerror\n ^\n', - locations: [ { line: 1, column: 1 } ] - } ] - }); - }); - - it('handles errors caused by a lack of query', async () => { - var app = express(); - - app.use(urlString(), graphqlHTTP({ - schema: TestSchema, - })); - - var error = await catchError( - request(app).get(urlString()) - ); - - expect(error.response.status).to.equal(400); - expect(JSON.parse(error.response.text)).to.deep.equal({ - errors: [ { message: 'Must provide query string.' } ] - }); - }); - - it('handles invalid JSON bodies', async () => { - var app = express(); - - app.use(urlString(), graphqlHTTP({ - schema: TestSchema, - })); - - var error = await catchError( - request(app) - .post(urlString()) - .set('Content-Type', 'application/json') - .send('[]') - ); - - expect(error.response.status).to.equal(400); - expect(JSON.parse(error.response.text)).to.deep.equal({ - errors: [ { message: 'POST body sent invalid JSON.' } ] - }); - }); - - it('handles incomplete JSON bodies', async () => { - var app = express(); - - app.use(urlString(), graphqlHTTP({ - schema: TestSchema, - })); - - var error = await catchError( - request(app) - .post(urlString()) - .set('Content-Type', 'application/json') - .send('{"query":') - ); - - expect(error.response.status).to.equal(400); - expect(JSON.parse(error.response.text)).to.deep.equal({ - errors: [ { message: 'POST body sent invalid JSON.' } ] - }); - }); - - it('handles plain POST text', async () => { - var app = express(); - - app.use(urlString(), graphqlHTTP({ - schema: TestSchema - })); - - var error = await catchError( - request(app) - .post(urlString({ - variables: JSON.stringify({ who: 'Dolly' }) - })) - .set('Content-Type', 'text/plain') - .send('query helloWho($who: String){ test(who: $who) }') - ); - - expect(error.response.status).to.equal(400); - expect(JSON.parse(error.response.text)).to.deep.equal({ - errors: [ { message: 'Must provide query string.' } ] - }); - }); - - it('handles unsupported charset', async () => { - var app = express(); - - app.use(urlString(), graphqlHTTP(() => ({ - schema: TestSchema - }))); - - var error = await catchError( - request(app) - .post(urlString()) - .set('Content-Type', 'application/graphql; charset=ascii') - .send('{ test(who: "World") }') - ); - - expect(error.response.status).to.equal(415); - expect(JSON.parse(error.response.text)).to.deep.equal({ - errors: [ { message: 'Unsupported charset "ASCII".' } ] - }); - }); - - it('handles unsupported utf charset', async () => { - var app = express(); - - app.use(urlString(), graphqlHTTP(() => ({ - schema: TestSchema - }))); - - var error = await catchError( - request(app) - .post(urlString()) - .set('Content-Type', 'application/graphql; charset=utf-53') - .send('{ test(who: "World") }') - ); - - expect(error.response.status).to.equal(415); - expect(JSON.parse(error.response.text)).to.deep.equal({ - errors: [ { message: 'Unsupported charset "UTF-53".' } ] - }); - }); - - it('handles unknown encoding', async () => { - var app = express(); - - app.use(urlString(), graphqlHTTP(() => ({ - schema: TestSchema - }))); - - var error = await catchError( - request(app) - .post(urlString()) - .set('Content-Encoding', 'garbage') - .send('!@#$%^*(&^$%#@') - ); - - expect(error.response.status).to.equal(415); - expect(JSON.parse(error.response.text)).to.deep.equal({ - errors: [ { message: 'Unsupported content-encoding "garbage".' } ] - }); - }); - - it('handles poorly formed variables', async () => { - var app = express(); - - app.use(urlString(), graphqlHTTP({ schema: TestSchema })); - - var error = await catchError( - request(app) - .get(urlString({ - variables: 'who:You', - query: 'query helloWho($who: String){ test(who: $who) }' - })) - ); - - expect(error.response.status).to.equal(400); - expect(JSON.parse(error.response.text)).to.deep.equal({ - errors: [ { message: 'Variables are invalid JSON.' } ] - }); - }); - - it('handles unsupported HTTP methods', async () => { - var app = express(); - - app.use(urlString(), graphqlHTTP({ schema: TestSchema })); - - var error = await catchError( - request(app) - .put(urlString({ query: '{test}' })) - ); - - expect(error.response.status).to.equal(405); - expect(error.response.headers.allow).to.equal('GET, POST'); - expect(JSON.parse(error.response.text)).to.deep.equal({ - errors: [ - { message: 'GraphQL only supports GET and POST requests.' } - ] - }); - }); - - }); - - describe('Built-in GraphiQL support', () => { - it('does not renders GraphiQL if no opt-in', async () => { - var app = express(); - - app.use(urlString(), graphqlHTTP({ schema: TestSchema })); - - var response = await request(app) - .get(urlString({ query: '{test}' })) - .set('Accept', 'text/html'); - - expect(response.status).to.equal(200); - expect(response.type).to.equal('application/json'); - expect(response.text).to.equal( - '{"data":{"test":"Hello World"}}' - ); - }); - - it('presents GraphiQL when accepting HTML', async () => { - var app = express(); - - app.use(urlString(), graphqlHTTP({ - schema: TestSchema, - graphiql: true - })); - - var response = await request(app) - .get(urlString({ query: '{test}' })) - .set('Accept', 'text/html'); - - expect(response.status).to.equal(200); - expect(response.type).to.equal('text/html'); - expect(response.text).to.include('{test}'); - expect(response.text).to.include('graphiql.min.js'); - }); - - it('contains a pre-run response within GraphiQL', async () => { - var app = express(); - - app.use(urlString(), graphqlHTTP({ - schema: TestSchema, - graphiql: true - })); - - var response = await request(app) - .get(urlString({ query: '{test}' })) - .set('Accept', 'text/html'); - - expect(response.status).to.equal(200); - expect(response.type).to.equal('text/html'); - expect(response.text).to.include( - 'response: ' + JSON.stringify( - JSON.stringify({ data: { test: 'Hello World' } }, null, 2) - ) - ); - }); - - it('contains a pre-run operation name within GraphiQL', async () => { - var app = express(); - - app.use(urlString(), graphqlHTTP({ - schema: TestSchema, - graphiql: true - })); - - var response = await request(app) - .get(urlString({ - query: 'query A{a:test} query B{b:test}', - operationName: 'B' - })) - .set('Accept', 'text/html'); - - expect(response.status).to.equal(200); - expect(response.type).to.equal('text/html'); - expect(response.text).to.include( - 'response: ' + JSON.stringify( - JSON.stringify({ data: { b: 'Hello World' } }, null, 2) - ) - ); - expect(response.text).to.include('operationName: "B"'); - }); - - it('escapes HTML in queries within GraphiQL', async () => { - var app = express(); - - app.use(urlString(), graphqlHTTP({ - schema: TestSchema, - graphiql: true - })); - - var error = await catchError( - request(app).get(urlString({ query: '' })) - .set('Accept', 'text/html') - ); - - expect(error.response.status).to.equal(400); - expect(error.response.type).to.equal('text/html'); - expect(error.response.text).to.not.include(''); - }); - - it('escapes HTML in variables within GraphiQL', async () => { - var app = express(); - - app.use(urlString(), graphqlHTTP({ - schema: TestSchema, - graphiql: true - })); - - var response = await request(app).get(urlString({ - query: 'query helloWho($who: String) { test(who: $who) }', - variables: JSON.stringify({ - who: '' - }) - })) .set('Accept', 'text/html'); - - expect(response.status).to.equal(200); - expect(response.type).to.equal('text/html'); - expect(response.text).to.not.include(''); - }); - - it('GraphiQL renders provided variables', async () => { - var app = express(); - - app.use(urlString(), graphqlHTTP({ - schema: TestSchema, - graphiql: true - })); - - var response = await request(app) - .get(urlString({ - query: 'query helloWho($who: String) { test(who: $who) }', - variables: JSON.stringify({ who: 'Dolly' }) - })) - .set('Accept', 'text/html'); - - expect(response.status).to.equal(200); - expect(response.type).to.equal('text/html'); - expect(response.text).to.include( - 'variables: ' + JSON.stringify( - JSON.stringify({ who: 'Dolly' }, null, 2) - ) - ); - }); - - it('GraphiQL accepts an empty query', async () => { - var app = express(); - - app.use(urlString(), graphqlHTTP({ - schema: TestSchema, - graphiql: true - })); - - var response = await request(app) - .get(urlString()) - .set('Accept', 'text/html'); - - expect(response.status).to.equal(200); - expect(response.type).to.equal('text/html'); - expect(response.text).to.include('response: null'); - }); - - it('GraphiQL accepts a mutation query - does not execute it', async () => { - var app = express(); - - app.use(urlString(), graphqlHTTP({ - schema: TestSchema, - graphiql: true - })); - - var response = await request(app) - .get(urlString({ - query: 'mutation TestMutation { writeTest { test } }' - })) - .set('Accept', 'text/html'); - - expect(response.status).to.equal(200); - expect(response.type).to.equal('text/html'); - expect(response.text).to.include( - 'query: "mutation TestMutation { writeTest { test } }"' - ); - expect(response.text).to.include('response: null'); - }); - - it('returns HTML if preferred', async () => { - var app = express(); - - app.use(urlString(), graphqlHTTP({ - schema: TestSchema, - graphiql: true - })); - - var response = await request(app) - .get(urlString({ query: '{test}' })) - .set('Accept', 'text/html,application/json'); - - expect(response.status).to.equal(200); - expect(response.type).to.equal('text/html'); - expect(response.text).to.include('graphiql.min.js'); - }); - - it('returns JSON if preferred', async () => { - var app = express(); - - app.use(urlString(), graphqlHTTP({ - schema: TestSchema, - graphiql: true - })); - - var response = await request(app) - .get(urlString({ query: '{test}' })) - .set('Accept', 'application/json,text/html'); - - expect(response.status).to.equal(200); - expect(response.type).to.equal('application/json'); - expect(response.text).to.equal( - '{"data":{"test":"Hello World"}}' - ); - }); - - it('prefers JSON if unknown accept', async () => { - var app = express(); - - app.use(urlString(), graphqlHTTP({ - schema: TestSchema, - graphiql: true - })); - - var response = await request(app) - .get(urlString({ query: '{test}' })) - .set('Accept', 'unknown'); - - expect(response.status).to.equal(200); - expect(response.type).to.equal('application/json'); - expect(response.text).to.equal( - '{"data":{"test":"Hello World"}}' - ); - }); - - it('prefers JSON if explicitly requested raw response', async () => { - var app = express(); - - app.use(urlString(), graphqlHTTP({ - schema: TestSchema, - graphiql: true - })); - - var response = await request(app) - .get(urlString({ query: '{test}', raw: '' })) - .set('Accept', 'text/html'); - - expect(response.status).to.equal(200); - expect(response.type).to.equal('application/json'); - expect(response.text).to.equal( - '{"data":{"test":"Hello World"}}' - ); - }); - }); - - describe('Custom validation rules', () => { - var AlwaysInvalidRule = function (context) { - return { - enter() { - context.reportError(new GraphQLError( - 'AlwaysInvalidRule was really invalid!' - )); - return BREAK; - } - }; - }; - - it('Do not execute a query if it do not pass the custom validation.', async() => { - var app = express(); - - app.use(urlString(), graphqlHTTP({ - schema: TestSchema, - validationRules: [ AlwaysInvalidRule ], - pretty: true, - })); - - var error = await catchError( - request(app) - .get(urlString({ - query: '{thrower}', - })) - ); - - expect(error.response.status).to.equal(400); - expect(JSON.parse(error.response.text)).to.deep.equal({ - errors: [ - { - message: 'AlwaysInvalidRule was really invalid!' - }, - ] - }); - - }); - }); - }); -}); diff --git a/test/tests.js b/test/tests.js index ab6e9efa610..4421d6dea62 100644 --- a/test/tests.js +++ b/test/tests.js @@ -3,5 +3,3 @@ import './testLogger'; import './testDiscourseSchema'; import './testTracer'; import './testMocking'; -import './testApolloServer'; -import './testApolloServerHTTP'; From cf85d264658428be1a98b2917161c7cab6f04e03 Mon Sep 17 00:00:00 2001 From: Slava Kim Date: Thu, 26 May 2016 14:24:42 -0700 Subject: [PATCH 2/2] 0.5.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 992d9174ab3..e97628dc857 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "graphql-tools", - "version": "0.4.2", + "version": "0.5.0", "description": "A set of useful GraphQL tools", "main": "dist/index.js", "directories": {