From a8d195ffdfdd2b391ba04ac5176c255eb0255010 Mon Sep 17 00:00:00 2001 From: Ivan Goncharov Date: Mon, 14 Jun 2021 22:30:02 +0300 Subject: [PATCH] simplify validation harness by extracting union types into approriate tests --- .../__tests__/FieldsOnCorrectTypeRule-test.ts | 61 +++++++++++++++++-- .../PossibleFragmentSpreadsRule-test.ts | 57 ++++++++++++++++- src/validation/__tests__/harness.ts | 32 ++-------- src/validation/__tests__/validation-test.ts | 34 ++++++----- 4 files changed, 135 insertions(+), 49 deletions(-) diff --git a/src/validation/__tests__/FieldsOnCorrectTypeRule-test.ts b/src/validation/__tests__/FieldsOnCorrectTypeRule-test.ts index 6ec857a683..21d638641f 100644 --- a/src/validation/__tests__/FieldsOnCorrectTypeRule-test.ts +++ b/src/validation/__tests__/FieldsOnCorrectTypeRule-test.ts @@ -10,16 +10,49 @@ import { buildSchema } from '../../utilities/buildASTSchema'; import { validate } from '../validate'; import { FieldsOnCorrectTypeRule } from '../rules/FieldsOnCorrectTypeRule'; -import { expectValidationErrors } from './harness'; +import { expectValidationErrorsWithSchema } from './harness'; function expectErrors(queryStr: string) { - return expectValidationErrors(FieldsOnCorrectTypeRule, queryStr); + return expectValidationErrorsWithSchema( + testSchema, + FieldsOnCorrectTypeRule, + queryStr, + ); } function expectValid(queryStr: string) { expectErrors(queryStr).to.deep.equal([]); } +const testSchema = buildSchema(` + interface Pet { + name: String + } + + type Dog implements Pet { + name: String + nickname: String + barkVolume: Int + } + + type Cat implements Pet { + name: String + nickname: String + meowVolume: Int + } + + union CatOrDog = Cat | Dog + + type Human { + name: String + pets: [Pet] + } + + type Query { + human: Human + } +`); + describe('Validate: Fields on correct type', () => { it('Object field selection', () => { expectValid(` @@ -237,7 +270,7 @@ describe('Validate: Fields on correct type', () => { `).to.deep.equal([ { message: - 'Cannot query field "name" on type "CatOrDog". Did you mean to use an inline fragment on "Being", "Pet", "Canine", "Cat", or "Dog"?', + 'Cannot query field "name" on type "CatOrDog". Did you mean to use an inline fragment on "Pet", "Cat", or "Dog"?', locations: [{ line: 3, column: 9 }], }, ]); @@ -332,7 +365,7 @@ describe('Validate: Fields on correct type', () => { }); it('Sort type suggestions based on inheritance order', () => { - const schema = buildSchema(` + const interfaceSchema = buildSchema(` interface T { bar: String } type Query { t: T } @@ -352,9 +385,27 @@ describe('Validate: Fields on correct type', () => { } `); - expectErrorMessage(schema, '{ t { foo } }').to.equal( + expectErrorMessage(interfaceSchema, '{ t { foo } }').to.equal( 'Cannot query field "foo" on type "T". Did you mean to use an inline fragment on "Z", "Y", or "X"?', ); + + const unionSchema = buildSchema(` + interface Animal { name: String } + interface Mammal implements Animal { name: String } + + interface Canine implements Animal & Mammal { name: String } + type Dog implements Animal & Mammal & Canine { name: String } + + interface Feline implements Animal & Mammal { name: String } + type Cat implements Animal & Mammal & Feline { name: String } + + union CatOrDog = Cat | Dog + type Query { catOrDog: CatOrDog } + `); + + expectErrorMessage(unionSchema, '{ catOrDog { name } }').to.equal( + 'Cannot query field "name" on type "CatOrDog". Did you mean to use an inline fragment on "Animal", "Mammal", "Canine", "Dog", or "Feline"?', + ); }); it('Limits lots of type suggestions', () => { diff --git a/src/validation/__tests__/PossibleFragmentSpreadsRule-test.ts b/src/validation/__tests__/PossibleFragmentSpreadsRule-test.ts index 267dbd3b38..c93d4d6457 100644 --- a/src/validation/__tests__/PossibleFragmentSpreadsRule-test.ts +++ b/src/validation/__tests__/PossibleFragmentSpreadsRule-test.ts @@ -1,17 +1,70 @@ import { describe, it } from 'mocha'; +import { buildSchema } from '../../utilities/buildASTSchema'; + import { PossibleFragmentSpreadsRule } from '../rules/PossibleFragmentSpreadsRule'; -import { expectValidationErrors } from './harness'; +import { expectValidationErrorsWithSchema } from './harness'; function expectErrors(queryStr: string) { - return expectValidationErrors(PossibleFragmentSpreadsRule, queryStr); + return expectValidationErrorsWithSchema( + testSchema, + PossibleFragmentSpreadsRule, + queryStr, + ); } function expectValid(queryStr: string) { expectErrors(queryStr).to.deep.equal([]); } +const testSchema = buildSchema(` + interface Being { + name: String + } + + interface Pet implements Being { + name: String + } + + type Dog implements Being & Pet { + name: String + barkVolume: Int + } + + type Cat implements Being & Pet { + name: String + meowVolume: Int + } + + union CatOrDog = Cat | Dog + + interface Intelligent { + iq: Int + } + + type Human implements Being & Intelligent { + name: String + pets: [Pet] + iq: Int + } + + type Alien implements Being & Intelligent { + name: String + iq: Int + } + + union DogOrHuman = Dog | Human + + union HumanOrAlien = Human | Alien + + type Query { + catOrDog: CatOrDog + dogOrHuman: DogOrHuman + humanOrAlien: HumanOrAlien + } +`); + describe('Validate: Possible fragment spreads', () => { it('of the same object', () => { expectValid(` diff --git a/src/validation/__tests__/harness.ts b/src/validation/__tests__/harness.ts index 8d6beccc25..139827af11 100644 --- a/src/validation/__tests__/harness.ts +++ b/src/validation/__tests__/harness.ts @@ -12,20 +12,16 @@ import { validate, validateSDL } from '../validate'; import type { ValidationRule, SDLValidationRule } from '../ValidationContext'; export const testSchema: GraphQLSchema = buildSchema(` - interface Being { - name(surname: Boolean): String - } - interface Mammal { mother: Mammal father: Mammal } - interface Pet implements Being { + interface Pet { name(surname: Boolean): String } - interface Canine implements Mammal & Being { + interface Canine implements Mammal { name(surname: Boolean): String mother: Canine father: Canine @@ -37,7 +33,7 @@ export const testSchema: GraphQLSchema = buildSchema(` DOWN } - type Dog implements Being & Pet & Mammal & Canine { + type Dog implements Pet & Mammal & Canine { name(surname: Boolean): String nickname: String barkVolume: Int @@ -49,7 +45,7 @@ export const testSchema: GraphQLSchema = buildSchema(` father: Dog } - type Cat implements Being & Pet { + type Cat implements Pet { name(surname: Boolean): String nickname: String meows: Boolean @@ -59,27 +55,12 @@ export const testSchema: GraphQLSchema = buildSchema(` union CatOrDog = Cat | Dog - interface Intelligent { - iq: Int - } - - type Human implements Being & Intelligent { + type Human { name(surname: Boolean): String pets: [Pet] relatives: [Human] - iq: Int } - type Alien implements Being & Intelligent { - name(surname: Boolean): String - numEyes: Int - iq: Int - } - - union DogOrHuman = Dog | Human - - union HumanOrAlien = Human | Alien - enum FurColor { BROWN BLACK @@ -120,13 +101,10 @@ export const testSchema: GraphQLSchema = buildSchema(` type QueryRoot { human(id: ID): Human - alien: Alien dog: Dog cat: Cat pet: Pet catOrDog: CatOrDog - dogOrHuman: DogOrHuman - humanOrAlien: HumanOrAlien complicatedArgs: ComplicatedArgs } diff --git a/src/validation/__tests__/validation-test.ts b/src/validation/__tests__/validation-test.ts index ed68d68788..af8508912f 100644 --- a/src/validation/__tests__/validation-test.ts +++ b/src/validation/__tests__/validation-test.ts @@ -23,12 +23,14 @@ describe('Validate: Supports full validation', () => { it('validates queries', () => { const doc = parse(` query { - catOrDog { - ... on Cat { - furColor - } - ... on Dog { - isHouseTrained + human { + pets { + ... on Cat { + meowsVolume + } + ... on Dog { + barkVolume + } } } } @@ -60,12 +62,14 @@ describe('Validate: Supports full validation', () => { const doc = parse(` query { - catOrDog { - ... on Cat { - furColor - } - ... on Dog { - isHouseTrained + human { + pets { + ... on Cat { + meowsVolume + } + ... on Dog { + barkVolume + } } } } @@ -75,9 +79,9 @@ describe('Validate: Supports full validation', () => { const errorMessages = errors.map((error) => error.message); expect(errorMessages).to.deep.equal([ - 'Cannot query field "catOrDog" on type "QueryRoot". Did you mean "catOrDog"?', - 'Cannot query field "furColor" on type "Cat". Did you mean "furColor"?', - 'Cannot query field "isHouseTrained" on type "Dog". Did you mean "isHouseTrained"?', + 'Cannot query field "human" on type "QueryRoot". Did you mean "human"?', + 'Cannot query field "meowsVolume" on type "Cat". Did you mean "meowsVolume"?', + 'Cannot query field "barkVolume" on type "Dog". Did you mean "barkVolume"?', ]); });