diff --git a/src/execution/__tests__/executor-test.js b/src/execution/__tests__/executor-test.js index d5eeafc81f..391814c77b 100644 --- a/src/execution/__tests__/executor-test.js +++ b/src/execution/__tests__/executor-test.js @@ -4,13 +4,15 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @noflow + * @flow strict */ import { expect } from 'chai'; import { describe, it } from 'mocha'; +import inspect from '../../jsutils/inspect'; +import invariant from '../../jsutils/invariant'; import { execute } from '../execute'; -import { parse } from '../../language'; +import { Kind, parse } from '../../language'; import { GraphQLSchema, GraphQLObjectType, @@ -32,22 +34,20 @@ describe('Execute: Handles basic execution tasks', () => { }), }); - expect(() => execute(schema, null)).to.throw('Must provide document'); + // $DisableFlowOnNegativeTest + expect(() => execute({ schema })).to.throw('Must provide document'); }); it('throws if no schema is provided', () => { - expect(() => - execute({ - document: parse('{ field }'), - }), - ).to.throw('Expected undefined to be a GraphQL schema.'); - }); - - it('accepts an object with named properties as arguments', () => { - const doc = 'query Example { a }'; + const document = parse('{ field }'); - const data = 'rootValue'; + // $DisableFlowOnNegativeTest + expect(() => execute({ document })).to.throw( + 'Expected undefined to be a GraphQL schema.', + ); + }); + it('accepts positional arguments', () => { const schema = new GraphQLSchema({ query: new GraphQLObjectType({ name: 'Type', @@ -62,11 +62,9 @@ describe('Execute: Handles basic execution tasks', () => { }), }); - const result = execute({ - schema, - document: parse(doc), - rootValue: data, - }); + const document = parse('{ a }'); + const rootValue = 'rootValue'; + const result = execute(schema, document, rootValue); expect(result).to.deep.equal({ data: { a: 'rootValue' }, @@ -75,46 +73,23 @@ describe('Execute: Handles basic execution tasks', () => { it('executes arbitrary code', async () => { const data = { - a() { - return 'Apple'; - }, - b() { - return 'Banana'; - }, - c() { - return 'Cookie'; - }, - d() { - return 'Donut'; - }, - e() { - return 'Egg'; - }, + a: () => 'Apple', + b: () => 'Banana', + c: () => 'Cookie', + d: () => 'Donut', + e: () => 'Egg', f: 'Fish', - pic(size) { - return 'Pic of size: ' + (size || 50); - }, - deep() { - return deepData; - }, - promise() { - return promiseData(); - }, + // Called only by DataType::pic static resolver + pic: size => 'Pic of size: ' + (size || 50), + deep: () => deepData, + promise: promiseData, }; const deepData = { - a() { - return 'Already Been Done'; - }, - b() { - return 'Boring'; - }, - c() { - return ['Contrived', undefined, 'Confusing']; - }, - deeper() { - return [data, null, data]; - }, + a: () => 'Already Been Done', + b: () => 'Boring', + c: () => ['Contrived', undefined, 'Confusing'], + deeper: () => [data, null, data], }; function promiseData() { @@ -125,8 +100,37 @@ describe('Execute: Handles basic execution tasks', () => { }); } - const doc = ` - query Example($size: Int) { + const DataType = new GraphQLObjectType({ + name: 'DataType', + fields: () => ({ + a: { type: GraphQLString }, + b: { type: GraphQLString }, + c: { type: GraphQLString }, + d: { type: GraphQLString }, + e: { type: GraphQLString }, + f: { type: GraphQLString }, + pic: { + args: { size: { type: GraphQLInt } }, + type: GraphQLString, + resolve: (obj, { size }) => obj.pic(size), + }, + deep: { type: DeepDataType }, + promise: { type: DataType }, + }), + }); + + const DeepDataType = new GraphQLObjectType({ + name: 'DeepDataType', + fields: { + a: { type: GraphQLString }, + b: { type: GraphQLString }, + c: { type: GraphQLList(GraphQLString) }, + deeper: { type: GraphQLList(DataType) }, + }, + }); + + const document = parse(` + query ($size: Int) { a, b, x: c @@ -153,10 +157,16 @@ describe('Execute: Handles basic execution tasks', () => { d e } - `; + `); + + const result = await execute({ + schema: new GraphQLSchema({ query: DataType }), + document, + rootValue: data, + variableValues: { size: 100 }, + }); - const ast = parse(doc); - const expected = { + expect(result).to.deep.equal({ data: { a: 'Apple', b: 'Banana', @@ -177,48 +187,22 @@ describe('Execute: Handles basic execution tasks', () => { ], }, }, - }; + }); + }); - const DataType = new GraphQLObjectType({ - name: 'DataType', + it('merges parallel fragments', () => { + const Type = new GraphQLObjectType({ + name: 'Type', fields: () => ({ - a: { type: GraphQLString }, - b: { type: GraphQLString }, - c: { type: GraphQLString }, - d: { type: GraphQLString }, - e: { type: GraphQLString }, - f: { type: GraphQLString }, - pic: { - args: { size: { type: GraphQLInt } }, - type: GraphQLString, - resolve: (obj, { size }) => obj.pic(size), - }, - deep: { type: DeepDataType }, - promise: { type: DataType }, + a: { type: GraphQLString, resolve: () => 'Apple' }, + b: { type: GraphQLString, resolve: () => 'Banana' }, + c: { type: GraphQLString, resolve: () => 'Cherry' }, + deep: { type: Type, resolve: () => ({}) }, }), }); + const schema = new GraphQLSchema({ query: Type }); - const DeepDataType = new GraphQLObjectType({ - name: 'DeepDataType', - fields: { - a: { type: GraphQLString }, - b: { type: GraphQLString }, - c: { type: GraphQLList(GraphQLString) }, - deeper: { type: GraphQLList(DataType) }, - }, - }); - - const schema = new GraphQLSchema({ - query: DataType, - }); - - expect( - await execute(schema, ast, data, null, { size: 100 }, 'Example'), - ).to.deep.equal(expected); - }); - - it('merges parallel fragments', () => { - const ast = parse(` + const document = parse(` { a, ...FragOne, ...FragTwo } fragment FragOne on Type { @@ -232,18 +216,8 @@ describe('Execute: Handles basic execution tasks', () => { } `); - const Type = new GraphQLObjectType({ - name: 'Type', - fields: () => ({ - a: { type: GraphQLString, resolve: () => 'Apple' }, - b: { type: GraphQLString, resolve: () => 'Banana' }, - c: { type: GraphQLString, resolve: () => 'Cherry' }, - deep: { type: Type, resolve: () => ({}) }, - }), - }); - const schema = new GraphQLSchema({ query: Type }); - - expect(execute(schema, ast)).to.deep.equal({ + const result = execute({ schema, document }); + expect(result).to.deep.equal({ data: { a: 'Apple', b: 'Banana', @@ -261,29 +235,27 @@ describe('Execute: Handles basic execution tasks', () => { }); it('provides info about current execution state', () => { - const ast = parse('query ($var: String) { result: test }'); - - let info; - - const schema = new GraphQLSchema({ - query: new GraphQLObjectType({ - name: 'Test', - fields: { - test: { - type: GraphQLString, - resolve(val, args, ctx, _info) { - info = _info; - }, + let resolvedInfo; + const testType = new GraphQLObjectType({ + name: 'Test', + fields: { + test: { + type: GraphQLString, + resolve(_val, _args, _ctx, info) { + resolvedInfo = info; }, }, - }), + }, }); + const schema = new GraphQLSchema({ query: testType }); + const document = parse('query ($var: String) { result: test }'); const rootValue = { root: 'val' }; + const variableValues = { var: 'abc' }; - execute(schema, ast, rootValue, null, { var: 'abc' }); + execute({ schema, document, rootValue, variableValues }); - expect(Object.keys(info)).to.deep.equal([ + expect(resolvedInfo).to.have.all.keys( 'fieldName', 'fieldNodes', 'returnType', @@ -294,58 +266,53 @@ describe('Execute: Handles basic execution tasks', () => { 'rootValue', 'operation', 'variableValues', - ]); - expect(info.fieldName).to.equal('test'); - expect(info.fieldNodes).to.have.lengthOf(1); - expect(info.fieldNodes[0]).to.equal( - ast.definitions[0].selectionSet.selections[0], ); - expect(info.returnType).to.equal(GraphQLString); - expect(info.parentType).to.equal(schema.getQueryType()); - expect(info.path).to.deep.equal({ prev: undefined, key: 'result' }); - expect(info.schema).to.equal(schema); - expect(info.rootValue).to.equal(rootValue); - expect(info.operation).to.equal(ast.definitions[0]); - expect(info.variableValues).to.deep.equal({ var: 'abc' }); - }); - it('threads root value context correctly', () => { - const doc = 'query Example { a }'; + const operation = document.definitions[0]; + invariant(operation && operation.kind === Kind.OPERATION_DEFINITION); - const data = { - contextThing: 'thing', - }; + expect(resolvedInfo).to.include({ + fieldName: 'test', + returnType: GraphQLString, + parentType: testType, + schema, + rootValue, + operation, + }); - let resolvedRootValue; + const field = operation.selectionSet.selections[0]; + expect(resolvedInfo).to.deep.include({ + fieldNodes: [field], + path: { prev: undefined, key: 'result' }, + variableValues: { var: 'abc' }, + }); + }); + it('threads root value context correctly', () => { + let resolvedRootValue; const schema = new GraphQLSchema({ query: new GraphQLObjectType({ name: 'Type', fields: { a: { type: GraphQLString, - resolve(rootValue) { - resolvedRootValue = rootValue; + resolve(rootValueArg) { + resolvedRootValue = rootValueArg; }, }, }, }), }); - execute(schema, parse(doc), data); + const document = parse('query Example { a }'); + const rootValue = { contextThing: 'thing' }; - expect(resolvedRootValue.contextThing).to.equal('thing'); + execute({ schema, document, rootValue }); + expect(resolvedRootValue).to.equal(rootValue); }); it('correctly threads arguments', () => { - const doc = ` - query Example { - b(numArg: 123, stringArg: "foo") - } - `; - let resolvedArgs; - const schema = new GraphQLSchema({ query: new GraphQLObjectType({ name: 'Type', @@ -364,30 +331,58 @@ describe('Execute: Handles basic execution tasks', () => { }), }); - execute(schema, parse(doc)); + const document = parse(` + query Example { + b(numArg: 123, stringArg: "foo") + } + `); - expect(resolvedArgs.numArg).to.equal(123); - expect(resolvedArgs.stringArg).to.equal('foo'); + execute({ schema, document }); + expect(resolvedArgs).to.deep.equal({ numArg: 123, stringArg: 'foo' }); }); it('nulls out error subtrees', async () => { - const doc = `{ - sync - syncError - syncRawError - syncReturnError - syncReturnErrorList - async - asyncReject - asyncRawReject - asyncEmptyReject - asyncError - asyncRawError - asyncReturnError - asyncReturnErrorWithExtensions - }`; + const schema = new GraphQLSchema({ + query: new GraphQLObjectType({ + name: 'Type', + fields: { + sync: { type: GraphQLString }, + syncError: { type: GraphQLString }, + syncRawError: { type: GraphQLString }, + syncReturnError: { type: GraphQLString }, + syncReturnErrorList: { type: GraphQLList(GraphQLString) }, + async: { type: GraphQLString }, + asyncReject: { type: GraphQLString }, + asyncRejectWithExtensions: { type: GraphQLString }, + asyncRawReject: { type: GraphQLString }, + asyncEmptyReject: { type: GraphQLString }, + asyncError: { type: GraphQLString }, + asyncRawError: { type: GraphQLString }, + asyncReturnError: { type: GraphQLString }, + asyncReturnErrorWithExtensions: { type: GraphQLString }, + }, + }), + }); - const data = { + const document = parse(` + { + sync + syncError + syncRawError + syncReturnError + syncReturnErrorList + async + asyncReject + asyncRawReject + asyncEmptyReject + asyncError + asyncRawError + asyncReturnError + asyncReturnErrorWithExtensions + } + `); + + const rootValue = { sync() { return 'sync'; }, @@ -438,38 +433,16 @@ describe('Execute: Handles basic execution tasks', () => { return Promise.resolve(new Error('Error getting asyncReturnError')); }, asyncReturnErrorWithExtensions() { - const error = new Error('Error getting asyncReturnErrorWithExtensions'); + const error: any = new Error( + 'Error getting asyncReturnErrorWithExtensions', + ); error.extensions = { foo: 'bar' }; return Promise.resolve(error); }, }; - const ast = parse(doc); - const schema = new GraphQLSchema({ - query: new GraphQLObjectType({ - name: 'Type', - fields: { - sync: { type: GraphQLString }, - syncError: { type: GraphQLString }, - syncRawError: { type: GraphQLString }, - syncReturnError: { type: GraphQLString }, - syncReturnErrorList: { type: GraphQLList(GraphQLString) }, - async: { type: GraphQLString }, - asyncReject: { type: GraphQLString }, - asyncRejectWithExtensions: { type: GraphQLString }, - asyncRawReject: { type: GraphQLString }, - asyncEmptyReject: { type: GraphQLString }, - asyncError: { type: GraphQLString }, - asyncRawError: { type: GraphQLString }, - asyncReturnError: { type: GraphQLString }, - asyncReturnErrorWithExtensions: { type: GraphQLString }, - }, - }), - }); - - const result = await execute(schema, ast, data); - + const result = await execute({ schema, document, rootValue }); expect(result).to.deep.equal({ data: { sync: 'sync', @@ -489,62 +462,62 @@ describe('Execute: Handles basic execution tasks', () => { errors: [ { message: 'Error getting syncError', - locations: [{ line: 3, column: 7 }], + locations: [{ line: 4, column: 9 }], path: ['syncError'], }, { message: 'Error getting syncRawError', - locations: [{ line: 4, column: 7 }], + locations: [{ line: 5, column: 9 }], path: ['syncRawError'], }, { message: 'Error getting syncReturnError', - locations: [{ line: 5, column: 7 }], + locations: [{ line: 6, column: 9 }], path: ['syncReturnError'], }, { message: 'Error getting syncReturnErrorList1', - locations: [{ line: 6, column: 7 }], + locations: [{ line: 7, column: 9 }], path: ['syncReturnErrorList', 1], }, { message: 'Error getting syncReturnErrorList3', - locations: [{ line: 6, column: 7 }], + locations: [{ line: 7, column: 9 }], path: ['syncReturnErrorList', 3], }, { message: 'Error getting asyncReject', - locations: [{ line: 8, column: 7 }], + locations: [{ line: 9, column: 9 }], path: ['asyncReject'], }, { message: 'Error getting asyncRawReject', - locations: [{ line: 9, column: 7 }], + locations: [{ line: 10, column: 9 }], path: ['asyncRawReject'], }, { message: '', - locations: [{ line: 10, column: 7 }], + locations: [{ line: 11, column: 9 }], path: ['asyncEmptyReject'], }, { message: 'Error getting asyncError', - locations: [{ line: 11, column: 7 }], + locations: [{ line: 12, column: 9 }], path: ['asyncError'], }, { message: 'Error getting asyncRawError', - locations: [{ line: 12, column: 7 }], + locations: [{ line: 13, column: 9 }], path: ['asyncRawError'], }, { message: 'Error getting asyncReturnError', - locations: [{ line: 13, column: 7 }], + locations: [{ line: 14, column: 9 }], path: ['asyncReturnError'], }, { message: 'Error getting asyncReturnErrorWithExtensions', - locations: [{ line: 14, column: 7 }], + locations: [{ line: 15, column: 9 }], path: ['asyncReturnErrorWithExtensions'], extensions: { foo: 'bar' }, }, @@ -553,14 +526,6 @@ describe('Execute: Handles basic execution tasks', () => { }); it('nulls error subtree for promise rejection #1071', async () => { - const query = ` - query { - foods { - name - } - } - `; - const schema = new GraphQLSchema({ query: new GraphQLObjectType({ name: 'Query', @@ -582,21 +547,21 @@ describe('Execute: Handles basic execution tasks', () => { }), }); - const ast = parse(query); - const result = await execute(schema, ast); + const document = parse(` + query { + foods { + name + } + } + `); + + const result = await execute({ schema, document }); expect(result).to.deep.equal({ - data: { - foods: null, - }, + data: { foods: null }, errors: [ { - locations: [ - { - column: 9, - line: 3, - }, - ], + locations: [{ column: 9, line: 3 }], message: 'Dangit', path: ['foods'], }, @@ -624,20 +589,19 @@ describe('Execute: Handles basic execution tasks', () => { }, }), }); - const queryType = new GraphQLObjectType({ - name: 'query', - fields: () => ({ - nullableA: { - type: A, - resolve: () => ({}), - }, - }), - }); const schema = new GraphQLSchema({ - query: queryType, + query: new GraphQLObjectType({ + name: 'query', + fields: () => ({ + nullableA: { + type: A, + resolve: () => ({}), + }, + }), + }), }); - const query = ` + const document = parse(` query { nullableA { aliasedA: nullableA { @@ -649,9 +613,9 @@ describe('Execute: Handles basic execution tasks', () => { } } } - `; + `); - const result = execute(schema, parse(query)); + const result = execute({ schema, document }); expect(result).to.deep.equal({ data: { nullableA: { @@ -669,9 +633,6 @@ describe('Execute: Handles basic execution tasks', () => { }); it('uses the inline operation if no operation name is provided', () => { - const doc = '{ a }'; - const data = { a: 'b' }; - const ast = parse(doc); const schema = new GraphQLSchema({ query: new GraphQLObjectType({ name: 'Type', @@ -680,16 +641,14 @@ describe('Execute: Handles basic execution tasks', () => { }, }), }); + const document = parse('{ a }'); + const rootValue = { a: 'b' }; - const result = execute(schema, ast, data); - + const result = execute({ schema, document, rootValue }); expect(result).to.deep.equal({ data: { a: 'b' } }); }); it('uses the only operation if no operation name is provided', () => { - const doc = 'query Example { a }'; - const data = { a: 'b' }; - const ast = parse(doc); const schema = new GraphQLSchema({ query: new GraphQLObjectType({ name: 'Type', @@ -698,16 +657,14 @@ describe('Execute: Handles basic execution tasks', () => { }, }), }); + const document = parse('query Example { a }'); + const rootValue = { a: 'b' }; - const result = execute(schema, ast, data); - + const result = execute({ schema, document, rootValue }); expect(result).to.deep.equal({ data: { a: 'b' } }); }); it('uses the named operation if operation name is provided', () => { - const doc = 'query Example { first: a } query OtherExample { second: a }'; - const data = { a: 'b' }; - const ast = parse(doc); const schema = new GraphQLSchema({ query: new GraphQLObjectType({ name: 'Type', @@ -717,15 +674,18 @@ describe('Execute: Handles basic execution tasks', () => { }), }); - const result = execute(schema, ast, data, null, null, 'OtherExample'); + const document = parse(` + query Example { first: a } + query OtherExample { second: a } + `); + const rootValue = { a: 'b' }; + const operationName = 'OtherExample'; + const result = execute({ schema, document, rootValue, operationName }); expect(result).to.deep.equal({ data: { second: 'b' } }); }); it('provides error if no operation is provided', () => { - const doc = 'fragment Example on Type { a }'; - const data = { a: 'b' }; - const ast = parse(doc); const schema = new GraphQLSchema({ query: new GraphQLObjectType({ name: 'Type', @@ -734,17 +694,16 @@ describe('Execute: Handles basic execution tasks', () => { }, }), }); + const document = parse('fragment Example on Type { a }'); + const rootValue = { a: 'b' }; - const result = execute(schema, ast, data); + const result = execute({ schema, document, rootValue }); expect(result).to.deep.equal({ errors: [{ message: 'Must provide an operation.' }], }); }); it('errors if no op name is provided with multiple operations', () => { - const doc = 'query Example { a } query OtherExample { a }'; - const data = { a: 'b' }; - const ast = parse(doc); const schema = new GraphQLSchema({ query: new GraphQLObjectType({ name: 'Type', @@ -753,8 +712,12 @@ describe('Execute: Handles basic execution tasks', () => { }, }), }); + const document = parse(` + query Example { a } + query OtherExample { a } + `); - const result = execute(schema, ast, data); + const result = execute({ schema, document }); expect(result).to.deep.equal({ errors: [ { @@ -766,8 +729,6 @@ describe('Execute: Handles basic execution tasks', () => { }); it('errors if unknown operation name is provided', () => { - const doc = 'query Example { a } query OtherExample { a }'; - const ast = parse(doc); const schema = new GraphQLSchema({ query: new GraphQLObjectType({ name: 'Type', @@ -776,21 +737,19 @@ describe('Execute: Handles basic execution tasks', () => { }, }), }); + const document = parse(` + query Example { a } + query OtherExample { a } + `); + const operationName = 'UnknownExample'; - const result = execute({ - schema, - document: ast, - operationName: 'UnknownExample', - }); + const result = execute({ schema, document, operationName }); expect(result).to.deep.equal({ errors: [{ message: 'Unknown operation named "UnknownExample".' }], }); }); it('uses the query schema for queries', () => { - const doc = 'query Q { a } mutation M { c } subscription S { a }'; - const data = { a: 'b', c: 'd' }; - const ast = parse(doc); const schema = new GraphQLSchema({ query: new GraphQLObjectType({ name: 'Q', @@ -811,16 +770,19 @@ describe('Execute: Handles basic execution tasks', () => { }, }), }); + const document = parse(` + query Q { a } + mutation M { c } + subscription S { a } + `); + const rootValue = { a: 'b', c: 'd' }; + const operationName = 'Q'; - const queryResult = execute(schema, ast, data, null, {}, 'Q'); - - expect(queryResult).to.deep.equal({ data: { a: 'b' } }); + const result = execute({ schema, document, rootValue, operationName }); + expect(result).to.deep.equal({ data: { a: 'b' } }); }); it('uses the mutation schema for mutations', () => { - const doc = 'query Q { a } mutation M { c }'; - const data = { a: 'b', c: 'd' }; - const ast = parse(doc); const schema = new GraphQLSchema({ query: new GraphQLObjectType({ name: 'Q', @@ -835,16 +797,18 @@ describe('Execute: Handles basic execution tasks', () => { }, }), }); + const document = parse(` + query Q { a } + mutation M { c } + `); + const rootValue = { a: 'b', c: 'd' }; + const operationName = 'M'; - const mutationResult = execute(schema, ast, data, null, {}, 'M'); - - expect(mutationResult).to.deep.equal({ data: { c: 'd' } }); + const result = execute({ schema, document, rootValue, operationName }); + expect(result).to.deep.equal({ data: { c: 'd' } }); }); it('uses the subscription schema for subscriptions', () => { - const doc = 'query Q { a } subscription S { a }'; - const data = { a: 'b', c: 'd' }; - const ast = parse(doc); const schema = new GraphQLSchema({ query: new GraphQLObjectType({ name: 'Q', @@ -859,40 +823,18 @@ describe('Execute: Handles basic execution tasks', () => { }, }), }); + const document = parse(` + query Q { a } + subscription S { a } + `); + const rootValue = { a: 'b', c: 'd' }; + const operationName = 'S'; - const subscriptionResult = execute(schema, ast, data, null, {}, 'S'); - - expect(subscriptionResult).to.deep.equal({ data: { a: 'b' } }); + const result = execute({ schema, document, rootValue, operationName }); + expect(result).to.deep.equal({ data: { a: 'b' } }); }); it('correct field ordering despite execution order', async () => { - const doc = `{ - a, - b, - c, - d, - e - }`; - - const data = { - a() { - return 'a'; - }, - b() { - return new Promise(resolve => resolve('b')); - }, - c() { - return 'c'; - }, - d() { - return new Promise(resolve => resolve('d')); - }, - e() { - return 'e'; - }, - }; - - const ast = parse(doc); const schema = new GraphQLSchema({ query: new GraphQLObjectType({ name: 'Type', @@ -905,37 +847,22 @@ describe('Execute: Handles basic execution tasks', () => { }, }), }); + const document = parse('{ a, b, c, d, e }'); + const rootValue = { + a: () => 'a', + b: () => new Promise(resolve => resolve('b')), + c: () => 'c', + d: () => new Promise(resolve => resolve('d')), + e: () => 'e', + }; - const result = await execute(schema, ast, data); - + const result = await execute({ schema, document, rootValue }); expect(result).to.deep.equal({ - data: { - a: 'a', - b: 'b', - c: 'c', - d: 'd', - e: 'e', - }, + data: { a: 'a', b: 'b', c: 'c', d: 'd', e: 'e' }, }); - - expect(Object.keys(result.data)).to.deep.equal(['a', 'b', 'c', 'd', 'e']); }); it('Avoids recursion', () => { - const doc = ` - query Q { - a - ...Frag - ...Frag - } - - fragment Frag on Type { - a, - ...Frag - } - `; - const data = { a: 'b' }; - const ast = parse(doc); const schema = new GraphQLSchema({ query: new GraphQLObjectType({ name: 'Type', @@ -944,17 +871,27 @@ describe('Execute: Handles basic execution tasks', () => { }, }), }); + const document = parse(` + { + a + ...Frag + ...Frag + } - const queryResult = execute(schema, ast, data, null, {}, 'Q'); + fragment Frag on Type { + a, + ...Frag + } + `); + const rootValue = { a: 'b' }; - expect(queryResult).to.deep.equal({ data: { a: 'b' } }); + const result = execute({ schema, document, rootValue }); + expect(result).to.deep.equal({ + data: { a: 'b' }, + }); }); it('does not include illegal fields in output', () => { - const doc = `mutation M { - thisIsIllegalDoNotIncludeMe - }`; - const ast = parse(doc); const schema = new GraphQLSchema({ query: new GraphQLObjectType({ name: 'Q', @@ -962,17 +899,11 @@ describe('Execute: Handles basic execution tasks', () => { a: { type: GraphQLString }, }, }), - mutation: new GraphQLObjectType({ - name: 'M', - fields: { - c: { type: GraphQLString }, - }, - }), }); + const document = parse('{ thisIsIllegalDoNotIncludeMe }'); - const mutationResult = execute(schema, ast); - - expect(mutationResult).to.deep.equal({ + const result = execute({ schema, document }); + expect(result).to.deep.equal({ data: {}, }); }); @@ -984,7 +915,7 @@ describe('Execute: Handles basic execution tasks', () => { fields: { field: { type: GraphQLString, - resolve: (data, args) => args && JSON.stringify(args), + resolve: (data, args) => inspect(args), args: { a: { type: GraphQLBoolean }, b: { type: GraphQLBoolean }, @@ -996,25 +927,28 @@ describe('Execute: Handles basic execution tasks', () => { }, }), }); + const document = parse('{ field(a: true, c: false, e: 0) }'); - const query = parse('{ field(a: true, c: false, e: 0) }'); - const result = execute(schema, query); - + const result = execute({ schema, document }); expect(result).to.deep.equal({ data: { - field: '{"a":true,"c":false,"e":0}', + field: '{ a: true, c: false, e: 0 }', }, }); }); it('fails when an isTypeOf check is not met', () => { class Special { + value: string; + constructor(value) { this.value = value; } } class NotSpecial { + value: string; + constructor(value) { this.value = value; } @@ -1022,32 +956,25 @@ describe('Execute: Handles basic execution tasks', () => { const SpecialType = new GraphQLObjectType({ name: 'SpecialType', - isTypeOf(obj) { - return obj instanceof Special; - }, - fields: { - value: { type: GraphQLString }, - }, + isTypeOf: obj => obj instanceof Special, + fields: { value: { type: GraphQLString } }, }); const schema = new GraphQLSchema({ query: new GraphQLObjectType({ name: 'Query', fields: { - specials: { - type: GraphQLList(SpecialType), - resolve: rootValue => rootValue.specials, - }, + specials: { type: GraphQLList(SpecialType) }, }, }), }); - const query = parse('{ specials { value } }'); - const value = { + const document = parse('{ specials { value } }'); + const rootValue = { specials: [new Special('foo'), new NotSpecial('bar')], }; - const result = execute(schema, query, value); + const result = execute({ schema, document, rootValue }); expect(result).to.deep.equal({ data: { specials: [{ value: 'foo' }, null], @@ -1064,12 +991,6 @@ describe('Execute: Handles basic execution tasks', () => { }); it('executes ignoring invalid non-executable definitions', () => { - const query = parse(` - { foo } - - type Query { bar: String } - `); - const schema = new GraphQLSchema({ query: new GraphQLObjectType({ name: 'Query', @@ -1079,17 +1000,17 @@ describe('Execute: Handles basic execution tasks', () => { }), }); - const result = execute(schema, query); - expect(result).to.deep.equal({ - data: { - foo: null, - }, - }); + const document = parse(` + { foo } + + type Query { bar: String } + `); + + const result = execute({ schema, document }); + expect(result).to.deep.equal({ data: { foo: null } }); }); it('uses a custom field resolver', () => { - const document = parse('{ foo }'); - const schema = new GraphQLSchema({ query: new GraphQLObjectType({ name: 'Query', @@ -1098,14 +1019,14 @@ describe('Execute: Handles basic execution tasks', () => { }, }), }); + const document = parse('{ foo }'); - // For the purposes of test, just return the name of the field! - function customResolver(source, args, context, info) { + function fieldResolver(source, args, context, info) { + // For the purposes of test, just return the name of the field! return info.fieldName; } - const result = execute({ schema, document, fieldResolver: customResolver }); - + const result = execute({ schema, document, fieldResolver }); expect(result).to.deep.equal({ data: { foo: 'foo' } }); }); });