Skip to content

Commit 5b2b39e

Browse files
committed
Move schema validation into separate step (type constructors)
This is the second step of moving work from type constructors to the schema validation function.
1 parent cddcad3 commit 5b2b39e

10 files changed

+1324
-1155
lines changed

src/type/__tests__/definition-test.js

Lines changed: 289 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -270,7 +270,7 @@ describe('Type System: Example', () => {
270270
expect(schema.getTypeMap().NestedInputObject).to.equal(NestedInputObject);
271271
});
272272

273-
it("includes interfaces' subtypes in the type map", () => {
273+
it('includes interface possible types in the type map', () => {
274274
const SomeInterface = new GraphQLInterfaceType({
275275
name: 'SomeInterface',
276276
fields: {
@@ -374,26 +374,13 @@ describe('Type System: Example', () => {
374374
});
375375
});
376376

377-
it('prohibits putting non-Object types in unions', () => {
378-
const badUnionTypes = [
379-
GraphQLInt,
380-
GraphQLNonNull(GraphQLInt),
381-
GraphQLList(GraphQLInt),
382-
InterfaceType,
383-
UnionType,
384-
EnumType,
385-
InputObjectType,
386-
];
387-
badUnionTypes.forEach(x => {
388-
expect(() =>
389-
new GraphQLUnionType({ name: 'BadUnion', types: [x] }).getTypes(),
390-
).to.throw(
391-
`BadUnion may only contain Object types, it cannot contain: ${x}.`,
392-
);
393-
});
377+
it('prohibits nesting NonNull inside NonNull', () => {
378+
expect(() => GraphQLNonNull(GraphQLNonNull(GraphQLInt))).to.throw(
379+
'Expected Int! to be a GraphQL nullable type.',
380+
);
394381
});
395382

396-
it("allows a thunk for Union's types", () => {
383+
it('allows a thunk for Union member types', () => {
397384
const union = new GraphQLUnionType({
398385
name: 'ThunkUnion',
399386
types: () => [ObjectType],
@@ -470,6 +457,289 @@ describe('Type System: Example', () => {
470457
});
471458
});
472459

460+
describe('Field config must be object', () => {
461+
it('accepts an Object type with a field function', () => {
462+
const objType = new GraphQLObjectType({
463+
name: 'SomeObject',
464+
fields() {
465+
return {
466+
f: { type: GraphQLString },
467+
};
468+
},
469+
});
470+
expect(objType.getFields().f.type).to.equal(GraphQLString);
471+
});
472+
473+
it('rejects an Object type field with undefined config', () => {
474+
const objType = new GraphQLObjectType({
475+
name: 'SomeObject',
476+
fields: {
477+
f: undefined,
478+
},
479+
});
480+
expect(() => objType.getFields()).to.throw(
481+
'SomeObject.f field config must be an object',
482+
);
483+
});
484+
485+
it('rejects an Object type with incorrectly typed fields', () => {
486+
const objType = new GraphQLObjectType({
487+
name: 'SomeObject',
488+
fields: [{ field: GraphQLString }],
489+
});
490+
expect(() => objType.getFields()).to.throw(
491+
'SomeObject fields must be an object with field names as keys or a ' +
492+
'function which returns such an object.',
493+
);
494+
});
495+
496+
it('rejects an Object type with a field function that returns incorrect type', () => {
497+
const objType = new GraphQLObjectType({
498+
name: 'SomeObject',
499+
fields() {
500+
return [{ field: GraphQLString }];
501+
},
502+
});
503+
expect(() => objType.getFields()).to.throw(
504+
'SomeObject fields must be an object with field names as keys or a ' +
505+
'function which returns such an object.',
506+
);
507+
});
508+
});
509+
510+
describe('Field arg config must be object', () => {
511+
it('accepts an Object type with field args', () => {
512+
const objType = new GraphQLObjectType({
513+
name: 'SomeObject',
514+
fields: {
515+
goodField: {
516+
type: GraphQLString,
517+
args: {
518+
goodArg: { type: GraphQLString },
519+
},
520+
},
521+
},
522+
});
523+
expect(() => objType.getFields()).not.to.throw();
524+
});
525+
526+
it('rejects an Object type with incorrectly typed field args', () => {
527+
const objType = new GraphQLObjectType({
528+
name: 'SomeObject',
529+
fields: {
530+
badField: {
531+
type: GraphQLString,
532+
args: [{ badArg: GraphQLString }],
533+
},
534+
},
535+
});
536+
expect(() => objType.getFields()).to.throw(
537+
'SomeObject.badField args must be an object with argument names as keys.',
538+
);
539+
});
540+
});
541+
542+
describe('Object interfaces must be array', () => {
543+
it('accepts an Object type with array interfaces', () => {
544+
const objType = new GraphQLObjectType({
545+
name: 'SomeObject',
546+
interfaces: [InterfaceType],
547+
fields: { f: { type: GraphQLString } },
548+
});
549+
expect(objType.getInterfaces()[0]).to.equal(InterfaceType);
550+
});
551+
552+
it('accepts an Object type with interfaces as a function returning an array', () => {
553+
const objType = new GraphQLObjectType({
554+
name: 'SomeObject',
555+
interfaces: () => [InterfaceType],
556+
fields: { f: { type: GraphQLString } },
557+
});
558+
expect(objType.getInterfaces()[0]).to.equal(InterfaceType);
559+
});
560+
561+
it('rejects an Object type with incorrectly typed interfaces', () => {
562+
const objType = new GraphQLObjectType({
563+
name: 'SomeObject',
564+
interfaces: {},
565+
fields: { f: { type: GraphQLString } },
566+
});
567+
expect(() => objType.getInterfaces()).to.throw(
568+
'SomeObject interfaces must be an Array or a function which returns an Array.',
569+
);
570+
});
571+
572+
it('rejects an Object type with interfaces as a function returning an incorrect type', () => {
573+
const objType = new GraphQLObjectType({
574+
name: 'SomeObject',
575+
interfaces() {
576+
return {};
577+
},
578+
fields: { f: { type: GraphQLString } },
579+
});
580+
expect(() => objType.getInterfaces()).to.throw(
581+
'SomeObject interfaces must be an Array or a function which returns an Array.',
582+
);
583+
});
584+
});
585+
586+
describe('Type System: Input Objects must have fields', () => {
587+
it('accepts an Input Object type with fields', () => {
588+
const inputObjType = new GraphQLInputObjectType({
589+
name: 'SomeInputObject',
590+
fields: {
591+
f: { type: GraphQLString },
592+
},
593+
});
594+
expect(inputObjType.getFields().f.type).to.equal(GraphQLString);
595+
});
596+
597+
it('accepts an Input Object type with a field function', () => {
598+
const inputObjType = new GraphQLInputObjectType({
599+
name: 'SomeInputObject',
600+
fields() {
601+
return {
602+
f: { type: GraphQLString },
603+
};
604+
},
605+
});
606+
expect(inputObjType.getFields().f.type).to.equal(GraphQLString);
607+
});
608+
609+
it('rejects an Input Object type with incorrect fields', () => {
610+
const inputObjType = new GraphQLInputObjectType({
611+
name: 'SomeInputObject',
612+
fields: [],
613+
});
614+
expect(() => inputObjType.getFields()).to.throw(
615+
'SomeInputObject fields must be an object with field names as keys or a ' +
616+
'function which returns such an object.',
617+
);
618+
});
619+
620+
it('rejects an Input Object type with fields function that returns incorrect type', () => {
621+
const inputObjType = new GraphQLInputObjectType({
622+
name: 'SomeInputObject',
623+
fields() {
624+
return [];
625+
},
626+
});
627+
expect(() => inputObjType.getFields()).to.throw(
628+
'SomeInputObject fields must be an object with field names as keys or a ' +
629+
'function which returns such an object.',
630+
);
631+
});
632+
});
633+
634+
describe('Type System: Input Object fields must not have resolvers', () => {
635+
it('rejects an Input Object type with resolvers', () => {
636+
const inputObjType = new GraphQLInputObjectType({
637+
name: 'SomeInputObject',
638+
fields: {
639+
f: {
640+
type: GraphQLString,
641+
resolve: () => {
642+
return 0;
643+
},
644+
},
645+
},
646+
});
647+
expect(() => inputObjType.getFields()).to.throw(
648+
'SomeInputObject.f field type has a resolve property, ' +
649+
'but Input Types cannot define resolvers.',
650+
);
651+
});
652+
653+
it('rejects an Input Object type with resolver constant', () => {
654+
const inputObjType = new GraphQLInputObjectType({
655+
name: 'SomeInputObject',
656+
fields: {
657+
f: {
658+
type: GraphQLString,
659+
resolve: {},
660+
},
661+
},
662+
});
663+
expect(() => inputObjType.getFields()).to.throw(
664+
'SomeInputObject.f field type has a resolve property, ' +
665+
'but Input Types cannot define resolvers.',
666+
);
667+
});
668+
});
669+
670+
describe('Type System: Enum types must be well defined', () => {
671+
it('accepts a well defined Enum type with empty value definition', () => {
672+
const enumType = new GraphQLEnumType({
673+
name: 'SomeEnum',
674+
values: {
675+
FOO: {},
676+
BAR: {},
677+
},
678+
});
679+
expect(enumType.getValue('FOO').value).to.equal('FOO');
680+
expect(enumType.getValue('BAR').value).to.equal('BAR');
681+
});
682+
683+
it('accepts a well defined Enum type with internal value definition', () => {
684+
const enumType = new GraphQLEnumType({
685+
name: 'SomeEnum',
686+
values: {
687+
FOO: { value: 10 },
688+
BAR: { value: 20 },
689+
},
690+
});
691+
expect(enumType.getValue('FOO').value).to.equal(10);
692+
expect(enumType.getValue('BAR').value).to.equal(20);
693+
});
694+
695+
it('rejects an Enum type with incorrectly typed values', () => {
696+
const enumType = new GraphQLEnumType({
697+
name: 'SomeEnum',
698+
values: [{ FOO: 10 }],
699+
});
700+
expect(() => enumType.getValue()).to.throw(
701+
'SomeEnum values must be an object with value names as keys.',
702+
);
703+
});
704+
705+
it('rejects an Enum type with missing value definition', () => {
706+
const enumType = new GraphQLEnumType({
707+
name: 'SomeEnum',
708+
values: { FOO: null },
709+
});
710+
expect(() => enumType.getValues()).to.throw(
711+
'SomeEnum.FOO must refer to an object with a "value" key representing ' +
712+
'an internal value but got: null.',
713+
);
714+
});
715+
716+
it('rejects an Enum type with incorrectly typed value definition', () => {
717+
const enumType = new GraphQLEnumType({
718+
name: 'SomeEnum',
719+
values: { FOO: 10 },
720+
});
721+
expect(() => enumType.getValues()).to.throw(
722+
'SomeEnum.FOO must refer to an object with a "value" key representing ' +
723+
'an internal value but got: 10.',
724+
);
725+
});
726+
727+
it('does not allow isDeprecated without deprecationReason on enum', () => {
728+
const enumType = new GraphQLEnumType({
729+
name: 'SomeEnum',
730+
values: {
731+
FOO: {
732+
isDeprecated: true,
733+
},
734+
},
735+
});
736+
expect(() => enumType.getValues()).to.throw(
737+
'SomeEnum.FOO should provide "deprecationReason" instead ' +
738+
'of "isDeprecated".',
739+
);
740+
});
741+
});
742+
473743
describe('Type System: List must accept only types', () => {
474744
const types = [
475745
GraphQLString,

0 commit comments

Comments
 (0)