diff --git a/src/type/__tests__/definition-test.ts b/src/type/__tests__/definition-test.ts index 617209206d..5c07c1c0e3 100644 --- a/src/type/__tests__/definition-test.ts +++ b/src/type/__tests__/definition-test.ts @@ -7,7 +7,16 @@ import { inspect } from '../../jsutils/inspect.js'; import { Kind } from '../../language/kinds.js'; import { parseConstValue } from '../../language/parser.js'; -import type { GraphQLNullableType, GraphQLType } from '../definition.js'; +import type { + GraphQLEnumTypeConfig, + GraphQLInputObjectTypeConfig, + GraphQLInterfaceTypeConfig, + GraphQLNullableType, + GraphQLObjectTypeConfig, + GraphQLScalarTypeConfig, + GraphQLType, + GraphQLUnionTypeConfig, +} from '../definition.js'; import { GraphQLEnumType, GraphQLInputObjectType, @@ -38,32 +47,43 @@ const ListOfNonNullScalarsType = new GraphQLList(NonNullScalarType); const NonNullListOfScalars = new GraphQLNonNull(ListOfScalarsType); /* c8 ignore next */ -const dummyFunc = () => expect.fail('Never called and used as a placeholder'); +const passThroughFunc = (arg: any) => arg; +const dummyAny = {} as any; describe('Type System: Scalars', () => { - it('accepts a Scalar type defining serialize', () => { - expect(() => new GraphQLScalarType({ name: 'SomeScalar' })).to.not.throw(); - }); - - it('accepts a Scalar type defining specifiedByURL', () => { - expect( - () => - new GraphQLScalarType({ - name: 'SomeScalar', - specifiedByURL: 'https://example.com/foo_spec', - }), - ).not.to.throw(); - }); - - it('accepts a Scalar type defining parseValue and parseConstLiteral', () => { - expect( - () => - new GraphQLScalarType({ - name: 'SomeScalar', - parseValue: dummyFunc, - parseConstLiteral: dummyFunc, - }), - ).to.not.throw(); + it('can be converted from a minimal configuration object', () => { + const someScalar = new GraphQLScalarType({ name: 'SomeScalar' }); + expect(someScalar.toConfig()).to.deep.equal({ + name: 'SomeScalar', + description: undefined, + specifiedByURL: undefined, + serialize: someScalar.serialize, + parseValue: someScalar.parseValue, + parseLiteral: someScalar.parseLiteral, + parseConstLiteral: undefined, + valueToLiteral: undefined, + extensions: {}, + astNode: undefined, + extensionASTNodes: [], + }); + }); + + it('can be converted to a configuration object', () => { + const someScalarConfig: GraphQLScalarTypeConfig = { + name: 'SomeScalar', + description: 'SomeScalar description.', + specifiedByURL: 'https://example.com/foo_spec', + serialize: passThroughFunc, + parseValue: passThroughFunc, + parseLiteral: passThroughFunc, + parseConstLiteral: passThroughFunc, + valueToLiteral: passThroughFunc, + extensions: { someExtension: 'extension' }, + astNode: dummyAny, + extensionASTNodes: [dummyAny], + }; + const someScalar = new GraphQLScalarType(someScalarConfig); + expect(someScalar.toConfig()).to.deep.equal(someScalarConfig); }); it('provides default methods if omitted', () => { @@ -97,7 +117,7 @@ describe('Type System: Scalars', () => { () => new GraphQLScalarType({ name: 'SomeScalar', - parseLiteral: dummyFunc, + parseLiteral: passThroughFunc, }), ).to.throw( 'SomeScalar must provide both "parseValue" and "parseLiteral" functions.', @@ -109,7 +129,7 @@ describe('Type System: Scalars', () => { () => new GraphQLScalarType({ name: 'SomeScalar', - parseConstLiteral: dummyFunc, + parseConstLiteral: passThroughFunc, }), ).to.throw( 'SomeScalar must provide both "parseValue" and "parseConstLiteral" functions.', @@ -118,6 +138,59 @@ describe('Type System: Scalars', () => { }); describe('Type System: Objects', () => { + it('can be converted from a minimal configuration object', () => { + const someObject = new GraphQLObjectType({ + name: 'SomeObject', + fields: {}, + }); + expect(someObject.toConfig()).to.deep.equal({ + name: 'SomeObject', + description: undefined, + interfaces: [], + fields: {}, + isTypeOf: undefined, + extensions: {}, + astNode: undefined, + extensionASTNodes: [], + }); + }); + + it('can be converted to a configuration object', () => { + const someObjectConfig: GraphQLObjectTypeConfig = { + name: 'SomeObject', + description: 'SomeObject description.', + interfaces: [InterfaceType], + fields: { + f: { + description: 'Field description.', + type: ScalarType, + args: { + input: { + description: 'Argument description.', + type: ScalarType, + defaultValue: 'DefaultValue', + defaultValueLiteral: undefined, + deprecationReason: 'Argument deprecation reason.', + extensions: { someExtension: 'extension' }, + astNode: dummyAny, + }, + }, + resolve: passThroughFunc, + subscribe: passThroughFunc, + deprecationReason: 'Field deprecation reason.', + extensions: { someExtension: 'extension' }, + astNode: dummyAny, + }, + }, + isTypeOf: passThroughFunc, + extensions: { someExtension: 'extension' }, + astNode: dummyAny, + extensionASTNodes: [dummyAny], + }; + const someObject = new GraphQLObjectType(someObjectConfig); + expect(someObject.toConfig()).to.deep.equal(someObjectConfig); + }); + it('does not mutate passed field definitions', () => { const outputFields = { field1: { type: ScalarType }, @@ -281,7 +354,7 @@ describe('Type System: Objects', () => { fields: { f: { type: ScalarType, - resolve: dummyFunc, + resolve: passThroughFunc, }, }, }); @@ -336,7 +409,60 @@ describe('Type System: Objects', () => { }); describe('Type System: Interfaces', () => { - it('accepts an Interface type defining resolveType', () => { + it('can be converted from a minimal configuration object', () => { + const someInterface = new GraphQLInterfaceType({ + name: 'SomeInterface', + fields: {}, + }); + expect(someInterface.toConfig()).to.deep.equal({ + name: 'SomeInterface', + description: undefined, + interfaces: [], + fields: {}, + resolveType: undefined, + extensions: {}, + astNode: undefined, + extensionASTNodes: [], + }); + }); + + it('can be converted to a configuration object', () => { + const someInterfaceConfig: GraphQLInterfaceTypeConfig = { + name: 'SomeInterface', + description: 'SomeInterface description.', + interfaces: [InterfaceType], + fields: { + f: { + description: 'Field description.', + type: ScalarType, + args: { + input: { + description: 'Argument description.', + type: ScalarType, + defaultValue: undefined, + defaultValueLiteral: dummyAny, + deprecationReason: 'Argument deprecation reason.', + extensions: { someExtension: 'extension' }, + astNode: dummyAny, + }, + }, + resolve: passThroughFunc, + subscribe: passThroughFunc, + deprecationReason: 'Field deprecation reason.', + extensions: { someExtension: 'extension' }, + astNode: dummyAny, + }, + }, + resolveType: passThroughFunc, + extensions: {}, + astNode: {} as any, + extensionASTNodes: [], + }; + const someInterface = new GraphQLInterfaceType(someInterfaceConfig); + expect(someInterface.toConfig()).to.deep.equal(someInterfaceConfig); + }); + + it('accepts an Interface type defining a field', () => { expect( () => new GraphQLInterfaceType({ @@ -346,6 +472,28 @@ describe('Type System: Interfaces', () => { ).to.not.throw(); }); + it('accepts an Interface type with a field function', () => { + const interfaceType = new GraphQLInterfaceType({ + name: 'SomeInterface', + fields: () => ({ + f: { type: ScalarType }, + }), + }); + expect(interfaceType.getFields()).to.deep.equal({ + f: { + name: 'f', + description: undefined, + type: ScalarType, + args: [], + resolve: undefined, + subscribe: undefined, + deprecationReason: undefined, + extensions: {}, + astNode: undefined, + }, + }); + }); + it('accepts an Interface type with an array of interfaces', () => { const implementing = new GraphQLInterfaceType({ name: 'AnotherInterface', @@ -372,6 +520,36 @@ describe('Type System: Interfaces', () => { }); describe('Type System: Unions', () => { + it('can be converted from a minimal configuration object', () => { + const someUnion = new GraphQLUnionType({ + name: 'SomeUnion', + types: [], + }); + expect(someUnion.toConfig()).to.deep.equal({ + name: 'SomeUnion', + description: undefined, + types: [], + resolveType: undefined, + extensions: {}, + astNode: undefined, + extensionASTNodes: [], + }); + }); + + it('can be converted to a configuration object', () => { + const someUnionConfig: GraphQLUnionTypeConfig = { + name: 'SomeUnion', + description: 'SomeUnion description.', + types: [ObjectType], + resolveType: passThroughFunc, + extensions: {}, + astNode: {} as any, + extensionASTNodes: [], + }; + const someUnion = new GraphQLUnionType(someUnionConfig); + expect(someUnion.toConfig()).to.deep.equal(someUnionConfig); + }); + it('accepts a Union type defining resolveType', () => { expect( () => @@ -414,6 +592,39 @@ describe('Type System: Unions', () => { }); describe('Type System: Enums', () => { + it('can be converted from a minimal configuration object', () => { + const someEnum = new GraphQLEnumType({ name: 'SomeEnum', values: {} }); + expect(someEnum.toConfig()).to.deep.equal({ + name: 'SomeEnum', + description: undefined, + values: {}, + extensions: {}, + astNode: undefined, + extensionASTNodes: [], + }); + }); + + it('can be converted to a configuration object', () => { + const someEnumConfig: GraphQLEnumTypeConfig = { + name: 'SomeEnum', + description: 'SomeEnum description.', + values: { + FOO: { + description: 'FOO description.', + value: 'foo', + deprecationReason: 'Value deprecation reason.', + extensions: { someExtension: 'extension' }, + astNode: dummyAny, + }, + }, + extensions: { someExtension: 'extension' }, + astNode: dummyAny, + extensionASTNodes: [dummyAny], + }; + const someEnum = new GraphQLEnumType(someEnumConfig); + expect(someEnum.toConfig()).to.deep.equal(someEnumConfig); + }); + it('defines an enum type with deprecated value', () => { const EnumTypeWithDeprecatedValue = new GraphQLEnumType({ name: 'EnumWithDeprecatedValue', @@ -516,6 +727,46 @@ describe('Type System: Enums', () => { }); describe('Type System: Input Objects', () => { + it('can be converted from a minimal configuration object', () => { + const inputObject = new GraphQLInputObjectType({ + name: 'SomeInputObject', + fields: {}, + }); + expect(inputObject.toConfig()).to.deep.equal({ + name: 'SomeInputObject', + description: undefined, + fields: {}, + isOneOf: false, + extensions: {}, + astNode: undefined, + extensionASTNodes: [], + }); + }); + + it('can be converted to a configuration object', () => { + const someInputObjectConfig: GraphQLInputObjectTypeConfig = { + name: 'SomeInputObject', + description: 'SomeObject description.', + fields: { + input: { + description: 'Argument description.', + type: ScalarType, + defaultValue: 'DefaultValue', + defaultValueLiteral: undefined, + deprecationReason: 'Argument deprecation reason.', + extensions: { someExtension: 'extension' }, + astNode: dummyAny, + }, + }, + isOneOf: true, + extensions: { someExtension: 'extension' }, + astNode: dummyAny, + extensionASTNodes: [dummyAny], + }; + const someInputObject = new GraphQLInputObjectType(someInputObjectConfig); + expect(someInputObject.toConfig()).to.deep.equal(someInputObjectConfig); + }); + describe('Input Objects must have fields', () => { it('accepts an Input Object type with fields', () => { const inputObjType = new GraphQLInputObjectType({