diff --git a/.changeset/beige-coats-kick.md b/.changeset/beige-coats-kick.md new file mode 100644 index 00000000000..cabfd82ff6b --- /dev/null +++ b/.changeset/beige-coats-kick.md @@ -0,0 +1,5 @@ +--- +'@graphql-tools/utils': patch +--- + +fix(visitResult): handle introspection fields correctly with an introspection query result diff --git a/packages/utils/src/visitResult.ts b/packages/utils/src/visitResult.ts index 37b64d347a6..504d2698efd 100644 --- a/packages/utils/src/visitResult.ts +++ b/packages/utils/src/visitResult.ts @@ -13,6 +13,7 @@ import { GraphQLError, TypeNameMetaFieldDef, FragmentDefinitionNode, + SchemaMetaFieldDef, } from 'graphql'; import { collectFields, collectSubFields } from './collectFields'; @@ -232,7 +233,17 @@ function visitObjectValue( for (const [responseKey, subFieldNodes] of fieldNodeMap) { const fieldName = subFieldNodes[0].name.value; - const fieldType = fieldName === '__typename' ? TypeNameMetaFieldDef.type : fieldMap[fieldName]?.type; + let fieldType = fieldMap[fieldName]?.type; + if (fieldType == null) { + switch (fieldName) { + case '__typename': + fieldType = TypeNameMetaFieldDef.type; + break; + case '__schema': + fieldType = SchemaMetaFieldDef.type; + break; + } + } const newPathIndex = pathIndex + 1; diff --git a/packages/utils/tests/visitResult.test.ts b/packages/utils/tests/visitResult.test.ts index 5b292daf62c..91f006bdffc 100644 --- a/packages/utils/tests/visitResult.test.ts +++ b/packages/utils/tests/visitResult.test.ts @@ -1,4 +1,4 @@ -import { buildSchema, parse, GraphQLError } from 'graphql'; +import { buildSchema, parse, GraphQLError, getIntrospectionQuery, introspectionFromSchema } from 'graphql'; import { createGraphQLError, ExecutionRequest, ExecutionResult } from '@graphql-tools/utils'; @@ -42,7 +42,7 @@ describe('visiting results', () => { expect(visitedResult).toEqual(result); }); - it('should visit with a request with introspection fields without throwing', async () => { + it('should visit with a request with typename fields without throwing', async () => { const introspectionRequest: ExecutionRequest = { document: parse('{ test { field __typename } }'), variables: {}, @@ -58,6 +58,25 @@ describe('visiting results', () => { expect(() => visitResult(result, introspectionRequest, schema, undefined)).not.toThrow(); }); + it('should visit with a request with introspection fields without throwing', async () => { + const introspectionRequest: ExecutionRequest = { + document: parse(getIntrospectionQuery()), + variables: {}, + }; + const result: any = { + data: introspectionFromSchema(schema), + }; + expect(() => + visitResult(result, introspectionRequest, schema, { + Query: { + __enter(val) { + return val; + }, + }, + }) + ).not.toThrow(); + }); + it('should successfully modify the result using an object type result visitor', async () => { const result = { data: {