diff --git a/src/QueryComplexity.ts b/src/QueryComplexity.ts index 091f45c..41dee1e 100644 --- a/src/QueryComplexity.ts +++ b/src/QueryComplexity.ts @@ -174,12 +174,18 @@ export default class QueryComplexity { // Get variable values from variables that are passed from options, merged // with default values defined in the operation - this.variableValues = getVariableValues( + const { coerced, errors } = getVariableValues( this.context.getSchema(), // We have to create a new array here because input argument is not readonly in graphql ~14.6.0 operation.variableDefinitions ? [...operation.variableDefinitions] : [], this.options.variables ?? {} - ).coerced; + ); + if (errors && errors.length) { + // We have input validation errors, report errors and abort + errors.forEach((error) => this.context.reportError(error)); + return; + } + this.variableValues = coerced; switch (operation.operation) { case 'query': diff --git a/src/__tests__/QueryComplexity-test.ts b/src/__tests__/QueryComplexity-test.ts index 6c22ae3..92269dd 100644 --- a/src/__tests__/QueryComplexity-test.ts +++ b/src/__tests__/QueryComplexity-test.ts @@ -254,21 +254,28 @@ describe('QueryComplexity analysis', () => { expect(visitor.complexity).to.equal(0); }); - it('should ignore unused variables', () => { + it('should report errors for unused variables', () => { const ast = parse(` query ($unusedVar: ID!) { variableScalar(count: 100) } `); - const context = new CompatibleValidationContext(schema, ast, typeInfo); - const visitor = new ComplexityVisitor(context, { - maximumComplexity: 100, - estimators: [simpleEstimator({ defaultComplexity: 10 })], - }); - - visit(ast, visitWithTypeInfo(typeInfo, visitor)); - expect(visitor.complexity).to.equal(10); + const errors = validate(schema, ast, [ + createComplexityRule({ + maximumComplexity: 1000, + estimators: [ + simpleEstimator({ + defaultComplexity: 1, + }), + ], + variables: { + unusedVar: 'someID', + }, + }), + ]); + expect(errors).to.have.length(1); + expect(errors[0].message).to.contain('$unusedVar'); }); it('should ignore unknown field', () => { @@ -860,4 +867,28 @@ describe('QueryComplexity analysis', () => { // query.scalar(5) + query.requiredArgs(5) * requiredArgs.scalar(5) expect(complexity).to.equal(30); }); + + it('reports variable coercion errors', () => { + const ast = parse(` + query ($input: RGB!){ + enumInputArg(enum: $input) + } + `); + + const errors = validate(schema, ast, [ + createComplexityRule({ + maximumComplexity: 1000, + estimators: [ + simpleEstimator({ + defaultComplexity: 1, + }), + ], + variables: { + input: 'INVALIDVALUE', + }, + }), + ]); + expect(errors).to.have.length(1); + expect(errors[0].message).to.contain('INVALIDVALUE'); + }); }); diff --git a/src/__tests__/fixtures/schema.ts b/src/__tests__/fixtures/schema.ts index 5a2d30b..415994a 100644 --- a/src/__tests__/fixtures/schema.ts +++ b/src/__tests__/fixtures/schema.ts @@ -164,6 +164,14 @@ const Query = new GraphQLObjectType({ }, }, }, + enumInputArg: { + type: GraphQLString, + args: { + enum: { + type: EnumType, + }, + }, + }, _service: { type: SDLInterface }, }), interfaces: () => [NameInterface, UnionInterface],