Skip to content

Commit

Permalink
add runtime errors for pre-coercion OneOf errors
Browse files Browse the repository at this point in the history
  • Loading branch information
yaacovCR committed Sep 18, 2024
1 parent 7875552 commit 136cde0
Show file tree
Hide file tree
Showing 4 changed files with 440 additions and 28 deletions.
357 changes: 355 additions & 2 deletions src/execution/__tests__/oneof-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,12 @@ function executeQuery(
rootValue: unknown,
variableValues?: { [variable: string]: unknown },
): ExecutionResult | Promise<ExecutionResult> {
return execute({ schema, document: parse(query), rootValue, variableValues });
return execute({
schema,
document: parse(query, { experimentalFragmentArguments: true }),
rootValue,
variableValues,
});
}

describe('Execute: Handles OneOf Input Objects', () => {
Expand Down Expand Up @@ -158,7 +163,7 @@ describe('Execute: Handles OneOf Input Objects', () => {
});
});

it('rejects a variable with multiple nullable keys', () => {
it('rejects a variable with multiple keys, some set to null', () => {
const query = `
query ($input: TestInputObject!) {
test(input: $input) {
Expand All @@ -178,6 +183,354 @@ describe('Execute: Handles OneOf Input Objects', () => {
message:
'Variable "$input" got invalid value { a: "abc", b: null }; Exactly one key must be specified for OneOf type "TestInputObject".',
},
{
message:
'Variable "$input" got invalid value null at "input.b"; Field "b" of OneOf type "TestInputObject" must be non-null.',
locations: [{ line: 2, column: 16 }],
},
],
});
});

it('rejects a variable with multiple null keys', () => {
const query = `
query ($input: TestInputObject!) {
test(input: $input) {
a
b
}
}
`;
const result = executeQuery(query, rootValue, {
input: { a: null, b: null },
});

expectJSON(result).toDeepEqual({
errors: [
{
locations: [{ column: 16, line: 2 }],
message:
'Variable "$input" got invalid value { a: null, b: null }; Exactly one key must be specified for OneOf type "TestInputObject".',
},
{
message:
'Variable "$input" got invalid value null at "input.a"; Field "a" of OneOf type "TestInputObject" must be non-null.',
locations: [{ line: 2, column: 16 }],
},
{
message:
'Variable "$input" got invalid value null at "input.b"; Field "b" of OneOf type "TestInputObject" must be non-null.',
locations: [{ line: 2, column: 16 }],
},
],
});
});

it('accepts a valid variable for field', () => {
const query = `
query ($a: String!) {
test(input: { a: $a }) {
a
b
}
}
`;
const result = executeQuery(query, rootValue, { a: 'abc' });

expectJSON(result).toDeepEqual({
data: {
test: {
a: 'abc',
b: null,
},
},
});
});

it('rejects multiple variables for fields', () => {
const query = `
query ($a: String!, $b: Int!) {
test(input: { a: $a, b: $b }) {
a
b
}
}
`;
const result = executeQuery(query, rootValue, { a: 'abc', b: 123 });

expectJSON(result).toDeepEqual({
data: {
test: null,
},
errors: [
{
// A nullable variable in a oneOf field position would be caught at validation-time
// hence the vague error message here.
message:
'Argument "input" of type "TestInputObject!" has invalid value { a: $a, b: $b }.',
locations: [{ line: 3, column: 23 }],
path: ['test'],
},
],
});
});

it('rejects variable for field explicitly set to undefined', () => {
const query = `
query ($a: String) {
test(input: { a: $a }) {
a
b
}
}
`;
const result = executeQuery(query, rootValue, { a: undefined });

expectJSON(result).toDeepEqual({
data: {
test: null,
},
errors: [
{
// A nullable variable in a oneOf field position would be caught at validation-time
// hence the vague error message here.
message:
'Argument "input" of type "TestInputObject!" has invalid value { a: $a }.',
locations: [{ line: 3, column: 23 }],
path: ['test'],
},
],
});
});

it('rejects nulled variable for field', () => {
const query = `
query ($a: String) {
test(input: { a: $a }) {
a
b
}
}
`;
const result = executeQuery(query, rootValue, { a: null });

expectJSON(result).toDeepEqual({
data: {
test: null,
},
errors: [
{
// A nullable variable in a oneOf field position would be caught at validation-time
// hence the vague error message here.
message:
'Argument "input" of type "TestInputObject!" has invalid value { a: $a }.',
locations: [{ line: 3, column: 23 }],
path: ['test'],
},
],
});
});

it('rejects missing variable for field', () => {
const query = `
query ($a: String) {
test(input: { a: $a }) {
a
b
}
}
`;
const result = executeQuery(query, rootValue);

expectJSON(result).toDeepEqual({
data: {
test: null,
},
errors: [
{
// A nullable variable in a oneOf field position would be caught at validation-time
// hence the vague error message here.
message:
'Argument "input" of type "TestInputObject!" has invalid value { a: $a }.',
locations: [{ line: 3, column: 23 }],
path: ['test'],
},
],
});
});

it('rejects missing second variable for field', () => {
const query = `
query ($a: String, $b: String) {
test(input: { a: $a, b: $b }) {
a
b
}
}
`;
const result = executeQuery(query, rootValue, { a: '123' });

expectJSON(result).toDeepEqual({
data: {
test: null,
},
errors: [
{
// A nullable variable in a oneOf field position would be caught at validation-time
// hence the vague error message here.
message:
'Argument "input" of type "TestInputObject!" has invalid value { a: $a, b: $b }.',
locations: [{ line: 3, column: 23 }],
path: ['test'],
},
],
});
});

it('accepts a valid fragment variable for field', () => {
const query = `
query {
...TestFragment(a: "abc")
}
fragment TestFragment($a: String) on Query {
test(input: { a: $a }) {
a
b
}
}
`;
const result = executeQuery(query, rootValue, { a: 'abc' });

expectJSON(result).toDeepEqual({
data: {
test: {
a: 'abc',
b: null,
},
},
});
});

it('rejects multiple fragment variables for fields', () => {
const query = `
query {
...TestFragment(a: "abc", b: 123)
}
fragment TestFragment($a: String, $b: Int) on Query {
test(input: { a: $a, b: $b }) {
a
b
}
}
`;
const result = executeQuery(query, rootValue, { a: 'abc', b: 123 });

expectJSON(result).toDeepEqual({
data: {
test: null,
},
errors: [
{
// A nullable variable in a oneOf field position would be caught at validation-time
// hence the vague error message here.
message:
'Argument "input" of type "TestInputObject!" has invalid value { a: $a, b: $b }.',
locations: [{ line: 6, column: 23 }],
path: ['test'],
},
],
});
});

it('rejects nulled fragment variable for field', () => {
const query = `
query {
...TestFragment(a: null)
}
fragment TestFragment($a: String) on Query {
test(input: { a: $a }) {
a
b
}
}
`;
const result = executeQuery(query, rootValue, { a: null });

expectJSON(result).toDeepEqual({
data: {
test: null,
},
errors: [
{
// A nullable variable in a oneOf field position would be caught at validation-time
// hence the vague error message here.
message:
'Argument "input" of type "TestInputObject!" has invalid value { a: $a }.',
locations: [{ line: 6, column: 23 }],
path: ['test'],
},
],
});
});

it('rejects missing fragment variable for field', () => {
const query = `
query {
...TestFragment
}
fragment TestFragment($a: String) on Query {
test(input: { a: $a }) {
a
b
}
}
`;
const result = executeQuery(query, rootValue);

expectJSON(result).toDeepEqual({
data: {
test: null,
},
errors: [
{
// A nullable variable in a oneOf field position would be caught at validation-time
// hence the vague error message here.
message:
'Argument "input" of type "TestInputObject!" has invalid value { a: $a }.',
locations: [{ line: 6, column: 23 }],
path: ['test'],
},
],
});
});

it('rejects missing second fragment variable for field', () => {
const query = `
query {
...TestFragment(a: "123")
}
fragment TestFragment($a: String, $b: string) on Query {
test(input: { a: $a, b: $b }) {
a
b
}
}
`;
const result = executeQuery(query, rootValue, { a: '123' });

expectJSON(result).toDeepEqual({
data: {
test: null,
},
errors: [
{
// A nullable variable in a oneOf field position would be caught at validation-time
// hence the vague error message here.
message:
'Argument "input" of type "TestInputObject!" has invalid value { a: $a, b: $b }.',
locations: [{ line: 6, column: 23 }],
path: ['test'],
},
],
});
});
Expand Down
Loading

0 comments on commit 136cde0

Please sign in to comment.