diff --git a/src/utilities/__tests__/coerceInputValue-test.ts b/src/utilities/__tests__/coerceInputValue-test.ts index 5f46b066d1..f8910bd5ba 100644 --- a/src/utilities/__tests__/coerceInputValue-test.ts +++ b/src/utilities/__tests__/coerceInputValue-test.ts @@ -598,6 +598,7 @@ describe('coerceInputLiteral', () => { test('{ a: null }', testOneOfInputObj, undefined); test('{ a: 1 }', testOneOfInputObj, undefined); test('{ a: "abc", b: "def" }', testOneOfInputObj, undefined); + test('{ a: "abc", c: "def" }', testOneOfInputObj, undefined); test('{}', testOneOfInputObj, undefined); test('{ c: "abc" }', testOneOfInputObj, undefined); }); diff --git a/src/utilities/__tests__/validateInputValue-test.ts b/src/utilities/__tests__/validateInputValue-test.ts index 31cdd57490..cc8ccb16c0 100644 --- a/src/utilities/__tests__/validateInputValue-test.ts +++ b/src/utilities/__tests__/validateInputValue-test.ts @@ -443,34 +443,31 @@ describe('validateInputValue', () => { }); it('returns error for an unknown field', () => { - // TODO: not technically a OneOf error, as the OneOf validation assumes known fields test({ foo: 123, unknownField: 123 }, TestInputObject, [ { error: 'Expected value of type "TestInputObject" not to include unknown field "unknownField", found: { foo: 123, unknownField: 123 }.', path: [], }, - { - error: - 'Within OneOf Input Object type "TestInputObject", exactly one field must be specified, and the value for that field must be non-null.', - path: [], - }, ]); }); it('returns error for a misspelled field', () => { - // TODO: technically also a OneOf error, as the OneOf validation assumes known fields, so there are no errors here test({ bart: 123 }, TestInputObject, [ { error: 'Expected value of type "TestInputObject" not to include unknown field "bart". Did you mean "bar"? Found: { bart: 123 }.', path: [], }, + { + error: + 'Within OneOf Input Object type "TestInputObject", exactly one field must be specified, and the value for that field must be non-null.', + path: [], + }, ]); }); it('returns error for a misspelled field (no suggestions)', () => { - // TODO: technically also a OneOf error, as the OneOf validation assumes known fields, so there are no errors here test( { bart: 123 }, TestInputObject, @@ -480,6 +477,11 @@ describe('validateInputValue', () => { 'Expected value of type "TestInputObject" not to include unknown field "bart", found: { bart: 123 }.', path: [], }, + { + error: + 'Within OneOf Input Object type "TestInputObject", exactly one field must be specified, and the value for that field must be non-null.', + path: [], + }, ], true, ); @@ -1016,34 +1018,22 @@ describe('validateInputLiteral', () => { }); it('returns error for an unknown field', () => { - // TODO: not technically a OneOf error, as the OneOf validation assumes known fields test('{ foo: 123, unknownField: 123 }', TestInputObject, [ { error: 'Expected value of type "TestInputObject" not to include unknown field "unknownField", found: { foo: 123, unknownField: 123 }.', path: [], }, - { - error: - 'Within OneOf Input Object type "TestInputObject", exactly one field must be specified, and the value for that field must be non-null.', - path: [], - }, ]); }); it('returns error for a misspelled field', () => { - // TODO: not technically a OneOf error, as the OneOf validation assumes known fields test('{ foo: 123, bart: 123 }', TestInputObject, [ { error: 'Expected value of type "TestInputObject" not to include unknown field "bart". Did you mean "bar"? Found: { foo: 123, bart: 123 }.', path: [], }, - { - error: - 'Within OneOf Input Object type "TestInputObject", exactly one field must be specified, and the value for that field must be non-null.', - path: [], - }, ]); }); diff --git a/src/utilities/validateInputValue.ts b/src/utilities/validateInputValue.ts index 865a7b81a1..0beac679d4 100644 --- a/src/utilities/validateInputValue.ts +++ b/src/utilities/validateInputValue.ts @@ -150,7 +150,6 @@ function validateInputValueImpl( if (inputValue[fieldName] === undefined) { continue; } - fields.push(fieldName); if (!Object.hasOwn(fieldDefs, fieldName)) { const suggestion = hideSuggestions ? '' @@ -162,7 +161,9 @@ function validateInputValueImpl( }: ${inspect(inputValue)}.`, path, ); + continue; } + fields.push(fieldName); } if (type.isOneOf) { @@ -414,6 +415,7 @@ function validateInputLiteralImpl( } const fields = valueNode.fields; + const knownFields: Array<(typeof fields)[number]> = []; // Ensure every provided field is defined. for (const fieldNode of fields) { const fieldName = fieldNode.name.value; @@ -429,11 +431,13 @@ function validateInputLiteralImpl( fieldNode, path, ); + } else { + knownFields.push(fieldNode); } } if (type.isOneOf) { - const isNotExactlyOneField = fields.length !== 1; + const isNotExactlyOneField = knownFields.length !== 1; if (isNotExactlyOneField) { reportInvalidLiteral( context.onError, @@ -444,9 +448,9 @@ function validateInputLiteralImpl( return; } - const fieldValueNode = fields[0].value; + const fieldValueNode = knownFields[0].value; if (fieldValueNode.kind === Kind.NULL) { - const fieldName = fields[0].name.value; + const fieldName = knownFields[0].name.value; reportInvalidLiteral( context.onError, getOneOfInputObjectErrorMessage(type), diff --git a/src/validation/__tests__/ValuesOfCorrectTypeRule-test.ts b/src/validation/__tests__/ValuesOfCorrectTypeRule-test.ts index 38dbcdcfd5..3f106dfc5f 100644 --- a/src/validation/__tests__/ValuesOfCorrectTypeRule-test.ts +++ b/src/validation/__tests__/ValuesOfCorrectTypeRule-test.ts @@ -1168,6 +1168,25 @@ describe('Validate: Values of correct type', () => { }, ]); }); + + it('Unknown field does not add a oneOf error', () => { + expectErrors(` + { + complicatedArgs { + oneOfArgField(oneOfArg: { + stringField: "abc", + invalidField: 123 + }) + } + } + `).toDeepEqual([ + { + message: + 'Expected value of type "OneOfInput" not to include unknown field "invalidField". Did you mean "intField"? Found: { stringField: "abc", invalidField: 123 }.', + locations: [{ line: 6, column: 17 }], + }, + ]); + }); }); describe('Directive arguments', () => {