diff --git a/src/validation/__tests__/ExecutableDefinitions-test.js b/src/validation/__tests__/ExecutableDefinitions-test.js index 4ed2b8c65f..ba0c87797f 100644 --- a/src/validation/__tests__/ExecutableDefinitions-test.js +++ b/src/validation/__tests__/ExecutableDefinitions-test.js @@ -8,12 +8,20 @@ */ import { describe, it } from 'mocha'; -import { expectPassesRule, expectFailsRule } from './harness'; +import { expectValidationErrors } from './harness'; import { ExecutableDefinitions, nonExecutableDefinitionMessage, } from '../rules/ExecutableDefinitions'; +function expectErrors(queryStr) { + return expectValidationErrors(ExecutableDefinitions, queryStr); +} + +function expectValid(queryStr) { + expectErrors(queryStr).to.deep.equal([]); +} + function nonExecutableDefinition(defName, line, column) { return { message: nonExecutableDefinitionMessage(defName), @@ -23,22 +31,17 @@ function nonExecutableDefinition(defName, line, column) { describe('Validate: Executable definitions', () => { it('with only operation', () => { - expectPassesRule( - ExecutableDefinitions, - ` + expectValid(` query Foo { dog { name } } - `, - ); + `); }); it('with operation and fragment', () => { - expectPassesRule( - ExecutableDefinitions, - ` + expectValid(` query Foo { dog { name @@ -49,14 +52,11 @@ describe('Validate: Executable definitions', () => { fragment Frag on Dog { name } - `, - ); + `); }); it('with type definition', () => { - expectFailsRule( - ExecutableDefinitions, - ` + expectErrors(` query Foo { dog { name @@ -70,18 +70,14 @@ describe('Validate: Executable definitions', () => { extend type Dog { color: String } - `, - [ - nonExecutableDefinition('Cow', 8, 7), - nonExecutableDefinition('Dog', 12, 7), - ], - ); + `).to.deep.equal([ + nonExecutableDefinition('Cow', 8, 7), + nonExecutableDefinition('Dog', 12, 7), + ]); }); it('with schema definition', () => { - expectFailsRule( - ExecutableDefinitions, - ` + expectErrors(` schema { query: Query } @@ -91,12 +87,10 @@ describe('Validate: Executable definitions', () => { } extend schema @directive - `, - [ - nonExecutableDefinition('schema', 2, 7), - nonExecutableDefinition('Query', 6, 7), - nonExecutableDefinition('schema', 10, 7), - ], - ); + `).to.deep.equal([ + nonExecutableDefinition('schema', 2, 7), + nonExecutableDefinition('Query', 6, 7), + nonExecutableDefinition('schema', 10, 7), + ]); }); }); diff --git a/src/validation/__tests__/FieldsOnCorrectType-test.js b/src/validation/__tests__/FieldsOnCorrectType-test.js index 20a0f451bb..62fbb1e08d 100644 --- a/src/validation/__tests__/FieldsOnCorrectType-test.js +++ b/src/validation/__tests__/FieldsOnCorrectType-test.js @@ -9,12 +9,20 @@ import { expect } from 'chai'; import { describe, it } from 'mocha'; -import { expectPassesRule, expectFailsRule } from './harness'; +import { expectValidationErrors } from './harness'; import { FieldsOnCorrectType, undefinedFieldMessage, } from '../rules/FieldsOnCorrectType'; +function expectErrors(queryStr) { + return expectValidationErrors(FieldsOnCorrectType, queryStr); +} + +function expectValid(queryStr) { + expectErrors(queryStr).to.deep.equal([]); +} + function undefinedField( field, type, @@ -36,231 +44,186 @@ function undefinedField( describe('Validate: Fields on correct type', () => { it('Object field selection', () => { - expectPassesRule( - FieldsOnCorrectType, - ` + expectValid(` fragment objectFieldSelection on Dog { __typename name } - `, - ); + `); }); it('Aliased object field selection', () => { - expectPassesRule( - FieldsOnCorrectType, - ` + expectValid(` fragment aliasedObjectFieldSelection on Dog { tn : __typename otherName : name } - `, - ); + `); }); it('Interface field selection', () => { - expectPassesRule( - FieldsOnCorrectType, - ` + expectValid(` fragment interfaceFieldSelection on Pet { __typename name } - `, - ); + `); }); it('Aliased interface field selection', () => { - expectPassesRule( - FieldsOnCorrectType, - ` + expectValid(` fragment interfaceFieldSelection on Pet { otherName : name } - `, - ); + `); }); it('Lying alias selection', () => { - expectPassesRule( - FieldsOnCorrectType, - ` + expectValid(` fragment lyingAliasSelection on Dog { name : nickname } - `, - ); + `); }); it('Ignores fields on unknown type', () => { - expectPassesRule( - FieldsOnCorrectType, - ` + expectValid(` fragment unknownSelection on UnknownType { unknownField } - `, - ); + `); }); it('reports errors when type is known again', () => { - expectFailsRule( - FieldsOnCorrectType, - ` + expectErrors(` fragment typeKnownAgain on Pet { unknown_pet_field { ... on Cat { unknown_cat_field } } - }`, - [ - undefinedField('unknown_pet_field', 'Pet', [], [], 3, 9), - undefinedField('unknown_cat_field', 'Cat', [], [], 5, 13), - ], - ); + } + `).to.deep.equal([ + undefinedField('unknown_pet_field', 'Pet', [], [], 3, 9), + undefinedField('unknown_cat_field', 'Cat', [], [], 5, 13), + ]); }); it('Field not defined on fragment', () => { - expectFailsRule( - FieldsOnCorrectType, - ` + expectErrors(` fragment fieldNotDefined on Dog { meowVolume - }`, - [undefinedField('meowVolume', 'Dog', [], ['barkVolume'], 3, 9)], - ); + } + `).to.deep.equal([ + undefinedField('meowVolume', 'Dog', [], ['barkVolume'], 3, 9), + ]); }); it('Ignores deeply unknown field', () => { - expectFailsRule( - FieldsOnCorrectType, - ` + expectErrors(` fragment deepFieldNotDefined on Dog { unknown_field { deeper_unknown_field } - }`, - [undefinedField('unknown_field', 'Dog', [], [], 3, 9)], - ); + } + `).to.deep.equal([undefinedField('unknown_field', 'Dog', [], [], 3, 9)]); }); it('Sub-field not defined', () => { - expectFailsRule( - FieldsOnCorrectType, - ` + expectErrors(` fragment subFieldNotDefined on Human { pets { unknown_field } - }`, - [undefinedField('unknown_field', 'Pet', [], [], 4, 11)], - ); + } + `).to.deep.equal([undefinedField('unknown_field', 'Pet', [], [], 4, 11)]); }); it('Field not defined on inline fragment', () => { - expectFailsRule( - FieldsOnCorrectType, - ` + expectErrors(` fragment fieldNotDefined on Pet { ... on Dog { meowVolume } - }`, - [undefinedField('meowVolume', 'Dog', [], ['barkVolume'], 4, 11)], - ); + } + `).to.deep.equal([ + undefinedField('meowVolume', 'Dog', [], ['barkVolume'], 4, 11), + ]); }); it('Aliased field target not defined', () => { - expectFailsRule( - FieldsOnCorrectType, - ` + expectErrors(` fragment aliasedFieldTargetNotDefined on Dog { volume : mooVolume - }`, - [undefinedField('mooVolume', 'Dog', [], ['barkVolume'], 3, 9)], - ); + } + `).to.deep.equal([ + undefinedField('mooVolume', 'Dog', [], ['barkVolume'], 3, 9), + ]); }); it('Aliased lying field target not defined', () => { - expectFailsRule( - FieldsOnCorrectType, - ` + expectErrors(` fragment aliasedLyingFieldTargetNotDefined on Dog { barkVolume : kawVolume - }`, - [undefinedField('kawVolume', 'Dog', [], ['barkVolume'], 3, 9)], - ); + } + `).to.deep.equal([ + undefinedField('kawVolume', 'Dog', [], ['barkVolume'], 3, 9), + ]); }); it('Not defined on interface', () => { - expectFailsRule( - FieldsOnCorrectType, - ` + expectErrors(` fragment notDefinedOnInterface on Pet { tailLength - }`, - [undefinedField('tailLength', 'Pet', [], [], 3, 9)], - ); + } + `).to.deep.equal([undefinedField('tailLength', 'Pet', [], [], 3, 9)]); }); it('Defined on implementors but not on interface', () => { - expectFailsRule( - FieldsOnCorrectType, - ` + expectErrors(` fragment definedOnImplementorsButNotInterface on Pet { nickname - }`, - [undefinedField('nickname', 'Pet', ['Dog', 'Cat'], ['name'], 3, 9)], - ); + } + `).to.deep.equal([ + undefinedField('nickname', 'Pet', ['Dog', 'Cat'], ['name'], 3, 9), + ]); }); it('Meta field selection on union', () => { - expectPassesRule( - FieldsOnCorrectType, - ` + expectValid(` fragment directFieldSelectionOnUnion on CatOrDog { __typename - }`, - ); + } + `); }); it('Direct field selection on union', () => { - expectFailsRule( - FieldsOnCorrectType, - ` + expectErrors(` fragment directFieldSelectionOnUnion on CatOrDog { directField - }`, - [undefinedField('directField', 'CatOrDog', [], [], 3, 9)], - ); + } + `).to.deep.equal([undefinedField('directField', 'CatOrDog', [], [], 3, 9)]); }); it('Defined on implementors queried on union', () => { - expectFailsRule( - FieldsOnCorrectType, - ` + expectErrors(` fragment definedOnImplementorsQueriedOnUnion on CatOrDog { name - }`, - [ - undefinedField( - 'name', - 'CatOrDog', - ['Being', 'Pet', 'Canine', 'Dog', 'Cat'], - [], - 3, - 9, - ), - ], - ); + } + `).to.deep.equal([ + undefinedField( + 'name', + 'CatOrDog', + ['Being', 'Pet', 'Canine', 'Dog', 'Cat'], + [], + 3, + 9, + ), + ]); }); it('valid field in inline fragment', () => { - expectPassesRule( - FieldsOnCorrectType, - ` + expectValid(` fragment objectFieldSelection on Pet { ... on Dog { name @@ -269,8 +232,7 @@ describe('Validate: Fields on correct type', () => { name } } - `, - ); + `); }); describe('Fields on correct type error message', () => { diff --git a/src/validation/__tests__/FragmentsOnCompositeTypes-test.js b/src/validation/__tests__/FragmentsOnCompositeTypes-test.js index da9ffa378c..1128b31bab 100644 --- a/src/validation/__tests__/FragmentsOnCompositeTypes-test.js +++ b/src/validation/__tests__/FragmentsOnCompositeTypes-test.js @@ -8,14 +8,22 @@ */ import { describe, it } from 'mocha'; -import { expectPassesRule, expectFailsRule } from './harness'; +import { expectValidationErrors } from './harness'; import { FragmentsOnCompositeTypes, inlineFragmentOnNonCompositeErrorMessage, fragmentOnNonCompositeErrorMessage, } from '../rules/FragmentsOnCompositeTypes'; -function error(fragName, typeName, line, column) { +function expectErrors(queryStr) { + return expectValidationErrors(FragmentsOnCompositeTypes, queryStr); +} + +function expectValid(queryStr) { + expectErrors(queryStr).to.deep.equal([]); +} + +function fragmentOnNonComposite(fragName, typeName, line, column) { return { message: fragmentOnNonCompositeErrorMessage(fragName, typeName), locations: [{ line, column }], @@ -24,116 +32,91 @@ function error(fragName, typeName, line, column) { describe('Validate: Fragments on composite types', () => { it('object is valid fragment type', () => { - expectPassesRule( - FragmentsOnCompositeTypes, - ` + expectValid(` fragment validFragment on Dog { barks } - `, - ); + `); }); it('interface is valid fragment type', () => { - expectPassesRule( - FragmentsOnCompositeTypes, - ` + expectValid(` fragment validFragment on Pet { name } - `, - ); + `); }); it('object is valid inline fragment type', () => { - expectPassesRule( - FragmentsOnCompositeTypes, - ` + expectValid(` fragment validFragment on Pet { ... on Dog { barks } } - `, - ); + `); }); it('inline fragment without type is valid', () => { - expectPassesRule( - FragmentsOnCompositeTypes, - ` + expectValid(` fragment validFragment on Pet { ... { name } } - `, - ); + `); }); it('union is valid fragment type', () => { - expectPassesRule( - FragmentsOnCompositeTypes, - ` + expectValid(` fragment validFragment on CatOrDog { __typename } - `, - ); + `); }); it('scalar is invalid fragment type', () => { - expectFailsRule( - FragmentsOnCompositeTypes, - ` + expectErrors(` fragment scalarFragment on Boolean { bad } - `, - [error('scalarFragment', 'Boolean', 2, 34)], - ); + `).to.deep.equal([ + fragmentOnNonComposite('scalarFragment', 'Boolean', 2, 34), + ]); }); it('enum is invalid fragment type', () => { - expectFailsRule( - FragmentsOnCompositeTypes, - ` + expectErrors(` fragment scalarFragment on FurColor { bad } - `, - [error('scalarFragment', 'FurColor', 2, 34)], - ); + `).to.deep.equal([ + fragmentOnNonComposite('scalarFragment', 'FurColor', 2, 34), + ]); }); it('input object is invalid fragment type', () => { - expectFailsRule( - FragmentsOnCompositeTypes, - ` + expectErrors(` fragment inputFragment on ComplexInput { stringField } - `, - [error('inputFragment', 'ComplexInput', 2, 33)], - ); + `).to.deep.equal([ + fragmentOnNonComposite('inputFragment', 'ComplexInput', 2, 33), + ]); }); it('scalar is invalid inline fragment type', () => { - expectFailsRule( - FragmentsOnCompositeTypes, - ` + expectErrors(` fragment invalidFragment on Pet { ... on String { barks } } - `, - [ - { - message: inlineFragmentOnNonCompositeErrorMessage('String'), - locations: [{ line: 3, column: 16 }], - }, - ], - ); + `).to.deep.equal([ + { + message: inlineFragmentOnNonCompositeErrorMessage('String'), + locations: [{ line: 3, column: 16 }], + }, + ]); }); }); diff --git a/src/validation/__tests__/KnownArgumentNames-test.js b/src/validation/__tests__/KnownArgumentNames-test.js index 3ef276fbfc..09f19376cd 100644 --- a/src/validation/__tests__/KnownArgumentNames-test.js +++ b/src/validation/__tests__/KnownArgumentNames-test.js @@ -9,11 +9,7 @@ import { describe, it } from 'mocha'; import { buildSchema } from '../../utilities'; -import { - expectPassesRule, - expectFailsRule, - expectSDLErrorsFromRule, -} from './harness'; +import { expectValidationErrors, expectSDLValidationErrors } from './harness'; import { KnownArgumentNames, KnownArgumentNamesOnDirectives, @@ -21,10 +17,25 @@ import { unknownDirectiveArgMessage, } from '../rules/KnownArgumentNames'; -const expectSDLErrors = expectSDLErrorsFromRule.bind( - undefined, - KnownArgumentNamesOnDirectives, -); +function expectErrors(queryStr) { + return expectValidationErrors(KnownArgumentNames, queryStr); +} + +function expectValid(queryStr) { + expectErrors(queryStr).to.deep.equal([]); +} + +function expectSDLErrors(sdlStr, schema) { + return expectSDLValidationErrors( + schema, + KnownArgumentNamesOnDirectives, + sdlStr, + ); +} + +function expectValidSDL(sdlStr) { + expectSDLErrors(sdlStr).to.deep.equal([]); +} function unknownArg(argName, fieldName, typeName, suggestedArgs, line, column) { return { @@ -48,64 +59,47 @@ function unknownDirectiveArg( describe('Validate: Known argument names', () => { it('single arg is known', () => { - expectPassesRule( - KnownArgumentNames, - ` + expectValid(` fragment argOnRequiredArg on Dog { doesKnowCommand(dogCommand: SIT) } - `, - ); + `); }); it('multiple args are known', () => { - expectPassesRule( - KnownArgumentNames, - ` + expectValid(` fragment multipleArgs on ComplicatedArgs { multipleReqs(req1: 1, req2: 2) } - `, - ); + `); }); it('ignores args of unknown fields', () => { - expectPassesRule( - KnownArgumentNames, - ` + expectValid(` fragment argOnUnknownField on Dog { unknownField(unknownArg: SIT) } - `, - ); + `); }); it('multiple args in reverse order are known', () => { - expectPassesRule( - KnownArgumentNames, - ` + expectValid(` fragment multipleArgsReverseOrder on ComplicatedArgs { multipleReqs(req2: 2, req1: 1) } - `, - ); + `); }); it('no args on optional arg', () => { - expectPassesRule( - KnownArgumentNames, - ` + expectValid(` fragment noArgOnOptionalArg on Dog { isHousetrained } - `, - ); + `); }); it('args are known deeply', () => { - expectPassesRule( - KnownArgumentNames, - ` + expectValid(` { dog { doesKnowCommand(dogCommand: SIT) @@ -118,97 +112,66 @@ describe('Validate: Known argument names', () => { } } } - `, - ); + `); }); it('directive args are known', () => { - expectPassesRule( - KnownArgumentNames, - ` + expectValid(` { dog @skip(if: true) } - `, - ); + `); }); it('field args are invalid', () => { - expectFailsRule( - KnownArgumentNames, - ` + expectErrors(` { dog @skip(unless: true) } - `, - [unknownDirectiveArg('unless', 'skip', [], 3, 19)], - ); + `).to.deep.equal([unknownDirectiveArg('unless', 'skip', [], 3, 19)]); }); it('misspelled directive args are reported', () => { - expectFailsRule( - KnownArgumentNames, - ` + expectErrors(` { dog @skip(iff: true) } - `, - [unknownDirectiveArg('iff', 'skip', ['if'], 3, 19)], - ); + `).to.deep.equal([unknownDirectiveArg('iff', 'skip', ['if'], 3, 19)]); }); it('invalid arg name', () => { - expectFailsRule( - KnownArgumentNames, - ` + expectErrors(` fragment invalidArgName on Dog { doesKnowCommand(unknown: true) } - `, - [unknownArg('unknown', 'doesKnowCommand', 'Dog', [], 3, 25)], - ); + `).to.deep.equal([ + unknownArg('unknown', 'doesKnowCommand', 'Dog', [], 3, 25), + ]); }); it('misspelled arg name is reported', () => { - expectFailsRule( - KnownArgumentNames, - ` + expectErrors(` fragment invalidArgName on Dog { doesKnowCommand(dogcommand: true) } - `, - [ - unknownArg( - 'dogcommand', - 'doesKnowCommand', - 'Dog', - ['dogCommand'], - 3, - 25, - ), - ], - ); + `).to.deep.equal([ + unknownArg('dogcommand', 'doesKnowCommand', 'Dog', ['dogCommand'], 3, 25), + ]); }); it('unknown args amongst known args', () => { - expectFailsRule( - KnownArgumentNames, - ` + expectErrors(` fragment oneGoodArgOneInvalidArg on Dog { doesKnowCommand(whoknows: 1, dogCommand: SIT, unknown: true) } - `, - [ - unknownArg('whoknows', 'doesKnowCommand', 'Dog', [], 3, 25), - unknownArg('unknown', 'doesKnowCommand', 'Dog', [], 3, 55), - ], - ); + `).to.deep.equal([ + unknownArg('whoknows', 'doesKnowCommand', 'Dog', [], 3, 25), + unknownArg('unknown', 'doesKnowCommand', 'Dog', [], 3, 55), + ]); }); it('unknown args deeply', () => { - expectFailsRule( - KnownArgumentNames, - ` + expectErrors(` { dog { doesKnowCommand(unknown: true) @@ -221,23 +184,21 @@ describe('Validate: Known argument names', () => { } } } - `, - [ - unknownArg('unknown', 'doesKnowCommand', 'Dog', [], 4, 27), - unknownArg('unknown', 'doesKnowCommand', 'Dog', [], 9, 31), - ], - ); + `).to.deep.equal([ + unknownArg('unknown', 'doesKnowCommand', 'Dog', [], 4, 27), + unknownArg('unknown', 'doesKnowCommand', 'Dog', [], 9, 31), + ]); }); describe('within SDL', () => { it('known arg on directive defined inside SDL', () => { - expectSDLErrors(` + expectValidSDL(` type Query { foo: String @test(arg: "") } directive @test(arg: String) on FIELD_DEFINITION - `).to.deep.equal([]); + `); }); it('unknown arg on directive defined inside SDL', () => { diff --git a/src/validation/__tests__/KnownDirectives-test.js b/src/validation/__tests__/KnownDirectives-test.js index 292128d589..dd8b8acc70 100644 --- a/src/validation/__tests__/KnownDirectives-test.js +++ b/src/validation/__tests__/KnownDirectives-test.js @@ -9,11 +9,7 @@ import { describe, it } from 'mocha'; import { buildSchema } from '../../utilities'; -import { - expectPassesRule, - expectFailsRule, - expectSDLErrorsFromRule, -} from './harness'; +import { expectValidationErrors, expectSDLValidationErrors } from './harness'; import { KnownDirectives, @@ -21,10 +17,21 @@ import { misplacedDirectiveMessage, } from '../rules/KnownDirectives'; -const expectSDLErrors = expectSDLErrorsFromRule.bind( - undefined, - KnownDirectives, -); +function expectErrors(queryStr) { + return expectValidationErrors(KnownDirectives, queryStr); +} + +function expectValid(queryStr) { + expectErrors(queryStr).to.deep.equal([]); +} + +function expectSDLErrors(sdlStr, schema) { + return expectSDLValidationErrors(schema, KnownDirectives, sdlStr); +} + +function expectValidSDL(sdlStr, schema) { + expectSDLErrors(sdlStr, schema).to.deep.equal([]); +} function unknownDirective(directiveName, line, column) { return { @@ -56,9 +63,7 @@ const schemaWithSDLDirectives = buildSchema(` describe('Validate: Known directives', () => { it('with no directives', () => { - expectPassesRule( - KnownDirectives, - ` + expectValid(` query Foo { name ...Frag @@ -67,14 +72,11 @@ describe('Validate: Known directives', () => { fragment Frag on Dog { name } - `, - ); + `); }); it('with known directives', () => { - expectPassesRule( - KnownDirectives, - ` + expectValid(` { dog @include(if: true) { name @@ -83,28 +85,21 @@ describe('Validate: Known directives', () => { name } } - `, - ); + `); }); it('with unknown directive', () => { - expectFailsRule( - KnownDirectives, - ` + expectErrors(` { dog @unknown(directive: "value") { name } } - `, - [unknownDirective('unknown', 3, 13)], - ); + `).to.deep.equal([unknownDirective('unknown', 3, 13)]); }); it('with many unknown directives', () => { - expectFailsRule( - KnownDirectives, - ` + expectErrors(` { dog @unknown(directive: "value") { name @@ -116,19 +111,15 @@ describe('Validate: Known directives', () => { } } } - `, - [ - unknownDirective('unknown', 3, 13), - unknownDirective('unknown', 6, 15), - unknownDirective('unknown', 8, 16), - ], - ); + `).to.deep.equal([ + unknownDirective('unknown', 3, 13), + unknownDirective('unknown', 6, 15), + unknownDirective('unknown', 8, 16), + ]); }); it('with well placed directives', () => { - expectPassesRule( - KnownDirectives, - ` + expectValid(` query Foo($var: Boolean) @onQuery { name @include(if: $var) ...Frag @include(if: true) @@ -139,25 +130,19 @@ describe('Validate: Known directives', () => { mutation Bar @onMutation { someField } - `, - ); + `); }); it('with well placed variable definition directive', () => { - expectPassesRule( - KnownDirectives, - ` + expectValid(` query Foo($var: Boolean @onVariableDefinition) { name } - `, - ); + `); }); it('with misplaced directives', () => { - expectFailsRule( - KnownDirectives, - ` + expectErrors(` query Foo($var: Boolean) @include(if: true) { name @onQuery @include(if: $var) ...Frag @onQuery @@ -166,54 +151,50 @@ describe('Validate: Known directives', () => { mutation Bar @onQuery { someField } - `, - [ - misplacedDirective('include', 'QUERY', 2, 32), - misplacedDirective('onQuery', 'FIELD', 3, 14), - misplacedDirective('onQuery', 'FRAGMENT_SPREAD', 4, 17), - misplacedDirective('onQuery', 'MUTATION', 7, 20), - ], - ); + `).to.deep.equal([ + misplacedDirective('include', 'QUERY', 2, 32), + misplacedDirective('onQuery', 'FIELD', 3, 14), + misplacedDirective('onQuery', 'FRAGMENT_SPREAD', 4, 17), + misplacedDirective('onQuery', 'MUTATION', 7, 20), + ]); }); it('with misplaced variable definition directive', () => { - expectFailsRule( - KnownDirectives, - ` + expectErrors(` query Foo($var: Boolean @onField) { name } - `, - [misplacedDirective('onField', 'VARIABLE_DEFINITION', 2, 31)], - ); + `).to.deep.equal([ + misplacedDirective('onField', 'VARIABLE_DEFINITION', 2, 31), + ]); }); describe('within SDL', () => { it('with directive defined inside SDL', () => { - expectSDLErrors(` + expectValidSDL(` type Query { foo: String @test } directive @test on FIELD_DEFINITION - `).to.deep.equal([]); + `); }); it('with standard directive', () => { - expectSDLErrors(` + expectValidSDL(` type Query { foo: String @deprecated } - `).to.deep.equal([]); + `); }); it('with overridden standard directive', () => { - expectSDLErrors(` + expectValidSDL(` schema @deprecated { query: Query } directive @deprecated on SCHEMA - `).to.deep.equal([]); + `); }); it('with directive defined in schema extension', () => { @@ -222,14 +203,14 @@ describe('Validate: Known directives', () => { foo: String } `); - expectSDLErrors( + expectValidSDL( ` directive @test on OBJECT extend type Query @test `, schema, - ).to.deep.equal([]); + ); }); it('with directive used in schema extension', () => { @@ -240,12 +221,12 @@ describe('Validate: Known directives', () => { foo: String } `); - expectSDLErrors( + expectValidSDL( ` extend type Query @test `, schema, - ).to.deep.equal([]); + ); }); it('with unknown directive in schema extension', () => { @@ -263,7 +244,7 @@ describe('Validate: Known directives', () => { }); it('with well placed directives', () => { - expectSDLErrors( + expectValidSDL( ` type MyObj implements MyInterface @onObject { myField(myArg: Int @onArgumentDefinition): String @onFieldDefinition @@ -304,7 +285,7 @@ describe('Validate: Known directives', () => { extend schema @onSchema `, schemaWithSDLDirectives, - ).to.deep.equal([]); + ); }); it('with misplaced directives', () => { diff --git a/src/validation/__tests__/KnownFragmentNames-test.js b/src/validation/__tests__/KnownFragmentNames-test.js index 67d11cecad..18ec7ba2a7 100644 --- a/src/validation/__tests__/KnownFragmentNames-test.js +++ b/src/validation/__tests__/KnownFragmentNames-test.js @@ -8,13 +8,21 @@ */ import { describe, it } from 'mocha'; -import { expectPassesRule, expectFailsRule } from './harness'; +import { expectValidationErrors } from './harness'; import { KnownFragmentNames, unknownFragmentMessage, } from '../rules/KnownFragmentNames'; -function undefFrag(fragName, line, column) { +function expectErrors(queryStr) { + return expectValidationErrors(KnownFragmentNames, queryStr); +} + +function expectValid(queryStr) { + expectErrors(queryStr).to.deep.equal([]); +} + +function unknownFragment(fragName, line, column) { return { message: unknownFragmentMessage(fragName), locations: [{ line, column }], @@ -23,9 +31,7 @@ function undefFrag(fragName, line, column) { describe('Validate: Known fragment names', () => { it('known fragment names are valid', () => { - expectPassesRule( - KnownFragmentNames, - ` + expectValid(` { human(id: 4) { ...HumanFields1 @@ -47,14 +53,11 @@ describe('Validate: Known fragment names', () => { fragment HumanFields3 on Human { name } - `, - ); + `); }); it('unknown fragment names are invalid', () => { - expectFailsRule( - KnownFragmentNames, - ` + expectErrors(` { human(id: 4) { ...UnknownFragment1 @@ -67,12 +70,10 @@ describe('Validate: Known fragment names', () => { name ...UnknownFragment3 } - `, - [ - undefFrag('UnknownFragment1', 4, 14), - undefFrag('UnknownFragment2', 6, 16), - undefFrag('UnknownFragment3', 12, 12), - ], - ); + `).to.deep.equal([ + unknownFragment('UnknownFragment1', 4, 14), + unknownFragment('UnknownFragment2', 6, 16), + unknownFragment('UnknownFragment3', 12, 12), + ]); }); }); diff --git a/src/validation/__tests__/KnownTypeNames-test.js b/src/validation/__tests__/KnownTypeNames-test.js index 3df4922b40..477b729b80 100644 --- a/src/validation/__tests__/KnownTypeNames-test.js +++ b/src/validation/__tests__/KnownTypeNames-test.js @@ -8,9 +8,17 @@ */ import { describe, it } from 'mocha'; -import { expectPassesRule, expectFailsRule } from './harness'; +import { expectValidationErrors } from './harness'; import { KnownTypeNames, unknownTypeMessage } from '../rules/KnownTypeNames'; +function expectErrors(queryStr) { + return expectValidationErrors(KnownTypeNames, queryStr); +} + +function expectValid(queryStr) { + expectErrors(queryStr).to.deep.equal([]); +} + function unknownType(typeName, suggestedTypes, line, column) { return { message: unknownTypeMessage(typeName, suggestedTypes), @@ -20,9 +28,7 @@ function unknownType(typeName, suggestedTypes, line, column) { describe('Validate: Known type names', () => { it('known type names are valid', () => { - expectPassesRule( - KnownTypeNames, - ` + expectValid(` query Foo($var: String, $required: [String!]!) { user(id: 4) { pets { ... on Pet { name }, ...PetFields, ... { name } } @@ -31,14 +37,11 @@ describe('Validate: Known type names', () => { fragment PetFields on Pet { name } - `, - ); + `); }); it('unknown type names are invalid', () => { - expectFailsRule( - KnownTypeNames, - ` + expectErrors(` query Foo($var: JumbledUpLetters) { user(id: 4) { name @@ -48,19 +51,15 @@ describe('Validate: Known type names', () => { fragment PetFields on Peettt { name } - `, - [ - unknownType('JumbledUpLetters', [], 2, 23), - unknownType('Badger', [], 5, 25), - unknownType('Peettt', ['Pet'], 8, 29), - ], - ); + `).to.deep.equal([ + unknownType('JumbledUpLetters', [], 2, 23), + unknownType('Badger', [], 5, 25), + unknownType('Peettt', ['Pet'], 8, 29), + ]); }); it('ignores type definitions', () => { - expectFailsRule( - KnownTypeNames, - ` + expectErrors(` type NotInTheSchema { field: FooBar } @@ -76,8 +75,6 @@ describe('Validate: Known type names', () => { id } } - `, - [unknownType('NotInTheSchema', [], 12, 23)], - ); + `).to.deep.equal([unknownType('NotInTheSchema', [], 12, 23)]); }); }); diff --git a/src/validation/__tests__/LoneAnonymousOperation-test.js b/src/validation/__tests__/LoneAnonymousOperation-test.js index bbe4ad2121..1a9bc3eb87 100644 --- a/src/validation/__tests__/LoneAnonymousOperation-test.js +++ b/src/validation/__tests__/LoneAnonymousOperation-test.js @@ -8,13 +8,21 @@ */ import { describe, it } from 'mocha'; -import { expectPassesRule, expectFailsRule } from './harness'; +import { expectValidationErrors } from './harness'; import { LoneAnonymousOperation, anonOperationNotAloneMessage, } from '../rules/LoneAnonymousOperation'; -function anonNotAlone(line, column) { +function expectErrors(queryStr) { + return expectValidationErrors(LoneAnonymousOperation, queryStr); +} + +function expectValid(queryStr) { + expectErrors(queryStr).to.deep.equal([]); +} + +function anonOperationNotAlone(line, column) { return { message: anonOperationNotAloneMessage(), locations: [{ line, column }], @@ -23,31 +31,23 @@ function anonNotAlone(line, column) { describe('Validate: Anonymous operation must be alone', () => { it('no operations', () => { - expectPassesRule( - LoneAnonymousOperation, - ` + expectValid(` fragment fragA on Type { field } - `, - ); + `); }); it('one anon operation', () => { - expectPassesRule( - LoneAnonymousOperation, - ` + expectValid(` { field } - `, - ); + `); }); it('multiple named operations', () => { - expectPassesRule( - LoneAnonymousOperation, - ` + expectValid(` query Foo { field } @@ -55,66 +55,53 @@ describe('Validate: Anonymous operation must be alone', () => { query Bar { field } - `, - ); + `); }); it('anon operation with fragment', () => { - expectPassesRule( - LoneAnonymousOperation, - ` + expectValid(` { ...Foo } fragment Foo on Type { field } - `, - ); + `); }); it('multiple anon operations', () => { - expectFailsRule( - LoneAnonymousOperation, - ` + expectErrors(` { fieldA } { fieldB } - `, - [anonNotAlone(2, 7), anonNotAlone(5, 7)], - ); + `).to.deep.equal([ + anonOperationNotAlone(2, 7), + anonOperationNotAlone(5, 7), + ]); }); it('anon operation with a mutation', () => { - expectFailsRule( - LoneAnonymousOperation, - ` + expectErrors(` { fieldA } mutation Foo { fieldB } - `, - [anonNotAlone(2, 7)], - ); + `).to.deep.equal([anonOperationNotAlone(2, 7)]); }); it('anon operation with a subscription', () => { - expectFailsRule( - LoneAnonymousOperation, - ` + expectErrors(` { fieldA } subscription Foo { fieldB } - `, - [anonNotAlone(2, 7)], - ); + `).to.deep.equal([anonOperationNotAlone(2, 7)]); }); }); diff --git a/src/validation/__tests__/LoneSchemaDefinition-test.js b/src/validation/__tests__/LoneSchemaDefinition-test.js index c9e29ba6f7..ff87f6040f 100644 --- a/src/validation/__tests__/LoneSchemaDefinition-test.js +++ b/src/validation/__tests__/LoneSchemaDefinition-test.js @@ -8,7 +8,7 @@ */ import { describe, it } from 'mocha'; -import { expectSDLErrorsFromRule } from './harness'; +import { expectSDLValidationErrors } from './harness'; import { LoneSchemaDefinition, schemaDefinitionNotAloneMessage, @@ -16,10 +16,13 @@ import { } from '../rules/LoneSchemaDefinition'; import { buildSchema } from '../../utilities'; -const expectSDLErrors = expectSDLErrorsFromRule.bind( - undefined, - LoneSchemaDefinition, -); +function expectSDLErrors(sdlStr, schema) { + return expectSDLValidationErrors(schema, LoneSchemaDefinition, sdlStr); +} + +function expectValidSDL(sdlStr, schema) { + expectSDLErrors(sdlStr, schema).to.deep.equal([]); +} function schemaDefinitionNotAlone(line, column) { return { @@ -37,15 +40,15 @@ function canNotDefineSchemaWithinExtension(line, column) { describe('Validate: Schema definition should be alone', () => { it('no schema', () => { - expectSDLErrors(` + expectValidSDL(` type Query { foo: String } - `).to.deep.equal([]); + `); }); it('one schema definition', () => { - expectSDLErrors(` + expectValidSDL(` schema { query: Foo } @@ -53,7 +56,7 @@ describe('Validate: Schema definition should be alone', () => { type Foo { foo: String } - `).to.deep.equal([]); + `); }); it('multiple schema definitions', () => { @@ -149,13 +152,13 @@ describe('Validate: Schema definition should be alone', () => { } `); - expectSDLErrors( + expectValidSDL( ` extend schema { mutation: Foo } `, schema, - ).to.deep.equal([]); + ); }); }); diff --git a/src/validation/__tests__/NoFragmentCycles-test.js b/src/validation/__tests__/NoFragmentCycles-test.js index 6cbef30d73..9bce73fb31 100644 --- a/src/validation/__tests__/NoFragmentCycles-test.js +++ b/src/validation/__tests__/NoFragmentCycles-test.js @@ -8,45 +8,42 @@ */ import { describe, it } from 'mocha'; -import { expectPassesRule, expectFailsRule } from './harness'; +import { expectValidationErrors } from './harness'; import { NoFragmentCycles, cycleErrorMessage } from '../rules/NoFragmentCycles'; +function expectErrors(queryStr) { + return expectValidationErrors(NoFragmentCycles, queryStr); +} + +function expectValid(queryStr) { + expectErrors(queryStr).to.deep.equal([]); +} + describe('Validate: No circular fragment spreads', () => { it('single reference is valid', () => { - expectPassesRule( - NoFragmentCycles, - ` + expectValid(` fragment fragA on Dog { ...fragB } fragment fragB on Dog { name } - `, - ); + `); }); it('spreading twice is not circular', () => { - expectPassesRule( - NoFragmentCycles, - ` + expectValid(` fragment fragA on Dog { ...fragB, ...fragB } fragment fragB on Dog { name } - `, - ); + `); }); it('spreading twice indirectly is not circular', () => { - expectPassesRule( - NoFragmentCycles, - ` + expectValid(` fragment fragA on Dog { ...fragB, ...fragC } fragment fragB on Dog { ...fragC } fragment fragC on Dog { name } - `, - ); + `); }); it('double spread within abstract types', () => { - expectPassesRule( - NoFragmentCycles, - ` + expectValid(` fragment nameFragment on Pet { ... on Dog { name } ... on Cat { name } @@ -56,106 +53,80 @@ describe('Validate: No circular fragment spreads', () => { ... on Dog { ...nameFragment } ... on Cat { ...nameFragment } } - `, - ); + `); }); it('does not false positive on unknown fragment', () => { - expectPassesRule( - NoFragmentCycles, - ` + expectValid(` fragment nameFragment on Pet { ...UnknownFragment } - `, - ); + `); }); it('spreading recursively within field fails', () => { - expectFailsRule( - NoFragmentCycles, - ` + expectErrors(` fragment fragA on Human { relatives { ...fragA } }, - `, - [ - { - message: cycleErrorMessage('fragA', []), - locations: [{ line: 2, column: 45 }], - }, - ], - ); + `).to.deep.equal([ + { + message: cycleErrorMessage('fragA', []), + locations: [{ line: 2, column: 45 }], + }, + ]); }); it('no spreading itself directly', () => { - expectFailsRule( - NoFragmentCycles, - ` + expectErrors(` fragment fragA on Dog { ...fragA } - `, - [ - { - message: cycleErrorMessage('fragA', []), - locations: [{ line: 2, column: 31 }], - }, - ], - ); + `).to.deep.equal([ + { + message: cycleErrorMessage('fragA', []), + locations: [{ line: 2, column: 31 }], + }, + ]); }); it('no spreading itself directly within inline fragment', () => { - expectFailsRule( - NoFragmentCycles, - ` + expectErrors(` fragment fragA on Pet { ... on Dog { ...fragA } } - `, - [ - { - message: cycleErrorMessage('fragA', []), - locations: [{ line: 4, column: 11 }], - }, - ], - ); + `).to.deep.equal([ + { + message: cycleErrorMessage('fragA', []), + locations: [{ line: 4, column: 11 }], + }, + ]); }); it('no spreading itself indirectly', () => { - expectFailsRule( - NoFragmentCycles, - ` + expectErrors(` fragment fragA on Dog { ...fragB } fragment fragB on Dog { ...fragA } - `, - [ - { - message: cycleErrorMessage('fragA', ['fragB']), - locations: [{ line: 2, column: 31 }, { line: 3, column: 31 }], - }, - ], - ); + `).to.deep.equal([ + { + message: cycleErrorMessage('fragA', ['fragB']), + locations: [{ line: 2, column: 31 }, { line: 3, column: 31 }], + }, + ]); }); it('no spreading itself indirectly reports opposite order', () => { - expectFailsRule( - NoFragmentCycles, - ` + expectErrors(` fragment fragB on Dog { ...fragA } fragment fragA on Dog { ...fragB } - `, - [ - { - message: cycleErrorMessage('fragB', ['fragA']), - locations: [{ line: 2, column: 31 }, { line: 3, column: 31 }], - }, - ], - ); + `).to.deep.equal([ + { + message: cycleErrorMessage('fragB', ['fragA']), + locations: [{ line: 2, column: 31 }, { line: 3, column: 31 }], + }, + ]); }); it('no spreading itself indirectly within inline fragment', () => { - expectFailsRule( - NoFragmentCycles, - ` + expectErrors(` fragment fragA on Pet { ... on Dog { ...fragB @@ -166,20 +137,16 @@ describe('Validate: No circular fragment spreads', () => { ...fragA } } - `, - [ - { - message: cycleErrorMessage('fragA', ['fragB']), - locations: [{ line: 4, column: 11 }, { line: 9, column: 11 }], - }, - ], - ); + `).to.deep.equal([ + { + message: cycleErrorMessage('fragA', ['fragB']), + locations: [{ line: 4, column: 11 }, { line: 9, column: 11 }], + }, + ]); }); it('no spreading itself deeply', () => { - expectFailsRule( - NoFragmentCycles, - ` + expectErrors(` fragment fragA on Dog { ...fragB } fragment fragB on Dog { ...fragC } fragment fragC on Dog { ...fragO } @@ -188,110 +155,96 @@ describe('Validate: No circular fragment spreads', () => { fragment fragZ on Dog { ...fragO } fragment fragO on Dog { ...fragP } fragment fragP on Dog { ...fragA, ...fragX } - `, - [ - { - message: cycleErrorMessage('fragA', [ - 'fragB', - 'fragC', - 'fragO', - 'fragP', - ]), - locations: [ - { line: 2, column: 31 }, - { line: 3, column: 31 }, - { line: 4, column: 31 }, - { line: 8, column: 31 }, - { line: 9, column: 31 }, - ], - }, - { - message: cycleErrorMessage('fragO', [ - 'fragP', - 'fragX', - 'fragY', - 'fragZ', - ]), - locations: [ - { line: 8, column: 31 }, - { line: 9, column: 41 }, - { line: 5, column: 31 }, - { line: 6, column: 31 }, - { line: 7, column: 31 }, - ], - }, - ], - ); + `).to.deep.equal([ + { + message: cycleErrorMessage('fragA', [ + 'fragB', + 'fragC', + 'fragO', + 'fragP', + ]), + locations: [ + { line: 2, column: 31 }, + { line: 3, column: 31 }, + { line: 4, column: 31 }, + { line: 8, column: 31 }, + { line: 9, column: 31 }, + ], + }, + { + message: cycleErrorMessage('fragO', [ + 'fragP', + 'fragX', + 'fragY', + 'fragZ', + ]), + locations: [ + { line: 8, column: 31 }, + { line: 9, column: 41 }, + { line: 5, column: 31 }, + { line: 6, column: 31 }, + { line: 7, column: 31 }, + ], + }, + ]); }); it('no spreading itself deeply two paths', () => { - expectFailsRule( - NoFragmentCycles, - ` + expectErrors(` fragment fragA on Dog { ...fragB, ...fragC } fragment fragB on Dog { ...fragA } fragment fragC on Dog { ...fragA } - `, - [ - { - message: cycleErrorMessage('fragA', ['fragB']), - locations: [{ line: 2, column: 31 }, { line: 3, column: 31 }], - }, - { - message: cycleErrorMessage('fragA', ['fragC']), - locations: [{ line: 2, column: 41 }, { line: 4, column: 31 }], - }, - ], - ); + `).to.deep.equal([ + { + message: cycleErrorMessage('fragA', ['fragB']), + locations: [{ line: 2, column: 31 }, { line: 3, column: 31 }], + }, + { + message: cycleErrorMessage('fragA', ['fragC']), + locations: [{ line: 2, column: 41 }, { line: 4, column: 31 }], + }, + ]); }); it('no spreading itself deeply two paths -- alt traverse order', () => { - expectFailsRule( - NoFragmentCycles, - ` + expectErrors(` fragment fragA on Dog { ...fragC } fragment fragB on Dog { ...fragC } fragment fragC on Dog { ...fragA, ...fragB } - `, - [ - { - message: cycleErrorMessage('fragA', ['fragC']), - locations: [{ line: 2, column: 31 }, { line: 4, column: 31 }], - }, - { - message: cycleErrorMessage('fragC', ['fragB']), - locations: [{ line: 4, column: 41 }, { line: 3, column: 31 }], - }, - ], - ); + `).to.deep.equal([ + { + message: cycleErrorMessage('fragA', ['fragC']), + locations: [{ line: 2, column: 31 }, { line: 4, column: 31 }], + }, + { + message: cycleErrorMessage('fragC', ['fragB']), + locations: [{ line: 4, column: 41 }, { line: 3, column: 31 }], + }, + ]); }); it('no spreading itself deeply and immediately', () => { - expectFailsRule( - NoFragmentCycles, - ` + expectErrors(` fragment fragA on Dog { ...fragB } fragment fragB on Dog { ...fragB, ...fragC } fragment fragC on Dog { ...fragA, ...fragB } - `, - [ - { - message: cycleErrorMessage('fragB', []), - locations: [{ line: 3, column: 31 }], - }, - { - message: cycleErrorMessage('fragA', ['fragB', 'fragC']), - locations: [ - { line: 2, column: 31 }, - { line: 3, column: 41 }, - { line: 4, column: 31 }, - ], - }, - { - message: cycleErrorMessage('fragB', ['fragC']), - locations: [{ line: 3, column: 41 }, { line: 4, column: 41 }], - }, - ], - ); + `).to.deep.equal([ + { + message: cycleErrorMessage('fragB', []), + locations: [{ line: 3, column: 31 }], + }, + { + message: cycleErrorMessage('fragA', ['fragB', 'fragC']), + locations: [ + { line: 2, column: 31 }, + { line: 3, column: 41 }, + { line: 4, column: 31 }, + ], + }, + { + message: cycleErrorMessage('fragB', ['fragC']), + locations: [{ line: 3, column: 41 }, { line: 4, column: 41 }], + }, + ]); }); }); diff --git a/src/validation/__tests__/NoUndefinedVariables-test.js b/src/validation/__tests__/NoUndefinedVariables-test.js index 486bd230a6..bae9816501 100644 --- a/src/validation/__tests__/NoUndefinedVariables-test.js +++ b/src/validation/__tests__/NoUndefinedVariables-test.js @@ -8,12 +8,20 @@ */ import { describe, it } from 'mocha'; -import { expectPassesRule, expectFailsRule } from './harness'; +import { expectValidationErrors } from './harness'; import { NoUndefinedVariables, undefinedVarMessage, } from '../rules/NoUndefinedVariables'; +function expectErrors(queryStr) { + return expectValidationErrors(NoUndefinedVariables, queryStr); +} + +function expectValid(queryStr) { + expectErrors(queryStr).to.deep.equal([]); +} + function undefVar(varName, l1, c1, opName, l2, c2) { return { message: undefinedVarMessage(varName, opName), @@ -23,20 +31,15 @@ function undefVar(varName, l1, c1, opName, l2, c2) { describe('Validate: No undefined variables', () => { it('all variables defined', () => { - expectPassesRule( - NoUndefinedVariables, - ` + expectValid(` query Foo($a: String, $b: String, $c: String) { field(a: $a, b: $b, c: $c) } - `, - ); + `); }); it('all variables deeply defined', () => { - expectPassesRule( - NoUndefinedVariables, - ` + expectValid(` query Foo($a: String, $b: String, $c: String) { field(a: $a) { field(b: $b) { @@ -44,14 +47,11 @@ describe('Validate: No undefined variables', () => { } } } - `, - ); + `); }); it('all variables deeply in inline fragments defined', () => { - expectPassesRule( - NoUndefinedVariables, - ` + expectValid(` query Foo($a: String, $b: String, $c: String) { ... on Type { field(a: $a) { @@ -63,14 +63,11 @@ describe('Validate: No undefined variables', () => { } } } - `, - ); + `); }); it('all variables in fragments deeply defined', () => { - expectPassesRule( - NoUndefinedVariables, - ` + expectValid(` query Foo($a: String, $b: String, $c: String) { ...FragA } @@ -87,14 +84,11 @@ describe('Validate: No undefined variables', () => { fragment FragC on Type { field(c: $c) } - `, - ); + `); }); it('variable within single fragment defined in multiple operations', () => { - expectPassesRule( - NoUndefinedVariables, - ` + expectValid(` query Foo($a: String) { ...FragA } @@ -104,14 +98,11 @@ describe('Validate: No undefined variables', () => { fragment FragA on Type { field(a: $a) } - `, - ); + `); }); it('variable within fragments defined in operations', () => { - expectPassesRule( - NoUndefinedVariables, - ` + expectValid(` query Foo($a: String) { ...FragA } @@ -124,14 +115,11 @@ describe('Validate: No undefined variables', () => { fragment FragB on Type { field(b: $b) } - `, - ); + `); }); it('variable within recursive fragment defined', () => { - expectPassesRule( - NoUndefinedVariables, - ` + expectValid(` query Foo($a: String) { ...FragA } @@ -140,65 +128,49 @@ describe('Validate: No undefined variables', () => { ...FragA } } - `, - ); + `); }); it('variable not defined', () => { - expectFailsRule( - NoUndefinedVariables, - ` + expectErrors(` query Foo($a: String, $b: String, $c: String) { field(a: $a, b: $b, c: $c, d: $d) } - `, - [undefVar('d', 3, 39, 'Foo', 2, 7)], - ); + `).to.deep.equal([undefVar('d', 3, 39, 'Foo', 2, 7)]); }); it('variable not defined by un-named query', () => { - expectFailsRule( - NoUndefinedVariables, - ` + expectErrors(` { field(a: $a) } - `, - [undefVar('a', 3, 18, '', 2, 7)], - ); + `).to.deep.equal([undefVar('a', 3, 18, '', 2, 7)]); }); it('multiple variables not defined', () => { - expectFailsRule( - NoUndefinedVariables, - ` + expectErrors(` query Foo($b: String) { field(a: $a, b: $b, c: $c) } - `, - [undefVar('a', 3, 18, 'Foo', 2, 7), undefVar('c', 3, 32, 'Foo', 2, 7)], - ); + `).to.deep.equal([ + undefVar('a', 3, 18, 'Foo', 2, 7), + undefVar('c', 3, 32, 'Foo', 2, 7), + ]); }); it('variable in fragment not defined by un-named query', () => { - expectFailsRule( - NoUndefinedVariables, - ` + expectErrors(` { ...FragA } fragment FragA on Type { field(a: $a) } - `, - [undefVar('a', 6, 18, '', 2, 7)], - ); + `).to.deep.equal([undefVar('a', 6, 18, '', 2, 7)]); }); it('variable in fragment not defined by operation', () => { - expectFailsRule( - NoUndefinedVariables, - ` + expectErrors(` query Foo($a: String, $b: String) { ...FragA } @@ -215,15 +187,11 @@ describe('Validate: No undefined variables', () => { fragment FragC on Type { field(c: $c) } - `, - [undefVar('c', 16, 18, 'Foo', 2, 7)], - ); + `).to.deep.equal([undefVar('c', 16, 18, 'Foo', 2, 7)]); }); it('multiple variables in fragments not defined', () => { - expectFailsRule( - NoUndefinedVariables, - ` + expectErrors(` query Foo($b: String) { ...FragA } @@ -240,15 +208,14 @@ describe('Validate: No undefined variables', () => { fragment FragC on Type { field(c: $c) } - `, - [undefVar('a', 6, 18, 'Foo', 2, 7), undefVar('c', 16, 18, 'Foo', 2, 7)], - ); + `).to.deep.equal([ + undefVar('a', 6, 18, 'Foo', 2, 7), + undefVar('c', 16, 18, 'Foo', 2, 7), + ]); }); it('single variable in fragment not defined by multiple operations', () => { - expectFailsRule( - NoUndefinedVariables, - ` + expectErrors(` query Foo($a: String) { ...FragAB } @@ -258,15 +225,14 @@ describe('Validate: No undefined variables', () => { fragment FragAB on Type { field(a: $a, b: $b) } - `, - [undefVar('b', 9, 25, 'Foo', 2, 7), undefVar('b', 9, 25, 'Bar', 5, 7)], - ); + `).to.deep.equal([ + undefVar('b', 9, 25, 'Foo', 2, 7), + undefVar('b', 9, 25, 'Bar', 5, 7), + ]); }); it('variables in fragment not defined by multiple operations', () => { - expectFailsRule( - NoUndefinedVariables, - ` + expectErrors(` query Foo($b: String) { ...FragAB } @@ -276,15 +242,14 @@ describe('Validate: No undefined variables', () => { fragment FragAB on Type { field(a: $a, b: $b) } - `, - [undefVar('a', 9, 18, 'Foo', 2, 7), undefVar('b', 9, 25, 'Bar', 5, 7)], - ); + `).to.deep.equal([ + undefVar('a', 9, 18, 'Foo', 2, 7), + undefVar('b', 9, 25, 'Bar', 5, 7), + ]); }); it('variable in fragment used by other operation', () => { - expectFailsRule( - NoUndefinedVariables, - ` + expectErrors(` query Foo($b: String) { ...FragA } @@ -297,15 +262,14 @@ describe('Validate: No undefined variables', () => { fragment FragB on Type { field(b: $b) } - `, - [undefVar('a', 9, 18, 'Foo', 2, 7), undefVar('b', 12, 18, 'Bar', 5, 7)], - ); + `).to.deep.equal([ + undefVar('a', 9, 18, 'Foo', 2, 7), + undefVar('b', 12, 18, 'Bar', 5, 7), + ]); }); it('multiple undefined variables produce multiple errors', () => { - expectFailsRule( - NoUndefinedVariables, - ` + expectErrors(` query Foo($b: String) { ...FragAB } @@ -320,15 +284,13 @@ describe('Validate: No undefined variables', () => { fragment FragC on Type { field2(c: $c) } - `, - [ - undefVar('a', 9, 19, 'Foo', 2, 7), - undefVar('a', 11, 19, 'Foo', 2, 7), - undefVar('c', 14, 19, 'Foo', 2, 7), - undefVar('b', 9, 26, 'Bar', 5, 7), - undefVar('b', 11, 26, 'Bar', 5, 7), - undefVar('c', 14, 19, 'Bar', 5, 7), - ], - ); + `).to.deep.equal([ + undefVar('a', 9, 19, 'Foo', 2, 7), + undefVar('a', 11, 19, 'Foo', 2, 7), + undefVar('c', 14, 19, 'Foo', 2, 7), + undefVar('b', 9, 26, 'Bar', 5, 7), + undefVar('b', 11, 26, 'Bar', 5, 7), + undefVar('c', 14, 19, 'Bar', 5, 7), + ]); }); }); diff --git a/src/validation/__tests__/NoUnusedFragments-test.js b/src/validation/__tests__/NoUnusedFragments-test.js index 0e32cb3542..44b1529a6d 100644 --- a/src/validation/__tests__/NoUnusedFragments-test.js +++ b/src/validation/__tests__/NoUnusedFragments-test.js @@ -8,12 +8,20 @@ */ import { describe, it } from 'mocha'; -import { expectPassesRule, expectFailsRule } from './harness'; +import { expectValidationErrors } from './harness'; import { NoUnusedFragments, unusedFragMessage, } from '../rules/NoUnusedFragments'; +function expectErrors(queryStr) { + return expectValidationErrors(NoUnusedFragments, queryStr); +} + +function expectValid(queryStr) { + expectErrors(queryStr).to.deep.equal([]); +} + function unusedFrag(fragName, line, column) { return { message: unusedFragMessage(fragName), @@ -23,9 +31,7 @@ function unusedFrag(fragName, line, column) { describe('Validate: No unused fragments', () => { it('all fragment names are used', () => { - expectPassesRule( - NoUnusedFragments, - ` + expectValid(` { human(id: 4) { ...HumanFields1 @@ -44,14 +50,11 @@ describe('Validate: No unused fragments', () => { fragment HumanFields3 on Human { name } - `, - ); + `); }); it('all fragment names are used by multiple operations', () => { - expectPassesRule( - NoUnusedFragments, - ` + expectValid(` query Foo { human(id: 4) { ...HumanFields1 @@ -72,14 +75,11 @@ describe('Validate: No unused fragments', () => { fragment HumanFields3 on Human { name } - `, - ); + `); }); it('contains unknown fragments', () => { - expectFailsRule( - NoUnusedFragments, - ` + expectErrors(` query Foo { human(id: 4) { ...HumanFields1 @@ -106,15 +106,14 @@ describe('Validate: No unused fragments', () => { fragment Unused2 on Human { name } - `, - [unusedFrag('Unused1', 22, 7), unusedFrag('Unused2', 25, 7)], - ); + `).to.deep.equal([ + unusedFrag('Unused1', 22, 7), + unusedFrag('Unused2', 25, 7), + ]); }); it('contains unknown fragments with ref cycle', () => { - expectFailsRule( - NoUnusedFragments, - ` + expectErrors(` query Foo { human(id: 4) { ...HumanFields1 @@ -143,15 +142,14 @@ describe('Validate: No unused fragments', () => { name ...Unused1 } - `, - [unusedFrag('Unused1', 22, 7), unusedFrag('Unused2', 26, 7)], - ); + `).to.deep.equal([ + unusedFrag('Unused1', 22, 7), + unusedFrag('Unused2', 26, 7), + ]); }); it('contains unknown and undef fragments', () => { - expectFailsRule( - NoUnusedFragments, - ` + expectErrors(` query Foo { human(id: 4) { ...bar @@ -160,8 +158,6 @@ describe('Validate: No unused fragments', () => { fragment foo on Human { name } - `, - [unusedFrag('foo', 7, 7)], - ); + `).to.deep.equal([unusedFrag('foo', 7, 7)]); }); }); diff --git a/src/validation/__tests__/NoUnusedVariables-test.js b/src/validation/__tests__/NoUnusedVariables-test.js index 40bcefec4e..1fe23541ba 100644 --- a/src/validation/__tests__/NoUnusedVariables-test.js +++ b/src/validation/__tests__/NoUnusedVariables-test.js @@ -8,12 +8,20 @@ */ import { describe, it } from 'mocha'; -import { expectPassesRule, expectFailsRule } from './harness'; +import { expectValidationErrors } from './harness'; import { NoUnusedVariables, unusedVariableMessage, } from '../rules/NoUnusedVariables'; +function expectErrors(queryStr) { + return expectValidationErrors(NoUnusedVariables, queryStr); +} + +function expectValid(queryStr) { + expectErrors(queryStr).to.deep.equal([]); +} + function unusedVar(varName, opName, line, column) { return { message: unusedVariableMessage(varName, opName), @@ -23,20 +31,15 @@ function unusedVar(varName, opName, line, column) { describe('Validate: No unused variables', () => { it('uses all variables', () => { - expectPassesRule( - NoUnusedVariables, - ` + expectValid(` query ($a: String, $b: String, $c: String) { field(a: $a, b: $b, c: $c) } - `, - ); + `); }); it('uses all variables deeply', () => { - expectPassesRule( - NoUnusedVariables, - ` + expectValid(` query Foo($a: String, $b: String, $c: String) { field(a: $a) { field(b: $b) { @@ -44,14 +47,11 @@ describe('Validate: No unused variables', () => { } } } - `, - ); + `); }); it('uses all variables deeply in inline fragments', () => { - expectPassesRule( - NoUnusedVariables, - ` + expectValid(` query Foo($a: String, $b: String, $c: String) { ... on Type { field(a: $a) { @@ -63,14 +63,11 @@ describe('Validate: No unused variables', () => { } } } - `, - ); + `); }); it('uses all variables in fragments', () => { - expectPassesRule( - NoUnusedVariables, - ` + expectValid(` query Foo($a: String, $b: String, $c: String) { ...FragA } @@ -87,14 +84,11 @@ describe('Validate: No unused variables', () => { fragment FragC on Type { field(c: $c) } - `, - ); + `); }); it('variable used by fragment in multiple operations', () => { - expectPassesRule( - NoUnusedVariables, - ` + expectValid(` query Foo($a: String) { ...FragA } @@ -107,14 +101,11 @@ describe('Validate: No unused variables', () => { fragment FragB on Type { field(b: $b) } - `, - ); + `); }); it('variable used by recursive fragment', () => { - expectPassesRule( - NoUnusedVariables, - ` + expectValid(` query Foo($a: String) { ...FragA } @@ -123,38 +114,30 @@ describe('Validate: No unused variables', () => { ...FragA } } - `, - ); + `); }); it('variable not used', () => { - expectFailsRule( - NoUnusedVariables, - ` + expectErrors(` query ($a: String, $b: String, $c: String) { field(a: $a, b: $b) } - `, - [unusedVar('c', null, 2, 38)], - ); + `).to.deep.equal([unusedVar('c', null, 2, 38)]); }); it('multiple variables not used', () => { - expectFailsRule( - NoUnusedVariables, - ` + expectErrors(` query Foo($a: String, $b: String, $c: String) { field(b: $b) } - `, - [unusedVar('a', 'Foo', 2, 17), unusedVar('c', 'Foo', 2, 41)], - ); + `).to.deep.equal([ + unusedVar('a', 'Foo', 2, 17), + unusedVar('c', 'Foo', 2, 41), + ]); }); it('variable not used in fragments', () => { - expectFailsRule( - NoUnusedVariables, - ` + expectErrors(` query Foo($a: String, $b: String, $c: String) { ...FragA } @@ -171,15 +154,11 @@ describe('Validate: No unused variables', () => { fragment FragC on Type { field } - `, - [unusedVar('c', 'Foo', 2, 41)], - ); + `).to.deep.equal([unusedVar('c', 'Foo', 2, 41)]); }); it('multiple variables not used in fragments', () => { - expectFailsRule( - NoUnusedVariables, - ` + expectErrors(` query Foo($a: String, $b: String, $c: String) { ...FragA } @@ -196,15 +175,14 @@ describe('Validate: No unused variables', () => { fragment FragC on Type { field } - `, - [unusedVar('a', 'Foo', 2, 17), unusedVar('c', 'Foo', 2, 41)], - ); + `).to.deep.equal([ + unusedVar('a', 'Foo', 2, 17), + unusedVar('c', 'Foo', 2, 41), + ]); }); it('variable not used by unreferenced fragment', () => { - expectFailsRule( - NoUnusedVariables, - ` + expectErrors(` query Foo($b: String) { ...FragA } @@ -214,15 +192,11 @@ describe('Validate: No unused variables', () => { fragment FragB on Type { field(b: $b) } - `, - [unusedVar('b', 'Foo', 2, 17)], - ); + `).to.deep.equal([unusedVar('b', 'Foo', 2, 17)]); }); it('variable not used by fragment used by other operation', () => { - expectFailsRule( - NoUnusedVariables, - ` + expectErrors(` query Foo($b: String) { ...FragA } @@ -235,8 +209,9 @@ describe('Validate: No unused variables', () => { fragment FragB on Type { field(b: $b) } - `, - [unusedVar('b', 'Foo', 2, 17), unusedVar('a', 'Bar', 5, 17)], - ); + `).to.deep.equal([ + unusedVar('b', 'Foo', 2, 17), + unusedVar('a', 'Bar', 5, 17), + ]); }); }); diff --git a/src/validation/__tests__/OverlappingFieldsCanBeMerged-test.js b/src/validation/__tests__/OverlappingFieldsCanBeMerged-test.js index 4492a049d6..193cc1de41 100644 --- a/src/validation/__tests__/OverlappingFieldsCanBeMerged-test.js +++ b/src/validation/__tests__/OverlappingFieldsCanBeMerged-test.js @@ -11,131 +11,123 @@ import { expect } from 'chai'; import { describe, it } from 'mocha'; import { buildSchema } from '../../'; import { - expectPassesRule, - expectFailsRule, - expectFailsRuleWithSchema, - expectPassesRuleWithSchema, + expectValidationErrors, + expectValidationErrorsWithSchema, } from './harness'; + import { OverlappingFieldsCanBeMerged, fieldsConflictMessage, } from '../rules/OverlappingFieldsCanBeMerged'; +function expectErrors(queryStr) { + return expectValidationErrors(OverlappingFieldsCanBeMerged, queryStr); +} + +function expectValid(queryStr) { + expectErrors(queryStr).to.deep.equal([]); +} + +function expectErrorsWithSchema(schema, queryStr) { + return expectValidationErrorsWithSchema( + schema, + OverlappingFieldsCanBeMerged, + queryStr, + ); +} + +function expectValidWithSchema(schema, queryStr) { + expectErrorsWithSchema(schema, queryStr).to.deep.equal([]); +} + describe('Validate: Overlapping fields can be merged', () => { it('unique fields', () => { - expectPassesRule( - OverlappingFieldsCanBeMerged, - ` + expectValid(` fragment uniqueFields on Dog { name nickname } - `, - ); + `); }); it('identical fields', () => { - expectPassesRule( - OverlappingFieldsCanBeMerged, - ` + expectValid(` fragment mergeIdenticalFields on Dog { name name } - `, - ); + `); }); it('identical fields with identical args', () => { - expectPassesRule( - OverlappingFieldsCanBeMerged, - ` + expectValid(` fragment mergeIdenticalFieldsWithIdenticalArgs on Dog { doesKnowCommand(dogCommand: SIT) doesKnowCommand(dogCommand: SIT) } - `, - ); + `); }); it('identical fields with identical directives', () => { - expectPassesRule( - OverlappingFieldsCanBeMerged, - ` + expectValid(` fragment mergeSameFieldsWithSameDirectives on Dog { name @include(if: true) name @include(if: true) } - `, - ); + `); }); it('different args with different aliases', () => { - expectPassesRule( - OverlappingFieldsCanBeMerged, - ` + expectValid(` fragment differentArgsWithDifferentAliases on Dog { knowsSit: doesKnowCommand(dogCommand: SIT) knowsDown: doesKnowCommand(dogCommand: DOWN) } - `, - ); + `); }); it('different directives with different aliases', () => { - expectPassesRule( - OverlappingFieldsCanBeMerged, - ` + expectValid(` fragment differentDirectivesWithDifferentAliases on Dog { nameIfTrue: name @include(if: true) nameIfFalse: name @include(if: false) } - `, - ); + `); }); it('different skip/include directives accepted', () => { // Note: Differing skip/include directives don't create an ambiguous return // value and are acceptable in conditions where differing runtime values // may have the same desired effect of including or skipping a field. - expectPassesRule( - OverlappingFieldsCanBeMerged, - ` + expectValid(` fragment differentDirectivesWithDifferentAliases on Dog { name @include(if: true) name @include(if: false) } - `, - ); + `); }); it('Same aliases with different field targets', () => { - expectFailsRule( - OverlappingFieldsCanBeMerged, - ` + expectErrors(` fragment sameAliasesWithDifferentFieldTargets on Dog { fido: name fido: nickname } - `, - [ - { - message: fieldsConflictMessage( - 'fido', - 'name and nickname are different fields', - ), - locations: [{ line: 3, column: 9 }, { line: 4, column: 9 }], - }, - ], - ); + `).to.deep.equal([ + { + message: fieldsConflictMessage( + 'fido', + 'name and nickname are different fields', + ), + locations: [{ line: 3, column: 9 }, { line: 4, column: 9 }], + }, + ]); }); it('Same aliases allowed on non-overlapping fields', () => { // This is valid since no object can be both a "Dog" and a "Cat", thus // these fields can never overlap. - expectPassesRule( - OverlappingFieldsCanBeMerged, - ` + expectValid(` fragment sameAliasesWithDifferentFieldTargets on Pet { ... on Dog { name @@ -144,100 +136,81 @@ describe('Validate: Overlapping fields can be merged', () => { name: nickname } } - `, - ); + `); }); it('Alias masking direct field access', () => { - expectFailsRule( - OverlappingFieldsCanBeMerged, - ` + expectErrors(` fragment aliasMaskingDirectFieldAccess on Dog { name: nickname name } - `, - [ - { - message: fieldsConflictMessage( - 'name', - 'nickname and name are different fields', - ), - locations: [{ line: 3, column: 9 }, { line: 4, column: 9 }], - }, - ], - ); + `).to.deep.equal([ + { + message: fieldsConflictMessage( + 'name', + 'nickname and name are different fields', + ), + locations: [{ line: 3, column: 9 }, { line: 4, column: 9 }], + }, + ]); }); it('different args, second adds an argument', () => { - expectFailsRule( - OverlappingFieldsCanBeMerged, - ` + expectErrors(` fragment conflictingArgs on Dog { doesKnowCommand doesKnowCommand(dogCommand: HEEL) } - `, - [ - { - message: fieldsConflictMessage( - 'doesKnowCommand', - 'they have differing arguments', - ), - locations: [{ line: 3, column: 9 }, { line: 4, column: 9 }], - }, - ], - ); + `).to.deep.equal([ + { + message: fieldsConflictMessage( + 'doesKnowCommand', + 'they have differing arguments', + ), + locations: [{ line: 3, column: 9 }, { line: 4, column: 9 }], + }, + ]); }); it('different args, second missing an argument', () => { - expectFailsRule( - OverlappingFieldsCanBeMerged, - ` + expectErrors(` fragment conflictingArgs on Dog { doesKnowCommand(dogCommand: SIT) doesKnowCommand } - `, - [ - { - message: fieldsConflictMessage( - 'doesKnowCommand', - 'they have differing arguments', - ), - locations: [{ line: 3, column: 9 }, { line: 4, column: 9 }], - }, - ], - ); + `).to.deep.equal([ + { + message: fieldsConflictMessage( + 'doesKnowCommand', + 'they have differing arguments', + ), + locations: [{ line: 3, column: 9 }, { line: 4, column: 9 }], + }, + ]); }); it('conflicting args', () => { - expectFailsRule( - OverlappingFieldsCanBeMerged, - ` + expectErrors(` fragment conflictingArgs on Dog { doesKnowCommand(dogCommand: SIT) doesKnowCommand(dogCommand: HEEL) } - `, - [ - { - message: fieldsConflictMessage( - 'doesKnowCommand', - 'they have differing arguments', - ), - locations: [{ line: 3, column: 9 }, { line: 4, column: 9 }], - }, - ], - ); + `).to.deep.equal([ + { + message: fieldsConflictMessage( + 'doesKnowCommand', + 'they have differing arguments', + ), + locations: [{ line: 3, column: 9 }, { line: 4, column: 9 }], + }, + ]); }); it('allows different args where no conflict is possible', () => { // This is valid since no object can be both a "Dog" and a "Cat", thus // these fields can never overlap. - expectPassesRule( - OverlappingFieldsCanBeMerged, - ` + expectValid(` fragment conflictingArgs on Pet { ... on Dog { name(surname: true) @@ -246,14 +219,11 @@ describe('Validate: Overlapping fields can be merged', () => { name } } - `, - ); + `); }); it('encounters conflict in fragments', () => { - expectFailsRule( - OverlappingFieldsCanBeMerged, - ` + expectErrors(` { ...A ...B @@ -264,20 +234,16 @@ describe('Validate: Overlapping fields can be merged', () => { fragment B on Type { x: b } - `, - [ - { - message: fieldsConflictMessage('x', 'a and b are different fields'), - locations: [{ line: 7, column: 9 }, { line: 10, column: 9 }], - }, - ], - ); + `).to.deep.equal([ + { + message: fieldsConflictMessage('x', 'a and b are different fields'), + locations: [{ line: 7, column: 9 }, { line: 10, column: 9 }], + }, + ]); }); it('reports each conflict once', () => { - expectFailsRule( - OverlappingFieldsCanBeMerged, - ` + expectErrors(` { f1 { ...A @@ -299,28 +265,24 @@ describe('Validate: Overlapping fields can be merged', () => { fragment B on Type { x: b } - `, - [ - { - message: fieldsConflictMessage('x', 'a and b are different fields'), - locations: [{ line: 18, column: 9 }, { line: 21, column: 9 }], - }, - { - message: fieldsConflictMessage('x', 'c and a are different fields'), - locations: [{ line: 14, column: 11 }, { line: 18, column: 9 }], - }, - { - message: fieldsConflictMessage('x', 'c and b are different fields'), - locations: [{ line: 14, column: 11 }, { line: 21, column: 9 }], - }, - ], - ); + `).to.deep.equal([ + { + message: fieldsConflictMessage('x', 'a and b are different fields'), + locations: [{ line: 18, column: 9 }, { line: 21, column: 9 }], + }, + { + message: fieldsConflictMessage('x', 'c and a are different fields'), + locations: [{ line: 14, column: 11 }, { line: 18, column: 9 }], + }, + { + message: fieldsConflictMessage('x', 'c and b are different fields'), + locations: [{ line: 14, column: 11 }, { line: 21, column: 9 }], + }, + ]); }); it('deep conflict', () => { - expectFailsRule( - OverlappingFieldsCanBeMerged, - ` + expectErrors(` { field { x: a @@ -329,27 +291,23 @@ describe('Validate: Overlapping fields can be merged', () => { x: b } } - `, - [ - { - message: fieldsConflictMessage('field', [ - ['x', 'a and b are different fields'], - ]), - locations: [ - { line: 3, column: 9 }, - { line: 4, column: 11 }, - { line: 6, column: 9 }, - { line: 7, column: 11 }, - ], - }, - ], - ); + `).to.deep.equal([ + { + message: fieldsConflictMessage('field', [ + ['x', 'a and b are different fields'], + ]), + locations: [ + { line: 3, column: 9 }, + { line: 4, column: 11 }, + { line: 6, column: 9 }, + { line: 7, column: 11 }, + ], + }, + ]); }); it('deep conflict with multiple issues', () => { - expectFailsRule( - OverlappingFieldsCanBeMerged, - ` + expectErrors(` { field { x: a @@ -360,30 +318,26 @@ describe('Validate: Overlapping fields can be merged', () => { y: d } } - `, - [ - { - message: fieldsConflictMessage('field', [ - ['x', 'a and b are different fields'], - ['y', 'c and d are different fields'], - ]), - locations: [ - { line: 3, column: 9 }, - { line: 4, column: 11 }, - { line: 5, column: 11 }, - { line: 7, column: 9 }, - { line: 8, column: 11 }, - { line: 9, column: 11 }, - ], - }, - ], - ); + `).to.deep.equal([ + { + message: fieldsConflictMessage('field', [ + ['x', 'a and b are different fields'], + ['y', 'c and d are different fields'], + ]), + locations: [ + { line: 3, column: 9 }, + { line: 4, column: 11 }, + { line: 5, column: 11 }, + { line: 7, column: 9 }, + { line: 8, column: 11 }, + { line: 9, column: 11 }, + ], + }, + ]); }); it('very deep conflict', () => { - expectFailsRule( - OverlappingFieldsCanBeMerged, - ` + expectErrors(` { field { deepField { @@ -396,29 +350,25 @@ describe('Validate: Overlapping fields can be merged', () => { } } } - `, - [ - { - message: fieldsConflictMessage('field', [ - ['deepField', [['x', 'a and b are different fields']]], - ]), - locations: [ - { line: 3, column: 9 }, - { line: 4, column: 11 }, - { line: 5, column: 13 }, - { line: 8, column: 9 }, - { line: 9, column: 11 }, - { line: 10, column: 13 }, - ], - }, - ], - ); + `).to.deep.equal([ + { + message: fieldsConflictMessage('field', [ + ['deepField', [['x', 'a and b are different fields']]], + ]), + locations: [ + { line: 3, column: 9 }, + { line: 4, column: 11 }, + { line: 5, column: 13 }, + { line: 8, column: 9 }, + { line: 9, column: 11 }, + { line: 10, column: 13 }, + ], + }, + ]); }); it('reports deep conflict to nearest common ancestor', () => { - expectFailsRule( - OverlappingFieldsCanBeMerged, - ` + expectErrors(` { field { deepField { @@ -434,27 +384,23 @@ describe('Validate: Overlapping fields can be merged', () => { } } } - `, - [ - { - message: fieldsConflictMessage('deepField', [ - ['x', 'a and b are different fields'], - ]), - locations: [ - { line: 4, column: 11 }, - { line: 5, column: 13 }, - { line: 7, column: 11 }, - { line: 8, column: 13 }, - ], - }, - ], - ); + `).to.deep.equal([ + { + message: fieldsConflictMessage('deepField', [ + ['x', 'a and b are different fields'], + ]), + locations: [ + { line: 4, column: 11 }, + { line: 5, column: 13 }, + { line: 7, column: 11 }, + { line: 8, column: 13 }, + ], + }, + ]); }); it('reports deep conflict to nearest common ancestor in fragments', () => { - expectFailsRule( - OverlappingFieldsCanBeMerged, - ` + expectErrors(` { field { ...F @@ -478,27 +424,23 @@ describe('Validate: Overlapping fields can be merged', () => { } } } - `, - [ - { - message: fieldsConflictMessage('deeperField', [ - ['x', 'a and b are different fields'], - ]), - locations: [ - { line: 12, column: 11 }, - { line: 13, column: 13 }, - { line: 15, column: 11 }, - { line: 16, column: 13 }, - ], - }, - ], - ); + `).to.deep.equal([ + { + message: fieldsConflictMessage('deeperField', [ + ['x', 'a and b are different fields'], + ]), + locations: [ + { line: 12, column: 11 }, + { line: 13, column: 13 }, + { line: 15, column: 11 }, + { line: 16, column: 13 }, + ], + }, + ]); }); it('reports deep conflict in nested fragments', () => { - expectFailsRule( - OverlappingFieldsCanBeMerged, - ` + expectErrors(` { field { ...F @@ -521,42 +463,37 @@ describe('Validate: Overlapping fields can be merged', () => { fragment J on T { x: b } - `, - [ - { - message: fieldsConflictMessage('field', [ - ['x', 'a and b are different fields'], - ['y', 'c and d are different fields'], - ]), - locations: [ - { line: 3, column: 9 }, - { line: 11, column: 9 }, - { line: 15, column: 9 }, - { line: 6, column: 9 }, - { line: 22, column: 9 }, - { line: 18, column: 9 }, - ], - }, - ], - ); + `).to.deep.equal([ + { + message: fieldsConflictMessage('field', [ + ['x', 'a and b are different fields'], + ['y', 'c and d are different fields'], + ]), + locations: [ + { line: 3, column: 9 }, + { line: 11, column: 9 }, + { line: 15, column: 9 }, + { line: 6, column: 9 }, + { line: 22, column: 9 }, + { line: 18, column: 9 }, + ], + }, + ]); }); it('ignores unknown fragments', () => { - expectPassesRule( - OverlappingFieldsCanBeMerged, - ` - { - field - ...Unknown - ...Known - } - - fragment Known on T { - field - ...OtherUnknown - } - `, - ); + expectValid(` + { + field + ...Unknown + ...Known + } + + fragment Known on T { + field + ...OtherUnknown + } + `); }); describe('return types must be unambiguous', () => { @@ -628,421 +565,398 @@ describe('Validate: Overlapping fields can be merged', () => { // type IntBox and the interface type NonNullStringBox1. While that // condition does not exist in the current schema, the schema could // expand in the future to allow this. Thus it is invalid. - expectFailsRuleWithSchema( + expectErrorsWithSchema( schema, - OverlappingFieldsCanBeMerged, ` - { - someBox { - ...on IntBox { - scalar - } - ...on NonNullStringBox1 { - scalar + { + someBox { + ...on IntBox { + scalar + } + ...on NonNullStringBox1 { + scalar + } } } - } - `, - [ - { - message: fieldsConflictMessage( - 'scalar', - 'they return conflicting types Int and String!', - ), - locations: [{ line: 5, column: 15 }, { line: 8, column: 15 }], - }, - ], - ); + `, + ).to.deep.equal([ + { + message: fieldsConflictMessage( + 'scalar', + 'they return conflicting types Int and String!', + ), + locations: [{ line: 5, column: 17 }, { line: 8, column: 17 }], + }, + ]); }); it('compatible return shapes on different return types', () => { // In this case `deepBox` returns `SomeBox` in the first usage, and // `StringBox` in the second usage. These return types are not the same! // however this is valid because the return *shapes* are compatible. - expectPassesRuleWithSchema( + expectValidWithSchema( schema, - OverlappingFieldsCanBeMerged, ` - { - someBox { - ... on SomeBox { - deepBox { - unrelatedField - } - } - ... on StringBox { - deepBox { - unrelatedField + { + someBox { + ... on SomeBox { + deepBox { + unrelatedField + } + } + ... on StringBox { + deepBox { + unrelatedField + } + } } } - } - } - `, + `, ); }); it('disallows differing return types despite no overlap', () => { - expectFailsRuleWithSchema( + expectErrorsWithSchema( schema, - OverlappingFieldsCanBeMerged, ` - { - someBox { - ... on IntBox { - scalar - } - ... on StringBox { - scalar + { + someBox { + ... on IntBox { + scalar + } + ... on StringBox { + scalar + } } } - } - `, - [ - { - message: fieldsConflictMessage( - 'scalar', - 'they return conflicting types Int and String', - ), - locations: [{ line: 5, column: 15 }, { line: 8, column: 15 }], - }, - ], - ); + `, + ).to.deep.equal([ + { + message: fieldsConflictMessage( + 'scalar', + 'they return conflicting types Int and String', + ), + locations: [{ line: 5, column: 17 }, { line: 8, column: 17 }], + }, + ]); }); it('reports correctly when a non-exclusive follows an exclusive', () => { - expectFailsRuleWithSchema( + expectErrorsWithSchema( schema, - OverlappingFieldsCanBeMerged, ` - { - someBox { - ... on IntBox { - deepBox { - ...X + { + someBox { + ... on IntBox { + deepBox { + ...X + } } } - } - someBox { - ... on StringBox { - deepBox { - ...Y + someBox { + ... on StringBox { + deepBox { + ...Y + } } } - } - memoed: someBox { - ... on IntBox { - deepBox { - ...X + memoed: someBox { + ... on IntBox { + deepBox { + ...X + } } } - } - memoed: someBox { - ... on StringBox { - deepBox { - ...Y + memoed: someBox { + ... on StringBox { + deepBox { + ...Y + } } } + other: someBox { + ...X + } + other: someBox { + ...Y + } } - other: someBox { - ...X + fragment X on SomeBox { + scalar } - other: someBox { - ...Y + fragment Y on SomeBox { + scalar: unrelatedField } - } - fragment X on SomeBox { - scalar - } - fragment Y on SomeBox { - scalar: unrelatedField - } - `, - [ - { - message: fieldsConflictMessage('other', [ - ['scalar', 'scalar and unrelatedField are different fields'], - ]), - locations: [ - { line: 31, column: 11 }, - { line: 39, column: 11 }, - { line: 34, column: 11 }, - { line: 42, column: 11 }, - ], - }, - ], - ); + `, + ).to.deep.equal([ + { + message: fieldsConflictMessage('other', [ + ['scalar', 'scalar and unrelatedField are different fields'], + ]), + locations: [ + { line: 31, column: 13 }, + { line: 39, column: 13 }, + { line: 34, column: 13 }, + { line: 42, column: 13 }, + ], + }, + ]); }); it('disallows differing return type nullability despite no overlap', () => { - expectFailsRuleWithSchema( + expectErrorsWithSchema( schema, - OverlappingFieldsCanBeMerged, ` - { - someBox { - ... on NonNullStringBox1 { - scalar - } - ... on StringBox { - scalar + { + someBox { + ... on NonNullStringBox1 { + scalar + } + ... on StringBox { + scalar + } } } - } - `, - [ - { - message: fieldsConflictMessage( - 'scalar', - 'they return conflicting types String! and String', - ), - locations: [{ line: 5, column: 15 }, { line: 8, column: 15 }], - }, - ], - ); + `, + ).to.deep.equal([ + { + message: fieldsConflictMessage( + 'scalar', + 'they return conflicting types String! and String', + ), + locations: [{ line: 5, column: 17 }, { line: 8, column: 17 }], + }, + ]); }); it('disallows differing return type list despite no overlap', () => { - expectFailsRuleWithSchema( + expectErrorsWithSchema( schema, - OverlappingFieldsCanBeMerged, ` - { - someBox { - ... on IntBox { - box: listStringBox { - scalar + { + someBox { + ... on IntBox { + box: listStringBox { + scalar + } } - } - ... on StringBox { - box: stringBox { - scalar + ... on StringBox { + box: stringBox { + scalar + } } } } - } - `, - [ - { - message: fieldsConflictMessage( - 'box', - 'they return conflicting types [StringBox] and StringBox', - ), - locations: [{ line: 5, column: 15 }, { line: 10, column: 15 }], - }, - ], - ); + `, + ).to.deep.equal([ + { + message: fieldsConflictMessage( + 'box', + 'they return conflicting types [StringBox] and StringBox', + ), + locations: [{ line: 5, column: 17 }, { line: 10, column: 17 }], + }, + ]); - expectFailsRuleWithSchema( + expectErrorsWithSchema( schema, - OverlappingFieldsCanBeMerged, ` - { - someBox { - ... on IntBox { - box: stringBox { - scalar + { + someBox { + ... on IntBox { + box: stringBox { + scalar + } } - } - ... on StringBox { - box: listStringBox { - scalar + ... on StringBox { + box: listStringBox { + scalar + } } } } - } - `, - [ - { - message: fieldsConflictMessage( - 'box', - 'they return conflicting types StringBox and [StringBox]', - ), - locations: [{ line: 5, column: 15 }, { line: 10, column: 15 }], - }, - ], - ); + `, + ).to.deep.equal([ + { + message: fieldsConflictMessage( + 'box', + 'they return conflicting types StringBox and [StringBox]', + ), + locations: [{ line: 5, column: 17 }, { line: 10, column: 17 }], + }, + ]); }); it('disallows differing subfields', () => { - expectFailsRuleWithSchema( + expectErrorsWithSchema( schema, - OverlappingFieldsCanBeMerged, ` - { - someBox { - ... on IntBox { - box: stringBox { - val: scalar - val: unrelatedField + { + someBox { + ... on IntBox { + box: stringBox { + val: scalar + val: unrelatedField + } } - } - ... on StringBox { - box: stringBox { - val: scalar + ... on StringBox { + box: stringBox { + val: scalar + } } } } - } - `, - [ - { - message: fieldsConflictMessage( - 'val', - 'scalar and unrelatedField are different fields', - ), - locations: [{ line: 6, column: 17 }, { line: 7, column: 17 }], - }, - ], - ); + `, + ).to.deep.equal([ + { + message: fieldsConflictMessage( + 'val', + 'scalar and unrelatedField are different fields', + ), + locations: [{ line: 6, column: 19 }, { line: 7, column: 19 }], + }, + ]); }); it('disallows differing deep return types despite no overlap', () => { - expectFailsRuleWithSchema( + expectErrorsWithSchema( schema, - OverlappingFieldsCanBeMerged, ` - { - someBox { - ... on IntBox { - box: stringBox { - scalar + { + someBox { + ... on IntBox { + box: stringBox { + scalar + } } - } - ... on StringBox { - box: intBox { - scalar + ... on StringBox { + box: intBox { + scalar + } } } } - } - `, - [ - { - message: fieldsConflictMessage('box', [ - ['scalar', 'they return conflicting types String and Int'], - ]), - locations: [ - { line: 5, column: 15 }, - { line: 6, column: 17 }, - { line: 10, column: 15 }, - { line: 11, column: 17 }, - ], - }, - ], - ); + `, + ).to.deep.equal([ + { + message: fieldsConflictMessage('box', [ + ['scalar', 'they return conflicting types String and Int'], + ]), + locations: [ + { line: 5, column: 17 }, + { line: 6, column: 19 }, + { line: 10, column: 17 }, + { line: 11, column: 19 }, + ], + }, + ]); }); it('allows non-conflicting overlapping types', () => { - expectPassesRuleWithSchema( + expectValidWithSchema( schema, - OverlappingFieldsCanBeMerged, ` - { - someBox { - ... on IntBox { - scalar: unrelatedField - } - ... on StringBox { - scalar + { + someBox { + ... on IntBox { + scalar: unrelatedField + } + ... on StringBox { + scalar + } } } - } - `, + `, ); }); it('same wrapped scalar return types', () => { - expectPassesRuleWithSchema( + expectValidWithSchema( schema, - OverlappingFieldsCanBeMerged, ` - { - someBox { - ...on NonNullStringBox1 { - scalar - } - ...on NonNullStringBox2 { - scalar + { + someBox { + ...on NonNullStringBox1 { + scalar + } + ...on NonNullStringBox2 { + scalar + } } } - } - `, + `, ); }); it('allows inline typeless fragments', () => { - expectPassesRuleWithSchema( + expectValidWithSchema( schema, - OverlappingFieldsCanBeMerged, ` - { - a - ... { + { a + ... { + a + } } - } - `, + `, ); }); it('compares deep types including list', () => { - expectFailsRuleWithSchema( + expectErrorsWithSchema( schema, - OverlappingFieldsCanBeMerged, ` - { - connection { - ...edgeID - edges { - node { - id: name + { + connection { + ...edgeID + edges { + node { + id: name + } } } } - } - fragment edgeID on Connection { - edges { - node { - id + fragment edgeID on Connection { + edges { + node { + id + } } } - } - `, - [ - { - message: fieldsConflictMessage('edges', [ - ['node', [['id', 'name and id are different fields']]], - ]), - locations: [ - { line: 5, column: 13 }, - { line: 6, column: 15 }, - { line: 7, column: 17 }, - { line: 14, column: 11 }, - { line: 15, column: 13 }, - { line: 16, column: 15 }, - ], - }, - ], - ); + `, + ).to.deep.equal([ + { + message: fieldsConflictMessage('edges', [ + ['node', [['id', 'name and id are different fields']]], + ]), + locations: [ + { line: 5, column: 15 }, + { line: 6, column: 17 }, + { line: 7, column: 19 }, + { line: 14, column: 13 }, + { line: 15, column: 15 }, + { line: 16, column: 17 }, + ], + }, + ]); }); it('ignores unknown types', () => { - expectPassesRuleWithSchema( + expectValidWithSchema( schema, - OverlappingFieldsCanBeMerged, ` - { - someBox { - ...on UnknownType { - scalar - } - ...on NonNullStringBox2 { - scalar + { + someBox { + ...on UnknownType { + scalar + } + ...on NonNullStringBox2 { + scalar + } } } - } - `, + `, ); }); @@ -1067,66 +981,54 @@ describe('Validate: Overlapping fields can be merged', () => { } `); - expectPassesRuleWithSchema( + expectValidWithSchema( schemaWithKeywords, - OverlappingFieldsCanBeMerged, - `{ - foo { - constructor + ` + { + foo { + constructor + } } - }`, + `, ); }); }); it('does not infinite loop on recursive fragment', () => { - expectPassesRule( - OverlappingFieldsCanBeMerged, - ` + expectValid(` fragment fragA on Human { name, relatives { name, ...fragA } } - `, - ); + `); }); it('does not infinite loop on immediately recursive fragment', () => { - expectPassesRule( - OverlappingFieldsCanBeMerged, - ` + expectValid(` fragment fragA on Human { name, ...fragA } - `, - ); + `); }); it('does not infinite loop on transitively recursive fragment', () => { - expectPassesRule( - OverlappingFieldsCanBeMerged, - ` + expectValid(` fragment fragA on Human { name, ...fragB } fragment fragB on Human { name, ...fragC } fragment fragC on Human { name, ...fragA } - `, - ); + `); }); it('finds invalid case even with immediately recursive fragment', () => { - expectFailsRule( - OverlappingFieldsCanBeMerged, - ` + expectErrors(` fragment sameAliasesWithDifferentFieldTargets on Dog { ...sameAliasesWithDifferentFieldTargets fido: name fido: nickname } - `, - [ - { - message: fieldsConflictMessage( - 'fido', - 'name and nickname are different fields', - ), - locations: [{ line: 4, column: 9 }, { line: 5, column: 9 }], - }, - ], - ); + `).to.deep.equal([ + { + message: fieldsConflictMessage( + 'fido', + 'name and nickname are different fields', + ), + locations: [{ line: 4, column: 9 }, { line: 5, column: 9 }], + }, + ]); }); }); diff --git a/src/validation/__tests__/PossibleFragmentSpreads-test.js b/src/validation/__tests__/PossibleFragmentSpreads-test.js index e0d5208727..7f1042e10c 100644 --- a/src/validation/__tests__/PossibleFragmentSpreads-test.js +++ b/src/validation/__tests__/PossibleFragmentSpreads-test.js @@ -8,13 +8,21 @@ */ import { describe, it } from 'mocha'; -import { expectPassesRule, expectFailsRule } from './harness'; +import { expectValidationErrors } from './harness'; import { PossibleFragmentSpreads, typeIncompatibleSpreadMessage, typeIncompatibleAnonSpreadMessage, } from '../rules/PossibleFragmentSpreads'; +function expectErrors(queryStr) { + return expectValidationErrors(PossibleFragmentSpreads, queryStr); +} + +function expectValid(queryStr) { + expectErrors(queryStr).to.deep.equal([]); +} + function error(fragName, parentType, fragType, line, column) { return { message: typeIncompatibleSpreadMessage(fragName, parentType, fragType), @@ -31,245 +39,173 @@ function errorAnon(parentType, fragType, line, column) { describe('Validate: Possible fragment spreads', () => { it('of the same object', () => { - expectPassesRule( - PossibleFragmentSpreads, - ` + expectValid(` fragment objectWithinObject on Dog { ...dogFragment } fragment dogFragment on Dog { barkVolume } - `, - ); + `); }); it('of the same object with inline fragment', () => { - expectPassesRule( - PossibleFragmentSpreads, - ` + expectValid(` fragment objectWithinObjectAnon on Dog { ... on Dog { barkVolume } } - `, - ); + `); }); it('object into an implemented interface', () => { - expectPassesRule( - PossibleFragmentSpreads, - ` + expectValid(` fragment objectWithinInterface on Pet { ...dogFragment } fragment dogFragment on Dog { barkVolume } - `, - ); + `); }); it('object into containing union', () => { - expectPassesRule( - PossibleFragmentSpreads, - ` + expectValid(` fragment objectWithinUnion on CatOrDog { ...dogFragment } fragment dogFragment on Dog { barkVolume } - `, - ); + `); }); it('union into contained object', () => { - expectPassesRule( - PossibleFragmentSpreads, - ` + expectValid(` fragment unionWithinObject on Dog { ...catOrDogFragment } fragment catOrDogFragment on CatOrDog { __typename } - `, - ); + `); }); it('union into overlapping interface', () => { - expectPassesRule( - PossibleFragmentSpreads, - ` + expectValid(` fragment unionWithinInterface on Pet { ...catOrDogFragment } fragment catOrDogFragment on CatOrDog { __typename } - `, - ); + `); }); it('union into overlapping union', () => { - expectPassesRule( - PossibleFragmentSpreads, - ` + expectValid(` fragment unionWithinUnion on DogOrHuman { ...catOrDogFragment } fragment catOrDogFragment on CatOrDog { __typename } - `, - ); + `); }); it('interface into implemented object', () => { - expectPassesRule( - PossibleFragmentSpreads, - ` + expectValid(` fragment interfaceWithinObject on Dog { ...petFragment } fragment petFragment on Pet { name } - `, - ); + `); }); it('interface into overlapping interface', () => { - expectPassesRule( - PossibleFragmentSpreads, - ` + expectValid(` fragment interfaceWithinInterface on Pet { ...beingFragment } fragment beingFragment on Being { name } - `, - ); + `); }); it('interface into overlapping interface in inline fragment', () => { - expectPassesRule( - PossibleFragmentSpreads, - ` + expectValid(` fragment interfaceWithinInterface on Pet { ... on Being { name } } - `, - ); + `); }); it('interface into overlapping union', () => { - expectPassesRule( - PossibleFragmentSpreads, - ` + expectValid(` fragment interfaceWithinUnion on CatOrDog { ...petFragment } fragment petFragment on Pet { name } - `, - ); + `); }); it('ignores incorrect type (caught by FragmentsOnCompositeTypes)', () => { - expectPassesRule( - PossibleFragmentSpreads, - ` + expectValid(` fragment petFragment on Pet { ...badInADifferentWay } fragment badInADifferentWay on String { name } - `, - ); + `); }); it('different object into object', () => { - expectFailsRule( - PossibleFragmentSpreads, - ` + expectErrors(` fragment invalidObjectWithinObject on Cat { ...dogFragment } fragment dogFragment on Dog { barkVolume } - `, - [error('dogFragment', 'Cat', 'Dog', 2, 51)], - ); + `).to.deep.equal([error('dogFragment', 'Cat', 'Dog', 2, 51)]); }); it('different object into object in inline fragment', () => { - expectFailsRule( - PossibleFragmentSpreads, - ` + expectErrors(` fragment invalidObjectWithinObjectAnon on Cat { ... on Dog { barkVolume } } - `, - [errorAnon('Cat', 'Dog', 3, 9)], - ); + `).to.deep.equal([errorAnon('Cat', 'Dog', 3, 9)]); }); it('object into not implementing interface', () => { - expectFailsRule( - PossibleFragmentSpreads, - ` + expectErrors(` fragment invalidObjectWithinInterface on Pet { ...humanFragment } fragment humanFragment on Human { pets { name } } - `, - [error('humanFragment', 'Pet', 'Human', 2, 54)], - ); + `).to.deep.equal([error('humanFragment', 'Pet', 'Human', 2, 54)]); }); it('object into not containing union', () => { - expectFailsRule( - PossibleFragmentSpreads, - ` + expectErrors(` fragment invalidObjectWithinUnion on CatOrDog { ...humanFragment } fragment humanFragment on Human { pets { name } } - `, - [error('humanFragment', 'CatOrDog', 'Human', 2, 55)], - ); + `).to.deep.equal([error('humanFragment', 'CatOrDog', 'Human', 2, 55)]); }); it('union into not contained object', () => { - expectFailsRule( - PossibleFragmentSpreads, - ` + expectErrors(` fragment invalidUnionWithinObject on Human { ...catOrDogFragment } fragment catOrDogFragment on CatOrDog { __typename } - `, - [error('catOrDogFragment', 'Human', 'CatOrDog', 2, 52)], - ); + `).to.deep.equal([error('catOrDogFragment', 'Human', 'CatOrDog', 2, 52)]); }); it('union into non overlapping interface', () => { - expectFailsRule( - PossibleFragmentSpreads, - ` + expectErrors(` fragment invalidUnionWithinInterface on Pet { ...humanOrAlienFragment } fragment humanOrAlienFragment on HumanOrAlien { __typename } - `, - [error('humanOrAlienFragment', 'Pet', 'HumanOrAlien', 2, 53)], - ); + `).to.deep.equal([ + error('humanOrAlienFragment', 'Pet', 'HumanOrAlien', 2, 53), + ]); }); it('union into non overlapping union', () => { - expectFailsRule( - PossibleFragmentSpreads, - ` + expectErrors(` fragment invalidUnionWithinUnion on CatOrDog { ...humanOrAlienFragment } fragment humanOrAlienFragment on HumanOrAlien { __typename } - `, - [error('humanOrAlienFragment', 'CatOrDog', 'HumanOrAlien', 2, 54)], - ); + `).to.deep.equal([ + error('humanOrAlienFragment', 'CatOrDog', 'HumanOrAlien', 2, 54), + ]); }); it('interface into non implementing object', () => { - expectFailsRule( - PossibleFragmentSpreads, - ` + expectErrors(` fragment invalidInterfaceWithinObject on Cat { ...intelligentFragment } fragment intelligentFragment on Intelligent { iq } - `, - [error('intelligentFragment', 'Cat', 'Intelligent', 2, 54)], - ); + `).to.deep.equal([ + error('intelligentFragment', 'Cat', 'Intelligent', 2, 54), + ]); }); it('interface into non overlapping interface', () => { - expectFailsRule( - PossibleFragmentSpreads, - ` + expectErrors(` fragment invalidInterfaceWithinInterface on Pet { ...intelligentFragment } fragment intelligentFragment on Intelligent { iq } - `, - [error('intelligentFragment', 'Pet', 'Intelligent', 3, 9)], - ); + `).to.deep.equal([ + error('intelligentFragment', 'Pet', 'Intelligent', 3, 9), + ]); }); it('interface into non overlapping interface in inline fragment', () => { - expectFailsRule( - PossibleFragmentSpreads, - ` + expectErrors(` fragment invalidInterfaceWithinInterfaceAnon on Pet { ...on Intelligent { iq } } - `, - [errorAnon('Pet', 'Intelligent', 3, 9)], - ); + `).to.deep.equal([errorAnon('Pet', 'Intelligent', 3, 9)]); }); it('interface into non overlapping union', () => { - expectFailsRule( - PossibleFragmentSpreads, - ` + expectErrors(` fragment invalidInterfaceWithinUnion on HumanOrAlien { ...petFragment } fragment petFragment on Pet { name } - `, - [error('petFragment', 'HumanOrAlien', 'Pet', 2, 62)], - ); + `).to.deep.equal([error('petFragment', 'HumanOrAlien', 'Pet', 2, 62)]); }); }); diff --git a/src/validation/__tests__/ProvidedRequiredArguments-test.js b/src/validation/__tests__/ProvidedRequiredArguments-test.js index 4948514665..4b28038084 100644 --- a/src/validation/__tests__/ProvidedRequiredArguments-test.js +++ b/src/validation/__tests__/ProvidedRequiredArguments-test.js @@ -9,11 +9,7 @@ import { describe, it } from 'mocha'; import { buildSchema } from '../../utilities'; -import { - expectPassesRule, - expectFailsRule, - expectSDLErrorsFromRule, -} from './harness'; +import { expectValidationErrors, expectSDLValidationErrors } from './harness'; import { ProvidedRequiredArguments, ProvidedRequiredArgumentsOnDirectives, @@ -21,10 +17,25 @@ import { missingDirectiveArgMessage, } from '../rules/ProvidedRequiredArguments'; -const expectSDLErrors = expectSDLErrorsFromRule.bind( - undefined, - ProvidedRequiredArgumentsOnDirectives, -); +function expectErrors(queryStr) { + return expectValidationErrors(ProvidedRequiredArguments, queryStr); +} + +function expectValid(queryStr) { + expectErrors(queryStr).to.deep.equal([]); +} + +function expectSDLErrors(sdlStr, schema) { + return expectSDLValidationErrors( + schema, + ProvidedRequiredArgumentsOnDirectives, + sdlStr, + ); +} + +function expectValidSDL(sdlStr) { + expectSDLErrors(sdlStr).to.deep.equal([]); +} function missingFieldArg(fieldName, argName, typeName, line, column) { return { @@ -42,226 +53,177 @@ function missingDirectiveArg(directiveName, argName, typeName, line, column) { describe('Validate: Provided required arguments', () => { it('ignores unknown arguments', () => { - expectPassesRule( - ProvidedRequiredArguments, - ` + expectValid(` { dog { isHousetrained(unknownArgument: true) } } - `, - ); + `); }); describe('Valid non-nullable value', () => { it('Arg on optional arg', () => { - expectPassesRule( - ProvidedRequiredArguments, - ` + expectValid(` { dog { isHousetrained(atOtherHomes: true) } } - `, - ); + `); }); it('No Arg on optional arg', () => { - expectPassesRule( - ProvidedRequiredArguments, - ` + expectValid(` { dog { isHousetrained } } - `, - ); + `); }); it('No arg on non-null field with default', () => { - expectPassesRule( - ProvidedRequiredArguments, - ` + expectValid(` { complicatedArgs { nonNullFieldWithDefault } } - `, - ); + `); }); it('Multiple args', () => { - expectPassesRule( - ProvidedRequiredArguments, - ` + expectValid(` { complicatedArgs { multipleReqs(req1: 1, req2: 2) } } - `, - ); + `); }); it('Multiple args reverse order', () => { - expectPassesRule( - ProvidedRequiredArguments, - ` + expectValid(` { complicatedArgs { multipleReqs(req2: 2, req1: 1) } } - `, - ); + `); }); it('No args on multiple optional', () => { - expectPassesRule( - ProvidedRequiredArguments, - ` + expectValid(` { complicatedArgs { multipleOpts } } - `, - ); + `); }); it('One arg on multiple optional', () => { - expectPassesRule( - ProvidedRequiredArguments, - ` + expectValid(` { complicatedArgs { multipleOpts(opt1: 1) } } - `, - ); + `); }); it('Second arg on multiple optional', () => { - expectPassesRule( - ProvidedRequiredArguments, - ` + expectValid(` { complicatedArgs { multipleOpts(opt2: 1) } } - `, - ); + `); }); it('Multiple reqs on mixedList', () => { - expectPassesRule( - ProvidedRequiredArguments, - ` + expectValid(` { complicatedArgs { multipleOptAndReq(req1: 3, req2: 4) } } - `, - ); + `); }); it('Multiple reqs and one opt on mixedList', () => { - expectPassesRule( - ProvidedRequiredArguments, - ` + expectValid(` { complicatedArgs { multipleOptAndReq(req1: 3, req2: 4, opt1: 5) } } - `, - ); + `); }); it('All reqs and opts on mixedList', () => { - expectPassesRule( - ProvidedRequiredArguments, - ` + expectValid(` { complicatedArgs { multipleOptAndReq(req1: 3, req2: 4, opt1: 5, opt2: 6) } } - `, - ); + `); }); }); describe('Invalid non-nullable value', () => { it('Missing one non-nullable argument', () => { - expectFailsRule( - ProvidedRequiredArguments, - ` + expectErrors(` { complicatedArgs { multipleReqs(req2: 2) } } - `, - [missingFieldArg('multipleReqs', 'req1', 'Int!', 4, 13)], - ); + `).to.deep.equal([ + missingFieldArg('multipleReqs', 'req1', 'Int!', 4, 13), + ]); }); it('Missing multiple non-nullable arguments', () => { - expectFailsRule( - ProvidedRequiredArguments, - ` + expectErrors(` { complicatedArgs { multipleReqs } } - `, - [ - missingFieldArg('multipleReqs', 'req1', 'Int!', 4, 13), - missingFieldArg('multipleReqs', 'req2', 'Int!', 4, 13), - ], - ); + `).to.deep.equal([ + missingFieldArg('multipleReqs', 'req1', 'Int!', 4, 13), + missingFieldArg('multipleReqs', 'req2', 'Int!', 4, 13), + ]); }); it('Incorrect value and missing argument', () => { - expectFailsRule( - ProvidedRequiredArguments, - ` + expectErrors(` { complicatedArgs { multipleReqs(req1: "one") } } - `, - [missingFieldArg('multipleReqs', 'req2', 'Int!', 4, 13)], - ); + `).to.deep.equal([ + missingFieldArg('multipleReqs', 'req2', 'Int!', 4, 13), + ]); }); }); describe('Directive arguments', () => { it('ignores unknown directives', () => { - expectPassesRule( - ProvidedRequiredArguments, - ` + expectValid(` { dog @unknown } - `, - ); + `); }); it('with directives of valid types', () => { - expectPassesRule( - ProvidedRequiredArguments, - ` + expectValid(` { dog @include(if: true) { name @@ -270,37 +232,32 @@ describe('Validate: Provided required arguments', () => { name } } - `, - ); + `); }); it('with directive with missing types', () => { - expectFailsRule( - ProvidedRequiredArguments, - ` + expectErrors(` { dog @include { name @skip } } - `, - [ - missingDirectiveArg('include', 'if', 'Boolean!', 3, 15), - missingDirectiveArg('skip', 'if', 'Boolean!', 4, 18), - ], - ); + `).to.deep.equal([ + missingDirectiveArg('include', 'if', 'Boolean!', 3, 15), + missingDirectiveArg('skip', 'if', 'Boolean!', 4, 18), + ]); }); }); describe('within SDL', () => { it('Missing optional args on directive defined inside SDL', () => { - expectSDLErrors(` + expectValidSDL(` type Query { foo: String @test } directive @test(arg1: String, arg2: String! = "") on FIELD_DEFINITION - `).to.deep.equal([]); + `); }); it('Missing arg on directive defined inside SDL', () => { diff --git a/src/validation/__tests__/ScalarLeafs-test.js b/src/validation/__tests__/ScalarLeafs-test.js index 1e66180b9c..fa6bd70dc6 100644 --- a/src/validation/__tests__/ScalarLeafs-test.js +++ b/src/validation/__tests__/ScalarLeafs-test.js @@ -8,13 +8,21 @@ */ import { describe, it } from 'mocha'; -import { expectPassesRule, expectFailsRule } from './harness'; +import { expectValidationErrors } from './harness'; import { ScalarLeafs, noSubselectionAllowedMessage, requiredSubselectionMessage, } from '../rules/ScalarLeafs'; +function expectErrors(queryStr) { + return expectValidationErrors(ScalarLeafs, queryStr); +} + +function expectValid(queryStr) { + expectErrors(queryStr).to.deep.equal([]); +} + function noScalarSubselection(field, type, line, column) { return { message: noSubselectionAllowedMessage(field, type), @@ -31,108 +39,78 @@ function missingObjSubselection(field, type, line, column) { describe('Validate: Scalar leafs', () => { it('valid scalar selection', () => { - expectPassesRule( - ScalarLeafs, - ` + expectValid(` fragment scalarSelection on Dog { barks } - `, - ); + `); }); it('object type missing selection', () => { - expectFailsRule( - ScalarLeafs, - ` + expectErrors(` query directQueryOnObjectWithoutSubFields { human } - `, - [missingObjSubselection('human', 'Human', 3, 9)], - ); + `).to.deep.equal([missingObjSubselection('human', 'Human', 3, 9)]); }); it('interface type missing selection', () => { - expectFailsRule( - ScalarLeafs, - ` + expectErrors(` { human { pets } } - `, - [missingObjSubselection('pets', '[Pet]', 3, 17)], - ); + `).to.deep.equal([missingObjSubselection('pets', '[Pet]', 3, 17)]); }); it('valid scalar selection with args', () => { - expectPassesRule( - ScalarLeafs, - ` + expectValid(` fragment scalarSelectionWithArgs on Dog { doesKnowCommand(dogCommand: SIT) } - `, - ); + `); }); it('scalar selection not allowed on Boolean', () => { - expectFailsRule( - ScalarLeafs, - ` + expectErrors(` fragment scalarSelectionsNotAllowedOnBoolean on Dog { barks { sinceWhen } } - `, - [noScalarSubselection('barks', 'Boolean', 3, 15)], - ); + `).to.deep.equal([noScalarSubselection('barks', 'Boolean', 3, 15)]); }); it('scalar selection not allowed on Enum', () => { - expectFailsRule( - ScalarLeafs, - ` + expectErrors(` fragment scalarSelectionsNotAllowedOnEnum on Cat { furColor { inHexdec } } - `, - [noScalarSubselection('furColor', 'FurColor', 3, 18)], - ); + `).to.deep.equal([noScalarSubselection('furColor', 'FurColor', 3, 18)]); }); it('scalar selection not allowed with args', () => { - expectFailsRule( - ScalarLeafs, - ` + expectErrors(` fragment scalarSelectionsNotAllowedWithArgs on Dog { doesKnowCommand(dogCommand: SIT) { sinceWhen } } - `, - [noScalarSubselection('doesKnowCommand', 'Boolean', 3, 42)], - ); + `).to.deep.equal([ + noScalarSubselection('doesKnowCommand', 'Boolean', 3, 42), + ]); }); it('Scalar selection not allowed with directives', () => { - expectFailsRule( - ScalarLeafs, - ` + expectErrors(` fragment scalarSelectionsNotAllowedWithDirectives on Dog { name @include(if: true) { isAlsoHumanName } } - `, - [noScalarSubselection('name', 'String', 3, 33)], - ); + `).to.deep.equal([noScalarSubselection('name', 'String', 3, 33)]); }); it('Scalar selection not allowed with directives and args', () => { - expectFailsRule( - ScalarLeafs, - ` + expectErrors(` fragment scalarSelectionsNotAllowedWithDirectivesAndArgs on Dog { doesKnowCommand(dogCommand: SIT) @include(if: true) { sinceWhen } } - `, - [noScalarSubselection('doesKnowCommand', 'Boolean', 3, 61)], - ); + `).to.deep.equal([ + noScalarSubselection('doesKnowCommand', 'Boolean', 3, 61), + ]); }); }); diff --git a/src/validation/__tests__/SingleFieldSubscriptions-test.js b/src/validation/__tests__/SingleFieldSubscriptions-test.js index e428640cad..066c00deb2 100644 --- a/src/validation/__tests__/SingleFieldSubscriptions-test.js +++ b/src/validation/__tests__/SingleFieldSubscriptions-test.js @@ -8,94 +8,83 @@ */ import { describe, it } from 'mocha'; -import { expectPassesRule, expectFailsRule } from './harness'; +import { expectValidationErrors } from './harness'; import { SingleFieldSubscriptions, singleFieldOnlyMessage, } from '../rules/SingleFieldSubscriptions'; +function expectErrors(queryStr) { + return expectValidationErrors(SingleFieldSubscriptions, queryStr); +} + +function expectValid(queryStr) { + expectErrors(queryStr).to.deep.equal([]); +} + describe('Validate: Subscriptions with single field', () => { it('valid subscription', () => { - expectPassesRule( - SingleFieldSubscriptions, - ` + expectValid(` subscription ImportantEmails { importantEmails } - `, - ); + `); }); it('fails with more than one root field', () => { - expectFailsRule( - SingleFieldSubscriptions, - ` + expectErrors(` subscription ImportantEmails { importantEmails notImportantEmails } - `, - [ - { - message: singleFieldOnlyMessage('ImportantEmails'), - locations: [{ line: 4, column: 9 }], - }, - ], - ); + `).to.deep.equal([ + { + message: singleFieldOnlyMessage('ImportantEmails'), + locations: [{ line: 4, column: 9 }], + }, + ]); }); it('fails with more than one root field including introspection', () => { - expectFailsRule( - SingleFieldSubscriptions, - ` + expectErrors(` subscription ImportantEmails { importantEmails __typename } - `, - [ - { - message: singleFieldOnlyMessage('ImportantEmails'), - locations: [{ line: 4, column: 9 }], - }, - ], - ); + `).to.deep.equal([ + { + message: singleFieldOnlyMessage('ImportantEmails'), + locations: [{ line: 4, column: 9 }], + }, + ]); }); it('fails with many more than one root field', () => { - expectFailsRule( - SingleFieldSubscriptions, - ` + expectErrors(` subscription ImportantEmails { importantEmails notImportantEmails spamEmails } - `, - [ - { - message: singleFieldOnlyMessage('ImportantEmails'), - locations: [{ line: 4, column: 9 }, { line: 5, column: 9 }], - }, - ], - ); + `).to.deep.equal([ + { + message: singleFieldOnlyMessage('ImportantEmails'), + locations: [{ line: 4, column: 9 }, { line: 5, column: 9 }], + }, + ]); }); it('fails with more than one root field in anonymous subscriptions', () => { - expectFailsRule( - SingleFieldSubscriptions, - ` + expectErrors(` subscription { importantEmails notImportantEmails } - `, - [ - { - message: singleFieldOnlyMessage(null), - locations: [{ line: 4, column: 9 }], - }, - ], - ); + `).to.deep.equal([ + { + message: singleFieldOnlyMessage(null), + locations: [{ line: 4, column: 9 }], + }, + ]); }); }); diff --git a/src/validation/__tests__/UniqueArgumentNames-test.js b/src/validation/__tests__/UniqueArgumentNames-test.js index 63071e22ac..a171638aa4 100644 --- a/src/validation/__tests__/UniqueArgumentNames-test.js +++ b/src/validation/__tests__/UniqueArgumentNames-test.js @@ -8,12 +8,20 @@ */ import { describe, it } from 'mocha'; -import { expectPassesRule, expectFailsRule } from './harness'; +import { expectValidationErrors } from './harness'; import { UniqueArgumentNames, duplicateArgMessage, } from '../rules/UniqueArgumentNames'; +function expectErrors(queryStr) { + return expectValidationErrors(UniqueArgumentNames, queryStr); +} + +function expectValid(queryStr) { + expectErrors(queryStr).to.deep.equal([]); +} + function duplicateArg(argName, l1, c1, l2, c2) { return { message: duplicateArgMessage(argName), @@ -23,150 +31,113 @@ function duplicateArg(argName, l1, c1, l2, c2) { describe('Validate: Unique argument names', () => { it('no arguments on field', () => { - expectPassesRule( - UniqueArgumentNames, - ` + expectValid(` { field } - `, - ); + `); }); it('no arguments on directive', () => { - expectPassesRule( - UniqueArgumentNames, - ` + expectValid(` { field @directive } - `, - ); + `); }); it('argument on field', () => { - expectPassesRule( - UniqueArgumentNames, - ` + expectValid(` { field(arg: "value") } - `, - ); + `); }); it('argument on directive', () => { - expectPassesRule( - UniqueArgumentNames, - ` + expectValid(` { field @directive(arg: "value") } - `, - ); + `); }); it('same argument on two fields', () => { - expectPassesRule( - UniqueArgumentNames, - ` + expectValid(` { one: field(arg: "value") two: field(arg: "value") } - `, - ); + `); }); it('same argument on field and directive', () => { - expectPassesRule( - UniqueArgumentNames, - ` + expectValid(` { field(arg: "value") @directive(arg: "value") } - `, - ); + `); }); it('same argument on two directives', () => { - expectPassesRule( - UniqueArgumentNames, - ` + expectValid(` { field @directive1(arg: "value") @directive2(arg: "value") } - `, - ); + `); }); it('multiple field arguments', () => { - expectPassesRule( - UniqueArgumentNames, - ` + expectValid(` { field(arg1: "value", arg2: "value", arg3: "value") } - `, - ); + `); }); it('multiple directive arguments', () => { - expectPassesRule( - UniqueArgumentNames, - ` + expectValid(` { field @directive(arg1: "value", arg2: "value", arg3: "value") } - `, - ); + `); }); it('duplicate field arguments', () => { - expectFailsRule( - UniqueArgumentNames, - ` + expectErrors(` { field(arg1: "value", arg1: "value") } - `, - [duplicateArg('arg1', 3, 15, 3, 30)], - ); + `).to.deep.equal([duplicateArg('arg1', 3, 15, 3, 30)]); }); it('many duplicate field arguments', () => { - expectFailsRule( - UniqueArgumentNames, - ` + expectErrors(` { field(arg1: "value", arg1: "value", arg1: "value") } - `, - [duplicateArg('arg1', 3, 15, 3, 30), duplicateArg('arg1', 3, 15, 3, 45)], - ); + `).to.deep.equal([ + duplicateArg('arg1', 3, 15, 3, 30), + duplicateArg('arg1', 3, 15, 3, 45), + ]); }); it('duplicate directive arguments', () => { - expectFailsRule( - UniqueArgumentNames, - ` + expectErrors(` { field @directive(arg1: "value", arg1: "value") } - `, - [duplicateArg('arg1', 3, 26, 3, 41)], - ); + `).to.deep.equal([duplicateArg('arg1', 3, 26, 3, 41)]); }); it('many duplicate directive arguments', () => { - expectFailsRule( - UniqueArgumentNames, - ` + expectErrors(` { field @directive(arg1: "value", arg1: "value", arg1: "value") } - `, - [duplicateArg('arg1', 3, 26, 3, 41), duplicateArg('arg1', 3, 26, 3, 56)], - ); + `).to.deep.equal([ + duplicateArg('arg1', 3, 26, 3, 41), + duplicateArg('arg1', 3, 26, 3, 56), + ]); }); }); diff --git a/src/validation/__tests__/UniqueDirectivesPerLocation-test.js b/src/validation/__tests__/UniqueDirectivesPerLocation-test.js index d0c07813fe..fc4e6f4a8b 100644 --- a/src/validation/__tests__/UniqueDirectivesPerLocation-test.js +++ b/src/validation/__tests__/UniqueDirectivesPerLocation-test.js @@ -8,21 +8,24 @@ */ import { describe, it } from 'mocha'; -import { - expectPassesRule, - expectFailsRule, - expectSDLErrorsFromRule, -} from './harness'; +import { expectValidationErrors, expectSDLValidationErrors } from './harness'; import { UniqueDirectivesPerLocation, duplicateDirectiveMessage, } from '../rules/UniqueDirectivesPerLocation'; -const expectSDLErrors = expectSDLErrorsFromRule.bind( - undefined, - UniqueDirectivesPerLocation, -); +function expectErrors(queryStr) { + return expectValidationErrors(UniqueDirectivesPerLocation, queryStr); +} + +function expectValid(queryStr) { + expectErrors(queryStr).to.deep.equal([]); +} + +function expectSDLErrors(sdlStr, schema) { + return expectSDLValidationErrors(schema, UniqueDirectivesPerLocation, sdlStr); +} function duplicateDirective(directiveName, l1, c1, l2, c2) { return { @@ -33,116 +36,85 @@ function duplicateDirective(directiveName, l1, c1, l2, c2) { describe('Validate: Directives Are Unique Per Location', () => { it('no directives', () => { - expectPassesRule( - UniqueDirectivesPerLocation, - ` + expectValid(` fragment Test on Type { field } - `, - ); + `); }); it('unique directives in different locations', () => { - expectPassesRule( - UniqueDirectivesPerLocation, - ` + expectValid(` fragment Test on Type @directiveA { field @directiveB } - `, - ); + `); }); it('unique directives in same locations', () => { - expectPassesRule( - UniqueDirectivesPerLocation, - ` + expectValid(` fragment Test on Type @directiveA @directiveB { field @directiveA @directiveB } - `, - ); + `); }); it('same directives in different locations', () => { - expectPassesRule( - UniqueDirectivesPerLocation, - ` + expectValid(` fragment Test on Type @directiveA { field @directiveA } - `, - ); + `); }); it('same directives in similar locations', () => { - expectPassesRule( - UniqueDirectivesPerLocation, - ` + expectValid(` fragment Test on Type { field @directive field @directive } - `, - ); + `); }); it('duplicate directives in one location', () => { - expectFailsRule( - UniqueDirectivesPerLocation, - ` + expectErrors(` fragment Test on Type { field @directive @directive } - `, - [duplicateDirective('directive', 3, 15, 3, 26)], - ); + `).to.deep.equal([duplicateDirective('directive', 3, 15, 3, 26)]); }); it('many duplicate directives in one location', () => { - expectFailsRule( - UniqueDirectivesPerLocation, - ` + expectErrors(` fragment Test on Type { field @directive @directive @directive } - `, - [ - duplicateDirective('directive', 3, 15, 3, 26), - duplicateDirective('directive', 3, 15, 3, 37), - ], - ); + `).to.deep.equal([ + duplicateDirective('directive', 3, 15, 3, 26), + duplicateDirective('directive', 3, 15, 3, 37), + ]); }); it('different duplicate directives in one location', () => { - expectFailsRule( - UniqueDirectivesPerLocation, - ` + expectErrors(` fragment Test on Type { field @directiveA @directiveB @directiveA @directiveB } - `, - [ - duplicateDirective('directiveA', 3, 15, 3, 39), - duplicateDirective('directiveB', 3, 27, 3, 51), - ], - ); + `).to.deep.equal([ + duplicateDirective('directiveA', 3, 15, 3, 39), + duplicateDirective('directiveB', 3, 27, 3, 51), + ]); }); it('duplicate directives in many locations', () => { - expectFailsRule( - UniqueDirectivesPerLocation, - ` + expectErrors(` fragment Test on Type @directive @directive { field @directive @directive } - `, - [ - duplicateDirective('directive', 2, 29, 2, 40), - duplicateDirective('directive', 3, 15, 3, 26), - ], - ); + `).to.deep.equal([ + duplicateDirective('directive', 2, 29, 2, 40), + duplicateDirective('directive', 3, 15, 3, 26), + ]); }); it('duplicate directives on SDL definitions', () => { diff --git a/src/validation/__tests__/UniqueFragmentNames-test.js b/src/validation/__tests__/UniqueFragmentNames-test.js index c4c99fdd9f..810b3068ab 100644 --- a/src/validation/__tests__/UniqueFragmentNames-test.js +++ b/src/validation/__tests__/UniqueFragmentNames-test.js @@ -8,12 +8,20 @@ */ import { describe, it } from 'mocha'; -import { expectPassesRule, expectFailsRule } from './harness'; +import { expectValidationErrors } from './harness'; import { UniqueFragmentNames, duplicateFragmentNameMessage, } from '../rules/UniqueFragmentNames'; +function expectErrors(queryStr) { + return expectValidationErrors(UniqueFragmentNames, queryStr); +} + +function expectValid(queryStr) { + expectErrors(queryStr).to.deep.equal([]); +} + function duplicateFrag(fragName, l1, c1, l2, c2) { return { message: duplicateFragmentNameMessage(fragName), @@ -23,20 +31,15 @@ function duplicateFrag(fragName, l1, c1, l2, c2) { describe('Validate: Unique fragment names', () => { it('no fragments', () => { - expectPassesRule( - UniqueFragmentNames, - ` + expectValid(` { field } - `, - ); + `); }); it('one fragment', () => { - expectPassesRule( - UniqueFragmentNames, - ` + expectValid(` { ...fragA } @@ -44,14 +47,11 @@ describe('Validate: Unique fragment names', () => { fragment fragA on Type { field } - `, - ); + `); }); it('many fragments', () => { - expectPassesRule( - UniqueFragmentNames, - ` + expectValid(` { ...fragA ...fragB @@ -66,14 +66,11 @@ describe('Validate: Unique fragment names', () => { fragment fragC on Type { fieldC } - `, - ); + `); }); it('inline fragments are always unique', () => { - expectPassesRule( - UniqueFragmentNames, - ` + expectValid(` { ...on Type { fieldA @@ -82,28 +79,22 @@ describe('Validate: Unique fragment names', () => { fieldB } } - `, - ); + `); }); it('fragment and operation named the same', () => { - expectPassesRule( - UniqueFragmentNames, - ` + expectValid(` query Foo { ...Foo } fragment Foo on Type { field } - `, - ); + `); }); it('fragments named the same', () => { - expectFailsRule( - UniqueFragmentNames, - ` + expectErrors(` { ...fragA } @@ -113,23 +104,17 @@ describe('Validate: Unique fragment names', () => { fragment fragA on Type { fieldB } - `, - [duplicateFrag('fragA', 5, 16, 8, 16)], - ); + `).to.deep.equal([duplicateFrag('fragA', 5, 16, 8, 16)]); }); it('fragments named the same without being referenced', () => { - expectFailsRule( - UniqueFragmentNames, - ` + expectErrors(` fragment fragA on Type { fieldA } fragment fragA on Type { fieldB } - `, - [duplicateFrag('fragA', 2, 16, 5, 16)], - ); + `).to.deep.equal([duplicateFrag('fragA', 2, 16, 5, 16)]); }); }); diff --git a/src/validation/__tests__/UniqueInputFieldNames-test.js b/src/validation/__tests__/UniqueInputFieldNames-test.js index bd0234e204..327731ff18 100644 --- a/src/validation/__tests__/UniqueInputFieldNames-test.js +++ b/src/validation/__tests__/UniqueInputFieldNames-test.js @@ -8,12 +8,20 @@ */ import { describe, it } from 'mocha'; -import { expectPassesRule, expectFailsRule } from './harness'; +import { expectValidationErrors } from './harness'; import { UniqueInputFieldNames, duplicateInputFieldMessage, } from '../rules/UniqueInputFieldNames'; +function expectErrors(queryStr) { + return expectValidationErrors(UniqueInputFieldNames, queryStr); +} + +function expectValid(queryStr) { + expectErrors(queryStr).to.deep.equal([]); +} + function duplicateField(name, l1, c1, l2, c2) { return { message: duplicateInputFieldMessage(name), @@ -23,42 +31,31 @@ function duplicateField(name, l1, c1, l2, c2) { describe('Validate: Unique input field names', () => { it('input object with fields', () => { - expectPassesRule( - UniqueInputFieldNames, - ` + expectValid(` { field(arg: { f: true }) } - `, - ); + `); }); it('same input object within two args', () => { - expectPassesRule( - UniqueInputFieldNames, - ` + expectValid(` { field(arg1: { f: true }, arg2: { f: true }) } - `, - ); + `); }); it('multiple input object fields', () => { - expectPassesRule( - UniqueInputFieldNames, - ` + expectValid(` { field(arg: { f1: "value", f2: "value", f3: "value" }) } - `, - ); + `); }); it('allows for nested input objects with similar fields', () => { - expectPassesRule( - UniqueInputFieldNames, - ` + expectValid(` { field(arg: { deep: { @@ -70,31 +67,25 @@ describe('Validate: Unique input field names', () => { id: 1 }) } - `, - ); + `); }); it('duplicate input object fields', () => { - expectFailsRule( - UniqueInputFieldNames, - ` + expectErrors(` { field(arg: { f1: "value", f1: "value" }) } - `, - [duplicateField('f1', 3, 22, 3, 35)], - ); + `).to.deep.equal([duplicateField('f1', 3, 22, 3, 35)]); }); it('many duplicate input object fields', () => { - expectFailsRule( - UniqueInputFieldNames, - ` + expectErrors(` { field(arg: { f1: "value", f1: "value", f1: "value" }) } - `, - [duplicateField('f1', 3, 22, 3, 35), duplicateField('f1', 3, 22, 3, 48)], - ); + `).to.deep.equal([ + duplicateField('f1', 3, 22, 3, 35), + duplicateField('f1', 3, 22, 3, 48), + ]); }); }); diff --git a/src/validation/__tests__/UniqueOperationNames-test.js b/src/validation/__tests__/UniqueOperationNames-test.js index a5222bed9b..288499613a 100644 --- a/src/validation/__tests__/UniqueOperationNames-test.js +++ b/src/validation/__tests__/UniqueOperationNames-test.js @@ -8,12 +8,20 @@ */ import { describe, it } from 'mocha'; -import { expectPassesRule, expectFailsRule } from './harness'; +import { expectValidationErrors } from './harness'; import { UniqueOperationNames, duplicateOperationNameMessage, } from '../rules/UniqueOperationNames'; +function expectErrors(queryStr) { + return expectValidationErrors(UniqueOperationNames, queryStr); +} + +function expectValid(queryStr) { + expectErrors(queryStr).to.deep.equal([]); +} + function duplicateOp(opName, l1, c1, l2, c2) { return { message: duplicateOperationNameMessage(opName), @@ -23,42 +31,31 @@ function duplicateOp(opName, l1, c1, l2, c2) { describe('Validate: Unique operation names', () => { it('no operations', () => { - expectPassesRule( - UniqueOperationNames, - ` + expectValid(` fragment fragA on Type { field } - `, - ); + `); }); it('one anon operation', () => { - expectPassesRule( - UniqueOperationNames, - ` + expectValid(` { field } - `, - ); + `); }); it('one named operation', () => { - expectPassesRule( - UniqueOperationNames, - ` + expectValid(` query Foo { field } - `, - ); + `); }); it('multiple operations', () => { - expectPassesRule( - UniqueOperationNames, - ` + expectValid(` query Foo { field } @@ -66,14 +63,11 @@ describe('Validate: Unique operation names', () => { query Bar { field } - `, - ); + `); }); it('multiple operations of different types', () => { - expectPassesRule( - UniqueOperationNames, - ` + expectValid(` query Foo { field } @@ -85,66 +79,50 @@ describe('Validate: Unique operation names', () => { subscription Baz { field } - `, - ); + `); }); it('fragment and operation named the same', () => { - expectPassesRule( - UniqueOperationNames, - ` + expectValid(` query Foo { ...Foo } fragment Foo on Type { field } - `, - ); + `); }); it('multiple operations of same name', () => { - expectFailsRule( - UniqueOperationNames, - ` + expectErrors(` query Foo { fieldA } query Foo { fieldB } - `, - [duplicateOp('Foo', 2, 13, 5, 13)], - ); + `).to.deep.equal([duplicateOp('Foo', 2, 13, 5, 13)]); }); it('multiple ops of same name of different types (mutation)', () => { - expectFailsRule( - UniqueOperationNames, - ` + expectErrors(` query Foo { fieldA } mutation Foo { fieldB } - `, - [duplicateOp('Foo', 2, 13, 5, 16)], - ); + `).to.deep.equal([duplicateOp('Foo', 2, 13, 5, 16)]); }); it('multiple ops of same name of different types (subscription)', () => { - expectFailsRule( - UniqueOperationNames, - ` + expectErrors(` query Foo { fieldA } subscription Foo { fieldB } - `, - [duplicateOp('Foo', 2, 13, 5, 20)], - ); + `).to.deep.equal([duplicateOp('Foo', 2, 13, 5, 20)]); }); }); diff --git a/src/validation/__tests__/UniqueVariableNames-test.js b/src/validation/__tests__/UniqueVariableNames-test.js index 7b8c763c34..22835360de 100644 --- a/src/validation/__tests__/UniqueVariableNames-test.js +++ b/src/validation/__tests__/UniqueVariableNames-test.js @@ -8,12 +8,20 @@ */ import { describe, it } from 'mocha'; -import { expectPassesRule, expectFailsRule } from './harness'; +import { expectValidationErrors } from './harness'; import { UniqueVariableNames, duplicateVariableMessage, } from '../rules/UniqueVariableNames'; +function expectErrors(queryStr) { + return expectValidationErrors(UniqueVariableNames, queryStr); +} + +function expectValid(queryStr) { + expectErrors(queryStr).to.deep.equal([]); +} + function duplicateVariable(name, l1, c1, l2, c2) { return { message: duplicateVariableMessage(name), @@ -23,29 +31,22 @@ function duplicateVariable(name, l1, c1, l2, c2) { describe('Validate: Unique variable names', () => { it('unique variable names', () => { - expectPassesRule( - UniqueVariableNames, - ` + expectValid(` query A($x: Int, $y: String) { __typename } query B($x: String, $y: Int) { __typename } - `, - ); + `); }); it('duplicate variable names', () => { - expectFailsRule( - UniqueVariableNames, - ` + expectErrors(` query A($x: Int, $x: Int, $x: String) { __typename } query B($x: String, $x: Int) { __typename } query C($x: Int, $x: Int) { __typename } - `, - [ - duplicateVariable('x', 2, 16, 2, 25), - duplicateVariable('x', 2, 16, 2, 34), - duplicateVariable('x', 3, 16, 3, 28), - duplicateVariable('x', 4, 16, 4, 25), - ], - ); + `).to.deep.equal([ + duplicateVariable('x', 2, 16, 2, 25), + duplicateVariable('x', 2, 16, 2, 34), + duplicateVariable('x', 3, 16, 3, 28), + duplicateVariable('x', 4, 16, 4, 25), + ]); }); }); diff --git a/src/validation/__tests__/ValuesOfCorrectType-test.js b/src/validation/__tests__/ValuesOfCorrectType-test.js index 1c82636dc6..4b1afcb74f 100644 --- a/src/validation/__tests__/ValuesOfCorrectType-test.js +++ b/src/validation/__tests__/ValuesOfCorrectType-test.js @@ -4,12 +4,11 @@ * 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 { describe, it } from 'mocha'; -import { expect } from 'chai'; -import { expectPassesRule, expectFailsRule } from './harness'; +import { expectValidationErrors } from './harness'; import { ValuesOfCorrectType, badValueMessage, @@ -17,6 +16,14 @@ import { unknownFieldMessage, } from '../rules/ValuesOfCorrectType'; +function expectErrors(queryStr) { + return expectValidationErrors(ValuesOfCorrectType, queryStr); +} + +function expectValid(queryStr) { + expectErrors(queryStr).to.deep.equal([]); +} + function badValue(typeName, value, line, column, message) { return { message: badValueMessage(typeName, value, message), @@ -41,881 +48,666 @@ function unknownField(typeName, fieldName, line, column, message) { describe('Validate: Values of correct type', () => { describe('Valid values', () => { it('Good int value', () => { - expectPassesRule( - ValuesOfCorrectType, - ` + expectValid(` { complicatedArgs { intArgField(intArg: 2) } } - `, - ); + `); }); it('Good negative int value', () => { - expectPassesRule( - ValuesOfCorrectType, - ` + expectValid(` { complicatedArgs { intArgField(intArg: -2) } } - `, - ); + `); }); it('Good boolean value', () => { - expectPassesRule( - ValuesOfCorrectType, - ` + expectValid(` { complicatedArgs { booleanArgField(booleanArg: true) } } - `, - ); + `); }); it('Good string value', () => { - expectPassesRule( - ValuesOfCorrectType, - ` + expectValid(` { complicatedArgs { stringArgField(stringArg: "foo") } } - `, - ); + `); }); it('Good float value', () => { - expectPassesRule( - ValuesOfCorrectType, - ` + expectValid(` { complicatedArgs { floatArgField(floatArg: 1.1) } } - `, - ); + `); }); it('Good negative float value', () => { - expectPassesRule( - ValuesOfCorrectType, - ` + expectValid(` { complicatedArgs { floatArgField(floatArg: -1.1) } } - `, - ); + `); }); it('Int into Float', () => { - expectPassesRule( - ValuesOfCorrectType, - ` + expectValid(` { complicatedArgs { floatArgField(floatArg: 1) } } - `, - ); + `); }); it('Int into ID', () => { - expectPassesRule( - ValuesOfCorrectType, - ` + expectValid(` { complicatedArgs { idArgField(idArg: 1) } } - `, - ); + `); }); it('String into ID', () => { - expectPassesRule( - ValuesOfCorrectType, - ` + expectValid(` { complicatedArgs { idArgField(idArg: "someIdString") } } - `, - ); + `); }); it('Good enum value', () => { - expectPassesRule( - ValuesOfCorrectType, - ` + expectValid(` { dog { doesKnowCommand(dogCommand: SIT) } } - `, - ); + `); }); it('Enum with undefined value', () => { - expectPassesRule( - ValuesOfCorrectType, - ` + expectValid(` { complicatedArgs { enumArgField(enumArg: UNKNOWN) } } - `, - ); + `); }); it('Enum with null value', () => { - expectPassesRule( - ValuesOfCorrectType, - ` + expectValid(` { complicatedArgs { enumArgField(enumArg: NO_FUR) } } - `, - ); + `); }); it('null into nullable type', () => { - expectPassesRule( - ValuesOfCorrectType, - ` + expectValid(` { complicatedArgs { intArgField(intArg: null) } } - `, - ); + `); - expectPassesRule( - ValuesOfCorrectType, - ` + expectValid(` { dog(a: null, b: null, c:{ requiredField: true, intField: null }) { name } } - `, - ); + `); }); }); describe('Invalid String values', () => { it('Int into String', () => { - expectFailsRule( - ValuesOfCorrectType, - ` + expectErrors(` { complicatedArgs { stringArgField(stringArg: 1) } } - `, - [badValue('String', '1', 4, 39)], - ); + `).to.deep.equal([badValue('String', '1', 4, 39)]); }); it('Float into String', () => { - expectFailsRule( - ValuesOfCorrectType, - ` + expectErrors(` { complicatedArgs { stringArgField(stringArg: 1.0) } } - `, - [badValue('String', '1.0', 4, 39)], - ); + `).to.deep.equal([badValue('String', '1.0', 4, 39)]); }); it('Boolean into String', () => { - expectFailsRule( - ValuesOfCorrectType, - ` + expectErrors(` { complicatedArgs { stringArgField(stringArg: true) } } - `, - [badValue('String', 'true', 4, 39)], - ); + `).to.deep.equal([badValue('String', 'true', 4, 39)]); }); it('Unquoted String into String', () => { - expectFailsRule( - ValuesOfCorrectType, - ` + expectErrors(` { complicatedArgs { stringArgField(stringArg: BAR) } } - `, - [badValue('String', 'BAR', 4, 39)], - ); + `).to.deep.equal([badValue('String', 'BAR', 4, 39)]); }); }); describe('Invalid Int values', () => { it('String into Int', () => { - expectFailsRule( - ValuesOfCorrectType, - ` + expectErrors(` { complicatedArgs { intArgField(intArg: "3") } } - `, - [badValue('Int', '"3"', 4, 33)], - ); + `).to.deep.equal([badValue('Int', '"3"', 4, 33)]); }); it('Big Int into Int', () => { - expectFailsRule( - ValuesOfCorrectType, - ` + expectErrors(` { complicatedArgs { intArgField(intArg: 829384293849283498239482938) } } - `, - [badValue('Int', '829384293849283498239482938', 4, 33)], - ); + `).to.deep.equal([badValue('Int', '829384293849283498239482938', 4, 33)]); }); it('Unquoted String into Int', () => { - expectFailsRule( - ValuesOfCorrectType, - ` + expectErrors(` { complicatedArgs { intArgField(intArg: FOO) } } - `, - [badValue('Int', 'FOO', 4, 33)], - ); + `).to.deep.equal([badValue('Int', 'FOO', 4, 33)]); }); it('Simple Float into Int', () => { - expectFailsRule( - ValuesOfCorrectType, - ` + expectErrors(` { complicatedArgs { intArgField(intArg: 3.0) } } - `, - [badValue('Int', '3.0', 4, 33)], - ); + `).to.deep.equal([badValue('Int', '3.0', 4, 33)]); }); it('Float into Int', () => { - expectFailsRule( - ValuesOfCorrectType, - ` + expectErrors(` { complicatedArgs { intArgField(intArg: 3.333) } } - `, - [badValue('Int', '3.333', 4, 33)], - ); + `).to.deep.equal([badValue('Int', '3.333', 4, 33)]); }); }); describe('Invalid Float values', () => { it('String into Float', () => { - expectFailsRule( - ValuesOfCorrectType, - ` + expectErrors(` { complicatedArgs { floatArgField(floatArg: "3.333") } } - `, - [badValue('Float', '"3.333"', 4, 37)], - ); + `).to.deep.equal([badValue('Float', '"3.333"', 4, 37)]); }); it('Boolean into Float', () => { - expectFailsRule( - ValuesOfCorrectType, - ` + expectErrors(` { complicatedArgs { floatArgField(floatArg: true) } } - `, - [badValue('Float', 'true', 4, 37)], - ); + `).to.deep.equal([badValue('Float', 'true', 4, 37)]); }); it('Unquoted into Float', () => { - expectFailsRule( - ValuesOfCorrectType, - ` + expectErrors(` { complicatedArgs { floatArgField(floatArg: FOO) } } - `, - [badValue('Float', 'FOO', 4, 37)], - ); + `).to.deep.equal([badValue('Float', 'FOO', 4, 37)]); }); }); describe('Invalid Boolean value', () => { it('Int into Boolean', () => { - expectFailsRule( - ValuesOfCorrectType, - ` + expectErrors(` { complicatedArgs { booleanArgField(booleanArg: 2) } } - `, - [badValue('Boolean', '2', 4, 41)], - ); + `).to.deep.equal([badValue('Boolean', '2', 4, 41)]); }); it('Float into Boolean', () => { - expectFailsRule( - ValuesOfCorrectType, - ` + expectErrors(` { complicatedArgs { booleanArgField(booleanArg: 1.0) } } - `, - [badValue('Boolean', '1.0', 4, 41)], - ); + `).to.deep.equal([badValue('Boolean', '1.0', 4, 41)]); }); it('String into Boolean', () => { - expectFailsRule( - ValuesOfCorrectType, - ` + expectErrors(` { complicatedArgs { booleanArgField(booleanArg: "true") } } - `, - [badValue('Boolean', '"true"', 4, 41)], - ); + `).to.deep.equal([badValue('Boolean', '"true"', 4, 41)]); }); it('Unquoted into Boolean', () => { - expectFailsRule( - ValuesOfCorrectType, - ` + expectErrors(` { complicatedArgs { booleanArgField(booleanArg: TRUE) } } - `, - [badValue('Boolean', 'TRUE', 4, 41)], - ); + `).to.deep.equal([badValue('Boolean', 'TRUE', 4, 41)]); }); }); describe('Invalid ID value', () => { it('Float into ID', () => { - expectFailsRule( - ValuesOfCorrectType, - ` + expectErrors(` { complicatedArgs { idArgField(idArg: 1.0) } } - `, - [badValue('ID', '1.0', 4, 31)], - ); + `).to.deep.equal([badValue('ID', '1.0', 4, 31)]); }); it('Boolean into ID', () => { - expectFailsRule( - ValuesOfCorrectType, - ` + expectErrors(` { complicatedArgs { idArgField(idArg: true) } } - `, - [badValue('ID', 'true', 4, 31)], - ); + `).to.deep.equal([badValue('ID', 'true', 4, 31)]); }); it('Unquoted into ID', () => { - expectFailsRule( - ValuesOfCorrectType, - ` + expectErrors(` { complicatedArgs { idArgField(idArg: SOMETHING) } } - `, - [badValue('ID', 'SOMETHING', 4, 31)], - ); + `).to.deep.equal([badValue('ID', 'SOMETHING', 4, 31)]); }); }); describe('Invalid Enum value', () => { it('Int into Enum', () => { - expectFailsRule( - ValuesOfCorrectType, - ` + expectErrors(` { dog { doesKnowCommand(dogCommand: 2) } } - `, - [badValue('DogCommand', '2', 4, 41)], - ); + `).to.deep.equal([badValue('DogCommand', '2', 4, 41)]); }); it('Float into Enum', () => { - expectFailsRule( - ValuesOfCorrectType, - ` + expectErrors(` { dog { doesKnowCommand(dogCommand: 1.0) } } - `, - [badValue('DogCommand', '1.0', 4, 41)], - ); + `).to.deep.equal([badValue('DogCommand', '1.0', 4, 41)]); }); it('String into Enum', () => { - expectFailsRule( - ValuesOfCorrectType, - ` + expectErrors(` { dog { doesKnowCommand(dogCommand: "SIT") } } - `, - [ - badValue( - 'DogCommand', - '"SIT"', - 4, - 41, - 'Did you mean the enum value SIT?', - ), - ], - ); + `).to.deep.equal([ + badValue( + 'DogCommand', + '"SIT"', + 4, + 41, + 'Did you mean the enum value SIT?', + ), + ]); }); it('Boolean into Enum', () => { - expectFailsRule( - ValuesOfCorrectType, - ` + expectErrors(` { dog { doesKnowCommand(dogCommand: true) } } - `, - [badValue('DogCommand', 'true', 4, 41)], - ); + `).to.deep.equal([badValue('DogCommand', 'true', 4, 41)]); }); it('Unknown Enum Value into Enum', () => { - expectFailsRule( - ValuesOfCorrectType, - ` + expectErrors(` { dog { doesKnowCommand(dogCommand: JUGGLE) } } - `, - [badValue('DogCommand', 'JUGGLE', 4, 41)], - ); + `).to.deep.equal([badValue('DogCommand', 'JUGGLE', 4, 41)]); }); it('Different case Enum Value into Enum', () => { - expectFailsRule( - ValuesOfCorrectType, - ` + expectErrors(` { dog { doesKnowCommand(dogCommand: sit) } } - `, - [ - badValue( - 'DogCommand', - 'sit', - 4, - 41, - 'Did you mean the enum value SIT?', - ), - ], - ); + `).to.deep.equal([ + badValue( + 'DogCommand', + 'sit', + 4, + 41, + 'Did you mean the enum value SIT?', + ), + ]); }); }); describe('Valid List value', () => { it('Good list value', () => { - expectPassesRule( - ValuesOfCorrectType, - ` + expectValid(` { complicatedArgs { stringListArgField(stringListArg: ["one", null, "two"]) } } - `, - ); + `); }); it('Empty list value', () => { - expectPassesRule( - ValuesOfCorrectType, - ` + expectValid(` { complicatedArgs { stringListArgField(stringListArg: []) } } - `, - ); + `); }); it('Null value', () => { - expectPassesRule( - ValuesOfCorrectType, - ` + expectValid(` { complicatedArgs { stringListArgField(stringListArg: null) } } - `, - ); + `); }); it('Single value into List', () => { - expectPassesRule( - ValuesOfCorrectType, - ` + expectValid(` { complicatedArgs { stringListArgField(stringListArg: "one") } } - `, - ); + `); }); }); describe('Invalid List value', () => { it('Incorrect item type', () => { - expectFailsRule( - ValuesOfCorrectType, - ` + expectErrors(` { complicatedArgs { stringListArgField(stringListArg: ["one", 2]) } } - `, - [badValue('String', '2', 4, 55)], - ); + `).to.deep.equal([badValue('String', '2', 4, 55)]); }); it('Single value of incorrect type', () => { - expectFailsRule( - ValuesOfCorrectType, - ` + expectErrors(` { complicatedArgs { stringListArgField(stringListArg: 1) } } - `, - [badValue('[String]', '1', 4, 47)], - ); + `).to.deep.equal([badValue('[String]', '1', 4, 47)]); }); }); describe('Valid non-nullable value', () => { it('Arg on optional arg', () => { - expectPassesRule( - ValuesOfCorrectType, - ` + expectValid(` { dog { isHousetrained(atOtherHomes: true) } } - `, - ); + `); }); it('No Arg on optional arg', () => { - expectPassesRule( - ValuesOfCorrectType, - ` + expectValid(` { dog { isHousetrained } } - `, - ); + `); }); it('Multiple args', () => { - expectPassesRule( - ValuesOfCorrectType, - ` + expectValid(` { complicatedArgs { multipleReqs(req1: 1, req2: 2) } } - `, - ); + `); }); it('Multiple args reverse order', () => { - expectPassesRule( - ValuesOfCorrectType, - ` + expectValid(` { complicatedArgs { multipleReqs(req2: 2, req1: 1) } } - `, - ); + `); }); it('No args on multiple optional', () => { - expectPassesRule( - ValuesOfCorrectType, - ` + expectValid(` { complicatedArgs { multipleOpts } } - `, - ); + `); }); it('One arg on multiple optional', () => { - expectPassesRule( - ValuesOfCorrectType, - ` + expectValid(` { complicatedArgs { multipleOpts(opt1: 1) } } - `, - ); + `); }); it('Second arg on multiple optional', () => { - expectPassesRule( - ValuesOfCorrectType, - ` + expectValid(` { complicatedArgs { multipleOpts(opt2: 1) } } - `, - ); + `); }); it('Multiple reqs on mixedList', () => { - expectPassesRule( - ValuesOfCorrectType, - ` + expectValid(` { complicatedArgs { multipleOptAndReq(req1: 3, req2: 4) } } - `, - ); + `); }); it('Multiple reqs and one opt on mixedList', () => { - expectPassesRule( - ValuesOfCorrectType, - ` + expectValid(` { complicatedArgs { multipleOptAndReq(req1: 3, req2: 4, opt1: 5) } } - `, - ); + `); }); it('All reqs and opts on mixedList', () => { - expectPassesRule( - ValuesOfCorrectType, - ` + expectValid(` { complicatedArgs { multipleOptAndReq(req1: 3, req2: 4, opt1: 5, opt2: 6) } } - `, - ); + `); }); }); describe('Invalid non-nullable value', () => { it('Incorrect value type', () => { - expectFailsRule( - ValuesOfCorrectType, - ` + expectErrors(` { complicatedArgs { multipleReqs(req2: "two", req1: "one") } } - `, - [badValue('Int!', '"two"', 4, 32), badValue('Int!', '"one"', 4, 45)], - ); + `).to.deep.equal([ + badValue('Int!', '"two"', 4, 32), + badValue('Int!', '"one"', 4, 45), + ]); }); it('Incorrect value and missing argument (ProvidedRequiredArguments)', () => { - expectFailsRule( - ValuesOfCorrectType, - ` + expectErrors(` { complicatedArgs { multipleReqs(req1: "one") } } - `, - [badValue('Int!', '"one"', 4, 32)], - ); + `).to.deep.equal([badValue('Int!', '"one"', 4, 32)]); }); it('Null value', () => { - expectFailsRule( - ValuesOfCorrectType, - ` + expectErrors(` { complicatedArgs { multipleReqs(req1: null) } } - `, - [badValue('Int!', 'null', 4, 32)], - ); + `).to.deep.equal([badValue('Int!', 'null', 4, 32)]); }); }); describe('Valid input object value', () => { it('Optional arg, despite required field in type', () => { - expectPassesRule( - ValuesOfCorrectType, - ` + expectValid(` { complicatedArgs { complexArgField } } - `, - ); + `); }); it('Partial object, only required', () => { - expectPassesRule( - ValuesOfCorrectType, - ` + expectValid(` { complicatedArgs { complexArgField(complexArg: { requiredField: true }) } } - `, - ); + `); }); it('Partial object, required field can be falsey', () => { - expectPassesRule( - ValuesOfCorrectType, - ` + expectValid(` { complicatedArgs { complexArgField(complexArg: { requiredField: false }) } } - `, - ); + `); }); it('Partial object, including required', () => { - expectPassesRule( - ValuesOfCorrectType, - ` + expectValid(` { complicatedArgs { complexArgField(complexArg: { requiredField: true, intField: 4 }) } } - `, - ); + `); }); it('Full object', () => { - expectPassesRule( - ValuesOfCorrectType, - ` + expectValid(` { complicatedArgs { complexArgField(complexArg: { @@ -927,14 +719,11 @@ describe('Validate: Values of correct type', () => { }) } } - `, - ); + `); }); it('Full object with fields in different order', () => { - expectPassesRule( - ValuesOfCorrectType, - ` + expectValid(` { complicatedArgs { complexArgField(complexArg: { @@ -946,30 +735,25 @@ describe('Validate: Values of correct type', () => { }) } } - `, - ); + `); }); }); describe('Invalid input object value', () => { it('Partial object, missing required', () => { - expectFailsRule( - ValuesOfCorrectType, - ` + expectErrors(` { complicatedArgs { complexArgField(complexArg: { intField: 4 }) } } - `, - [requiredField('ComplexInput', 'requiredField', 'Boolean!', 4, 41)], - ); + `).to.deep.equal([ + requiredField('ComplexInput', 'requiredField', 'Boolean!', 4, 41), + ]); }); it('Partial object, invalid field type', () => { - expectFailsRule( - ValuesOfCorrectType, - ` + expectErrors(` { complicatedArgs { complexArgField(complexArg: { @@ -978,15 +762,11 @@ describe('Validate: Values of correct type', () => { }) } } - `, - [badValue('String', '2', 5, 40)], - ); + `).to.deep.equal([badValue('String', '2', 5, 40)]); }); it('Partial object, null to non-null field', () => { - expectFailsRule( - ValuesOfCorrectType, - ` + expectErrors(` { complicatedArgs { complexArgField(complexArg: { @@ -995,15 +775,11 @@ describe('Validate: Values of correct type', () => { }) } } - `, - [badValue('Boolean!', 'null', 6, 29)], - ); + `).to.deep.equal([badValue('Boolean!', 'null', 6, 29)]); }); it('Partial object, unknown field arg', () => { - expectFailsRule( - ValuesOfCorrectType, - ` + expectErrors(` { complicatedArgs { complexArgField(complexArg: { @@ -1012,62 +788,55 @@ describe('Validate: Values of correct type', () => { }) } } - `, - [ - unknownField( - 'ComplexInput', - 'unknownField', - 6, - 15, - 'Did you mean nonNullField, intField, or booleanField?', - ), - ], - ); + `).to.deep.equal([ + unknownField( + 'ComplexInput', + 'unknownField', + 6, + 15, + 'Did you mean nonNullField, intField, or booleanField?', + ), + ]); }); it('reports original error for custom scalar which throws', () => { - const errors = expectFailsRule( - ValuesOfCorrectType, - ` + const expectedErrors = expectErrors(` { invalidArg(arg: 123) } - `, - [ - badValue( - 'Invalid', - '123', - 3, - 27, - 'Invalid scalar is always invalid: 123', - ), - ], - ); - expect(errors[0].originalError.message).to.equal( + `); + + expectedErrors.to.deep.equal([ + badValue( + 'Invalid', + '123', + 3, + 27, + 'Invalid scalar is always invalid: 123', + ), + ]); + + expectedErrors.to.have.nested.property( + '[0].originalError.message', 'Invalid scalar is always invalid: 123', ); }); it('allows custom scalar to accept complex literals', () => { - expectPassesRule( - ValuesOfCorrectType, - ` + expectValid(` { test1: anyArg(arg: 123) test2: anyArg(arg: "abc") test3: anyArg(arg: [123, "abc"]) test4: anyArg(arg: {deep: [123, "abc"]}) } - `, - ); + `); }); }); describe('Directive arguments', () => { it('with directives of valid types', () => { - expectPassesRule( - ValuesOfCorrectType, - ` + expectValid(` { dog @include(if: true) { name @@ -1076,33 +845,26 @@ describe('Validate: Values of correct type', () => { name } } - `, - ); + `); }); it('with directive with incorrect types', () => { - expectFailsRule( - ValuesOfCorrectType, - ` + expectErrors(` { dog @include(if: "yes") { name @skip(if: ENUM) } } - `, - [ - badValue('Boolean!', '"yes"', 3, 28), - badValue('Boolean!', 'ENUM', 4, 28), - ], - ); + `).to.deep.equal([ + badValue('Boolean!', '"yes"', 3, 28), + badValue('Boolean!', 'ENUM', 4, 28), + ]); }); }); describe('Variable default values', () => { it('variables with valid default values', () => { - expectPassesRule( - ValuesOfCorrectType, - ` + expectValid(` query WithDefaultValues( $a: Int = 1, $b: String = "ok", @@ -1111,14 +873,11 @@ describe('Validate: Values of correct type', () => { ) { dog { name } } - `, - ); + `); }); it('variables with valid default null values', () => { - expectPassesRule( - ValuesOfCorrectType, - ` + expectValid(` query WithDefaultValues( $a: Int = null, $b: String = null, @@ -1126,14 +885,11 @@ describe('Validate: Values of correct type', () => { ) { dog { name } } - `, - ); + `); }); it('variables with invalid default null values', () => { - expectFailsRule( - ValuesOfCorrectType, - ` + expectErrors(` query WithDefaultValues( $a: Int! = null, $b: String! = null, @@ -1141,19 +897,15 @@ describe('Validate: Values of correct type', () => { ) { dog { name } } - `, - [ - badValue('Int!', 'null', 3, 22), - badValue('String!', 'null', 4, 25), - badValue('Boolean!', 'null', 5, 47), - ], - ); + `).to.deep.equal([ + badValue('Int!', 'null', 3, 22), + badValue('String!', 'null', 4, 25), + badValue('Boolean!', 'null', 5, 47), + ]); }); it('variables with invalid default values', () => { - expectFailsRule( - ValuesOfCorrectType, - ` + expectErrors(` query InvalidDefaultValues( $a: Int = "one", $b: String = 4, @@ -1161,51 +913,42 @@ describe('Validate: Values of correct type', () => { ) { dog { name } } - `, - [ - badValue('Int', '"one"', 3, 21), - badValue('String', '4', 4, 24), - badValue('ComplexInput', '"notverycomplex"', 5, 30), - ], - ); + `).to.deep.equal([ + badValue('Int', '"one"', 3, 21), + badValue('String', '4', 4, 24), + badValue('ComplexInput', '"notverycomplex"', 5, 30), + ]); }); it('variables with complex invalid default values', () => { - expectFailsRule( - ValuesOfCorrectType, - ` + expectErrors(` query WithDefaultValues( $a: ComplexInput = { requiredField: 123, intField: "abc" } ) { dog { name } } - `, - [badValue('Boolean!', '123', 3, 47), badValue('Int', '"abc"', 3, 62)], - ); + `).to.deep.equal([ + badValue('Boolean!', '123', 3, 47), + badValue('Int', '"abc"', 3, 62), + ]); }); it('complex variables missing required field', () => { - expectFailsRule( - ValuesOfCorrectType, - ` + expectErrors(` query MissingRequiredField($a: ComplexInput = {intField: 3}) { dog { name } } - `, - [requiredField('ComplexInput', 'requiredField', 'Boolean!', 2, 55)], - ); + `).to.deep.equal([ + requiredField('ComplexInput', 'requiredField', 'Boolean!', 2, 55), + ]); }); it('list variables with invalid item', () => { - expectFailsRule( - ValuesOfCorrectType, - ` + expectErrors(` query InvalidItem($a: [String] = ["one", 2]) { dog { name } } - `, - [badValue('String', '2', 2, 50)], - ); + `).to.deep.equal([badValue('String', '2', 2, 50)]); }); }); }); diff --git a/src/validation/__tests__/VariablesAreInputTypes-test.js b/src/validation/__tests__/VariablesAreInputTypes-test.js index 4235caf377..96e650ea64 100644 --- a/src/validation/__tests__/VariablesAreInputTypes-test.js +++ b/src/validation/__tests__/VariablesAreInputTypes-test.js @@ -8,46 +8,47 @@ */ import { describe, it } from 'mocha'; -import { expectPassesRule, expectFailsRule } from './harness'; +import { expectValidationErrors } from './harness'; import { VariablesAreInputTypes, nonInputTypeOnVarMessage, } from '../rules/VariablesAreInputTypes'; +function expectErrors(queryStr) { + return expectValidationErrors(VariablesAreInputTypes, queryStr); +} + +function expectValid(queryStr) { + expectErrors(queryStr).to.deep.equal([]); +} + describe('Validate: Variables are input types', () => { it('input types are valid', () => { - expectPassesRule( - VariablesAreInputTypes, - ` + expectValid(` query Foo($a: String, $b: [Boolean!]!, $c: ComplexInput) { field(a: $a, b: $b, c: $c) } - `, - ); + `); }); it('output types are invalid', () => { - expectFailsRule( - VariablesAreInputTypes, - ` + expectErrors(` query Foo($a: Dog, $b: [[CatOrDog!]]!, $c: Pet) { field(a: $a, b: $b, c: $c) } - `, - [ - { - locations: [{ line: 2, column: 21 }], - message: nonInputTypeOnVarMessage('a', 'Dog'), - }, - { - locations: [{ line: 2, column: 30 }], - message: nonInputTypeOnVarMessage('b', '[[CatOrDog!]]!'), - }, - { - locations: [{ line: 2, column: 50 }], - message: nonInputTypeOnVarMessage('c', 'Pet'), - }, - ], - ); + `).to.deep.equal([ + { + locations: [{ line: 2, column: 21 }], + message: nonInputTypeOnVarMessage('a', 'Dog'), + }, + { + locations: [{ line: 2, column: 30 }], + message: nonInputTypeOnVarMessage('b', '[[CatOrDog!]]!'), + }, + { + locations: [{ line: 2, column: 50 }], + message: nonInputTypeOnVarMessage('c', 'Pet'), + }, + ]); }); }); diff --git a/src/validation/__tests__/VariablesInAllowedPosition-test.js b/src/validation/__tests__/VariablesInAllowedPosition-test.js index a7ef69fedc..4eeb07d0e1 100644 --- a/src/validation/__tests__/VariablesInAllowedPosition-test.js +++ b/src/validation/__tests__/VariablesInAllowedPosition-test.js @@ -8,31 +8,34 @@ */ import { describe, it } from 'mocha'; -import { expectPassesRule, expectFailsRule } from './harness'; +import { expectValidationErrors } from './harness'; import { VariablesInAllowedPosition, badVarPosMessage, } from '../rules/VariablesInAllowedPosition'; +function expectErrors(queryStr) { + return expectValidationErrors(VariablesInAllowedPosition, queryStr); +} + +function expectValid(queryStr) { + expectErrors(queryStr).to.deep.equal([]); +} + describe('Validate: Variables are in allowed positions', () => { it('Boolean => Boolean', () => { - expectPassesRule( - VariablesInAllowedPosition, - ` + expectValid(` query Query($booleanArg: Boolean) { complicatedArgs { booleanArgField(booleanArg: $booleanArg) } } - `, - ); + `); }); it('Boolean => Boolean within fragment', () => { - expectPassesRule( - VariablesInAllowedPosition, - ` + expectValid(` fragment booleanArgFrag on ComplicatedArgs { booleanArgField(booleanArg: $booleanArg) } @@ -42,12 +45,9 @@ describe('Validate: Variables are in allowed positions', () => { ...booleanArgFrag } } - `, - ); + `); - expectPassesRule( - VariablesInAllowedPosition, - ` + expectValid(` query Query($booleanArg: Boolean) { complicatedArgs { @@ -57,28 +57,22 @@ describe('Validate: Variables are in allowed positions', () => { fragment booleanArgFrag on ComplicatedArgs { booleanArgField(booleanArg: $booleanArg) } - `, - ); + `); }); it('Boolean! => Boolean', () => { - expectPassesRule( - VariablesInAllowedPosition, - ` + expectValid(` query Query($nonNullBooleanArg: Boolean!) { complicatedArgs { booleanArgField(booleanArg: $nonNullBooleanArg) } } - `, - ); + `); }); it('Boolean! => Boolean within fragment', () => { - expectPassesRule( - VariablesInAllowedPosition, - ` + expectValid(` fragment booleanArgFrag on ComplicatedArgs { booleanArgField(booleanArg: $nonNullBooleanArg) } @@ -89,129 +83,101 @@ describe('Validate: Variables are in allowed positions', () => { ...booleanArgFrag } } - `, - ); + `); }); it('[String] => [String]', () => { - expectPassesRule( - VariablesInAllowedPosition, - ` + expectValid(` query Query($stringListVar: [String]) { complicatedArgs { stringListArgField(stringListArg: $stringListVar) } } - `, - ); + `); }); it('[String!] => [String]', () => { - expectPassesRule( - VariablesInAllowedPosition, - ` + expectValid(` query Query($stringListVar: [String!]) { complicatedArgs { stringListArgField(stringListArg: $stringListVar) } } - `, - ); + `); }); it('String => [String] in item position', () => { - expectPassesRule( - VariablesInAllowedPosition, - ` + expectValid(` query Query($stringVar: String) { complicatedArgs { stringListArgField(stringListArg: [$stringVar]) } } - `, - ); + `); }); it('String! => [String] in item position', () => { - expectPassesRule( - VariablesInAllowedPosition, - ` + expectValid(` query Query($stringVar: String!) { complicatedArgs { stringListArgField(stringListArg: [$stringVar]) } } - `, - ); + `); }); it('ComplexInput => ComplexInput', () => { - expectPassesRule( - VariablesInAllowedPosition, - ` + expectValid(` query Query($complexVar: ComplexInput) { complicatedArgs { complexArgField(complexArg: $complexVar) } } - `, - ); + `); }); it('ComplexInput => ComplexInput in field position', () => { - expectPassesRule( - VariablesInAllowedPosition, - ` + expectValid(` query Query($boolVar: Boolean = false) { complicatedArgs { complexArgField(complexArg: {requiredArg: $boolVar}) } } - `, - ); + `); }); it('Boolean! => Boolean! in directive', () => { - expectPassesRule( - VariablesInAllowedPosition, - ` + expectValid(` query Query($boolVar: Boolean!) { dog @include(if: $boolVar) } - `, - ); + `); }); it('Int => Int!', () => { - expectFailsRule( - VariablesInAllowedPosition, - ` + expectErrors(` query Query($intArg: Int) { complicatedArgs { nonNullIntArgField(nonNullIntArg: $intArg) } } - `, - [ - { - message: badVarPosMessage('intArg', 'Int', 'Int!'), - locations: [{ line: 2, column: 19 }, { line: 4, column: 45 }], - }, - ], - ); + `).to.deep.equal([ + { + message: badVarPosMessage('intArg', 'Int', 'Int!'), + locations: [{ line: 2, column: 19 }, { line: 4, column: 45 }], + }, + ]); }); it('Int => Int! within fragment', () => { - expectFailsRule( - VariablesInAllowedPosition, - ` + expectErrors(` fragment nonNullIntArgFieldFrag on ComplicatedArgs { nonNullIntArgField(nonNullIntArg: $intArg) } @@ -221,20 +187,16 @@ describe('Validate: Variables are in allowed positions', () => { ...nonNullIntArgFieldFrag } } - `, - [ - { - message: badVarPosMessage('intArg', 'Int', 'Int!'), - locations: [{ line: 6, column: 19 }, { line: 3, column: 43 }], - }, - ], - ); + `).to.deep.equal([ + { + message: badVarPosMessage('intArg', 'Int', 'Int!'), + locations: [{ line: 6, column: 19 }, { line: 3, column: 43 }], + }, + ]); }); it('Int => Int! within nested fragment', () => { - expectFailsRule( - VariablesInAllowedPosition, - ` + expectErrors(` fragment outerFrag on ComplicatedArgs { ...nonNullIntArgFieldFrag } @@ -248,159 +210,125 @@ describe('Validate: Variables are in allowed positions', () => { ...outerFrag } } - `, - [ - { - message: badVarPosMessage('intArg', 'Int', 'Int!'), - locations: [{ line: 10, column: 19 }, { line: 7, column: 43 }], - }, - ], - ); + `).to.deep.equal([ + { + message: badVarPosMessage('intArg', 'Int', 'Int!'), + locations: [{ line: 10, column: 19 }, { line: 7, column: 43 }], + }, + ]); }); it('String over Boolean', () => { - expectFailsRule( - VariablesInAllowedPosition, - ` + expectErrors(` query Query($stringVar: String) { complicatedArgs { booleanArgField(booleanArg: $stringVar) } } - `, - [ - { - message: badVarPosMessage('stringVar', 'String', 'Boolean'), - locations: [{ line: 2, column: 19 }, { line: 4, column: 39 }], - }, - ], - ); + `).to.deep.equal([ + { + message: badVarPosMessage('stringVar', 'String', 'Boolean'), + locations: [{ line: 2, column: 19 }, { line: 4, column: 39 }], + }, + ]); }); it('String => [String]', () => { - expectFailsRule( - VariablesInAllowedPosition, - ` + expectErrors(` query Query($stringVar: String) { complicatedArgs { stringListArgField(stringListArg: $stringVar) } } - `, - [ - { - message: badVarPosMessage('stringVar', 'String', '[String]'), - locations: [{ line: 2, column: 19 }, { line: 4, column: 45 }], - }, - ], - ); + `).to.deep.equal([ + { + message: badVarPosMessage('stringVar', 'String', '[String]'), + locations: [{ line: 2, column: 19 }, { line: 4, column: 45 }], + }, + ]); }); it('Boolean => Boolean! in directive', () => { - expectFailsRule( - VariablesInAllowedPosition, - ` + expectErrors(` query Query($boolVar: Boolean) { dog @include(if: $boolVar) } - `, - [ - { - message: badVarPosMessage('boolVar', 'Boolean', 'Boolean!'), - locations: [{ line: 2, column: 19 }, { line: 3, column: 26 }], - }, - ], - ); + `).to.deep.equal([ + { + message: badVarPosMessage('boolVar', 'Boolean', 'Boolean!'), + locations: [{ line: 2, column: 19 }, { line: 3, column: 26 }], + }, + ]); }); it('String => Boolean! in directive', () => { - expectFailsRule( - VariablesInAllowedPosition, - ` + expectErrors(` query Query($stringVar: String) { dog @include(if: $stringVar) } - `, - [ - { - message: badVarPosMessage('stringVar', 'String', 'Boolean!'), - locations: [{ line: 2, column: 19 }, { line: 3, column: 26 }], - }, - ], - ); + `).to.deep.equal([ + { + message: badVarPosMessage('stringVar', 'String', 'Boolean!'), + locations: [{ line: 2, column: 19 }, { line: 3, column: 26 }], + }, + ]); }); it('[String] => [String!]', () => { - expectFailsRule( - VariablesInAllowedPosition, - ` + expectErrors(` query Query($stringListVar: [String]) { complicatedArgs { stringListNonNullArgField(stringListNonNullArg: $stringListVar) } } - `, - [ - { - message: badVarPosMessage('stringListVar', '[String]', '[String!]'), - locations: [{ line: 2, column: 19 }, { line: 5, column: 59 }], - }, - ], - ); + `).to.deep.equal([ + { + message: badVarPosMessage('stringListVar', '[String]', '[String!]'), + locations: [{ line: 2, column: 19 }, { line: 5, column: 59 }], + }, + ]); }); describe('Allows optional (nullable) variables with default values', () => { it('Int => Int! fails when variable provides null default value', () => { - expectFailsRule( - VariablesInAllowedPosition, - ` + expectErrors(` query Query($intVar: Int = null) { complicatedArgs { nonNullIntArgField(nonNullIntArg: $intVar) } - }`, - [ - { - message: badVarPosMessage('intVar', 'Int', 'Int!'), - locations: [{ line: 2, column: 21 }, { line: 4, column: 47 }], - }, - ], - ); + } + `).to.deep.equal([ + { + message: badVarPosMessage('intVar', 'Int', 'Int!'), + locations: [{ line: 2, column: 21 }, { line: 4, column: 47 }], + }, + ]); }); it('Int => Int! when variable provides non-null default value', () => { - expectPassesRule( - VariablesInAllowedPosition, - ` + expectValid(` query Query($intVar: Int = 1) { complicatedArgs { nonNullIntArgField(nonNullIntArg: $intVar) } - }`, - ); + }`); }); it('Int => Int! when optional argument provides default value', () => { - expectPassesRule( - VariablesInAllowedPosition, - ` + expectValid(` query Query($intVar: Int) { complicatedArgs { nonNullFieldWithDefault(nonNullIntArg: $intVar) } - }`, - ); + }`); }); it('Boolean => Boolean! in directive with default value with option', () => { - expectPassesRule( - VariablesInAllowedPosition, - ` + expectValid(` query Query($boolVar: Boolean = false) { dog @include(if: $boolVar) - }`, - ); + }`); }); }); }); diff --git a/src/validation/__tests__/harness.js b/src/validation/__tests__/harness.js index 9f9211f18d..34f91c1ade 100644 --- a/src/validation/__tests__/harness.js +++ b/src/validation/__tests__/harness.js @@ -4,12 +4,14 @@ * 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 { parse } from '../../language'; +import inspect from '../../jsutils/inspect'; +import { parse, print } from '../../language'; import { validate, validateSDL } from '../validate'; +import type { ValidationRule, SDLValidationRule } from '../ValidationContext'; import { GraphQLSchema, GraphQLObjectType, @@ -291,11 +293,11 @@ const InvalidScalar = new GraphQLScalarType({ serialize(value) { return value; }, - parseLiteral(node) { - throw new Error('Invalid scalar is always invalid: ' + node.value); + parseLiteral(valueNode) { + throw new Error(`Invalid scalar is always invalid: ${print(valueNode)}`); }, - parseValue(node) { - throw new Error('Invalid scalar is always invalid: ' + node); + parseValue(value) { + throw new Error(`Invalid scalar is always invalid: ${inspect(value)}`); }, }); @@ -383,35 +385,26 @@ export const testSchema = new GraphQLSchema({ ], }); -function expectValid(schema, rule, queryString) { - const errors = validate(schema, parse(queryString), [rule]); - expect(errors).to.deep.equal([], 'Should validate'); -} - -function expectInvalid(schema, rule, queryString, expectedErrors) { - const errors = validate(schema, parse(queryString), [rule]); - expect(errors).to.have.length.of.at.least(1, 'Should not validate'); - expect(errors).to.deep.equal(expectedErrors); - return errors; -} - -export function expectPassesRule(rule, queryString) { - return expectValid(testSchema, rule, queryString); -} - -export function expectFailsRule(rule, queryString, errors) { - return expectInvalid(testSchema, rule, queryString, errors); -} - -export function expectPassesRuleWithSchema(schema, rule, queryString) { - return expectValid(schema, rule, queryString); +export function expectValidationErrorsWithSchema( + schema: GraphQLSchema, + rule: ValidationRule, + queryStr: string, +) { + const doc = parse(queryStr); + const errors = validate(schema, doc, [rule]); + return expect(errors); } -export function expectFailsRuleWithSchema(schema, rule, queryString, errors) { - return expectInvalid(schema, rule, queryString, errors); +export function expectValidationErrors(rule: ValidationRule, queryStr: string) { + return expectValidationErrorsWithSchema(testSchema, rule, queryStr); } -export function expectSDLErrorsFromRule(rule, sdlString, schema) { - const errors = validateSDL(parse(sdlString), schema, [rule]); +export function expectSDLValidationErrors( + schema: ?GraphQLSchema, + rule: SDLValidationRule, + sdlStr: string, +) { + const doc = parse(sdlStr); + const errors = validateSDL(doc, schema, [rule]); return expect(errors); } diff --git a/src/validation/__tests__/validation-test.js b/src/validation/__tests__/validation-test.js index 938f8b148c..fb3238d9fc 100644 --- a/src/validation/__tests__/validation-test.js +++ b/src/validation/__tests__/validation-test.js @@ -14,16 +14,9 @@ import { validate, specifiedRules } from '../'; import { parse } from '../../language'; import { TypeInfo } from '../../utilities/TypeInfo'; -function expectValid(schema, queryString) { - const errors = validate(schema, parse(queryString)); - expect(errors).to.deep.equal([], 'Should validate'); -} - describe('Validate: Supports full validation', () => { it('validates queries', () => { - expectValid( - testSchema, - ` + const doc = parse(` query { catOrDog { ... on Cat { @@ -34,24 +27,26 @@ describe('Validate: Supports full validation', () => { } } } - `, - ); + `); + + const errors = validate(testSchema, doc); + expect(errors).to.deep.equal([]); }); it('detects bad scalar parse', () => { - const doc = ` + const doc = parse(` query { invalidArg(arg: "bad value") } - `; + `); - const errors = validate(testSchema, parse(doc)); + const errors = validate(testSchema, doc); expect(errors).to.deep.equal([ { locations: [{ line: 3, column: 25 }], message: 'Expected type Invalid, found "bad value"; ' + - 'Invalid scalar is always invalid: bad value', + 'Invalid scalar is always invalid: "bad value"', }, ]); }); @@ -61,7 +56,7 @@ describe('Validate: Supports full validation', () => { // This TypeInfo will never return a valid field. const typeInfo = new TypeInfo(testSchema, () => null); - const ast = parse(` + const doc = parse(` query { catOrDog { ... on Cat { @@ -74,8 +69,7 @@ describe('Validate: Supports full validation', () => { } `); - const errors = validate(testSchema, ast, specifiedRules, typeInfo); - + const errors = validate(testSchema, doc, specifiedRules, typeInfo); const errorMessages = errors.map(err => err.message); expect(errorMessages).to.deep.equal([