Skip to content
Closed
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@
"no-unneeded-ternary": 2,
"no-unreachable": 2,
"no-unused-expressions": 2,
"no-unused-vars": [2, {"vars": "all", "args": "after-used", "argsIgnorePattern": "^_"}],
"no-unused-vars": [2, {"vars": "all", "args": "after-used", "argsIgnorePattern": "^_", "ignoreRestSiblings": true}],
"no-use-before-define": 0,
"no-useless-call": 2,
"no-useless-escape": 2,
Expand Down
335 changes: 334 additions & 1 deletion src/execution/__tests__/variables-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
GraphQLSchema,
GraphQLObjectType,
GraphQLInputObjectType,
GraphQLInputUnionType,
GraphQLList,
GraphQLString,
GraphQLNonNull,
Expand Down Expand Up @@ -59,6 +60,35 @@ const TestNestedInputObject = new GraphQLInputObjectType({
},
});

const TestUnionInputObjectA = new GraphQLInputObjectType({
name: 'TestUnionInputObjectA',
fields: {
a: { type: GraphQLString },
b: { type: GraphQLList(GraphQLString) },
},
});

const TestUnionInputObjectB = new GraphQLInputObjectType({
name: 'TestUnionInputObjectB',
fields: {
c: { type: GraphQLNonNull(GraphQLString) },
d: { type: TestComplexScalar },
},
});

const TestInputUnion = new GraphQLInputUnionType({
name: 'TestInputUnion',
types: [TestUnionInputObjectA, TestUnionInputObjectB],
});

const TestNestedInputUnion = new GraphQLInputObjectType({
name: 'TestNestedInputUnion',
fields: {
na: { type: GraphQLNonNull(TestInputUnion) },
nb: { type: GraphQLNonNull(GraphQLString) },
},
});

const TestType = new GraphQLObjectType({
name: 'TestType',
fields: {
Expand All @@ -67,6 +97,11 @@ const TestType = new GraphQLObjectType({
args: { input: { type: TestInputObject } },
resolve: (_, { input }) => input && JSON.stringify(input),
},
fieldWithUnionInput: {
type: GraphQLString,
args: { input: { type: TestInputUnion } },
resolve: (_, { input }) => input && JSON.stringify(input),
},
fieldWithNullableStringInput: {
type: GraphQLString,
args: { input: { type: GraphQLString } },
Expand All @@ -87,6 +122,15 @@ const TestType = new GraphQLObjectType({
args: {
input: {
type: TestNestedInputObject,
},
},
resolve: (_, { input }) => input && JSON.stringify(input),
},
fieldWithNestedUnionInput: {
type: GraphQLString,
args: {
input: {
type: TestNestedInputUnion,
defaultValue: 'Hello World',
},
},
Expand Down Expand Up @@ -229,6 +273,115 @@ describe('Execute: Handles inputs', () => {
});
});

describe('using inline structs with union input', () => {
it('executes with complex input', async () => {
const doc = `
{
a: fieldWithUnionInput(input: {__inputname: "TestUnionInputObjectA", a: "foo", b: ["bar"]})
b: fieldWithUnionInput(input: {__inputname: "TestUnionInputObjectB", c: "baz"})
}
`;
const ast = parse(doc);

expect(await execute(schema, ast)).to.deep.equal({
data: {
a: '{"__inputname":"TestUnionInputObjectA","a":"foo","b":["bar"]}',
b: '{"__inputname":"TestUnionInputObjectB","c":"baz"}',
},
});
});

it('properly parses single value to list', async () => {
const doc = `
{
fieldWithUnionInput(input: {__inputname: "TestUnionInputObjectA", a: "foo", b: "bar"})
}
`;
const ast = parse(doc);

expect(await execute(schema, ast)).to.deep.equal({
data: {
fieldWithUnionInput:
'{"__inputname":"TestUnionInputObjectA","a":"foo","b":["bar"]}',
},
});
});

it('properly parses null value to null', async () => {
const doc = `
{
a: fieldWithUnionInput(input: {__inputname: "TestUnionInputObjectA", a: null, b: null, c: "C", d: null})
b: fieldWithUnionInput(input: {__inputname: "TestUnionInputObjectB", c: "C", d: null})
}
`;
const ast = parse(doc);

expect(await execute(schema, ast)).to.deep.equal({
data: {
a: '{"__inputname":"TestUnionInputObjectA","a":null,"b":null}',
b: '{"__inputname":"TestUnionInputObjectB","c":"C","d":null}',
},
});
});

it('properly parses null value in list', async () => {
const doc = `
{
fieldWithUnionInput(input: {__inputname: "TestUnionInputObjectA", b: ["A",null,"C"]})
}
`;
const ast = parse(doc);

expect(await execute(schema, ast)).to.deep.equal({
data: {
fieldWithUnionInput:
'{"__inputname":"TestUnionInputObjectA","b":["A",null,"C"]}',
},
});
});

it('does not use incorrect value', async () => {
const doc = `
{
fieldWithUnionInput(input: ["foo", "bar", "baz"])
}
`;
const ast = parse(doc);

const result = await execute(schema, ast);

expect(result).to.containSubset({
data: {
fieldWithUnionInput: null,
},
errors: [
{
message:
'Argument "input" has invalid value ["foo", "bar", "baz"].',
path: ['fieldWithUnionInput'],
locations: [{ line: 3, column: 38 }],
},
],
});
});

it('properly runs parseLiteral on complex scalar types', async () => {
const doc = `
{
fieldWithUnionInput(input: {__inputname:"TestUnionInputObjectB", c: "foo", d: "SerializedValue"})
}
`;
const ast = parse(doc);

expect(await execute(schema, ast)).to.deep.equal({
data: {
fieldWithUnionInput:
'{"__inputname":"TestUnionInputObjectB","c":"foo","d":"DeserializedValue"}',
},
});
});
});

describe('using variables', () => {
const doc = `
query q($input: TestInputObject) {
Expand Down Expand Up @@ -341,7 +494,7 @@ describe('Execute: Handles inputs', () => {
it('errors on deep nested errors and with many errors', async () => {
const nestedDoc = `
query q($input: TestNestedInputObject) {
fieldWithNestedObjectInput(input: $input)
fieldWithNestedInputObject(input: $input)
}
`;
const nestedAst = parse(nestedDoc);
Expand Down Expand Up @@ -388,6 +541,186 @@ describe('Execute: Handles inputs', () => {
});
});
});

describe('using variables with union input', () => {
const doc = `
query q($input: TestInputUnion) {
fieldWithUnionInput(input: $input)
}
`;
const ast = parse(doc);

it('executes with complex input', async () => {
const params = {
input: { a: 'foo', b: ['bar'], __inputname: 'TestUnionInputObjectA' },
};
const result = await execute(schema, ast, null, null, params);

expect(result).to.deep.equal({
data: {
fieldWithUnionInput:
'{"__inputname":"TestUnionInputObjectA","a":"foo","b":["bar"]}',
},
});
});

it('uses default value when not provided', async () => {
const withDefaultsAST = parse(`
query q($input: TestInputUnion = {__inputname:"TestUnionInputObjectA", a: "foo", b: ["bar"], c: "baz"}) {
fieldWithUnionInput(input: $input)
}
`);

const result = await execute(schema, withDefaultsAST);

expect(result).to.deep.equal({
data: {
fieldWithUnionInput:
'{"__inputname":"TestUnionInputObjectA","a":"foo","b":["bar"]}',
},
});
});

it('properly parses single value to list', async () => {
const params = {
input: { a: 'foo', b: 'bar', __inputname: 'TestUnionInputObjectA' },
};
const result = await execute(schema, ast, null, null, params);

expect(result).to.deep.equal({
data: {
fieldWithUnionInput:
'{"__inputname":"TestUnionInputObjectA","a":"foo","b":["bar"]}',
},
});
});

it('executes with complex scalar input', async () => {
const params = {
input: {
c: 'foo',
d: 'SerializedValue',
__inputname: 'TestUnionInputObjectB',
},
};
const result = await execute(schema, ast, null, null, params);

expect(result).to.deep.equal({
data: {
fieldWithUnionInput:
'{"__inputname":"TestUnionInputObjectB","c":"foo","d":"DeserializedValue"}',
},
});
});

it('errors on null for nested non-null', async () => {
const params = {
input: { __inputname: 'TestUnionInputObjectB', c: null },
};

const result = await execute(schema, ast, null, null, params);
expect(result).to.deep.equal({
errors: [
{
message:
'Variable "$input" got invalid value ' +
'{"__inputname":"TestUnionInputObjectB","c":null}; ' +
'Expected non-nullable type String! not to be null at value.c.',
locations: [{ line: 2, column: 17 }],
path: undefined,
},
],
});
});

it('errors on incorrect type', async () => {
const params = { input: 'foo bar' };

const result = await execute(schema, ast, null, null, params);
expect(result).to.deep.equal({
errors: [
{
message:
'Variable "$input" got invalid value "foo bar"; ' +
'Expected type TestInputUnion to be an object.',
locations: [{ line: 2, column: 17 }],
path: undefined,
},
],
});
});

it('errors on omission of nested non-null', async () => {
const params = { input: { __inputname: 'TestUnionInputObjectB' } };

const result = await execute(schema, ast, null, null, params);
expect(result).to.deep.equal({
errors: [
{
message:
'Variable "$input" got invalid value {"__inputname":"TestUnionInputObjectB"}; ' +
'Field value.c of required type String! was not provided.',
locations: [{ line: 2, column: 17 }],
path: undefined,
},
],
});
});

it('errors on deep nested errors and with many errors', async () => {
const nestedDoc = `
query q($input: TestNestedInputObject) {
fieldWithNestedUnionInput(input: $input)
}
`;
const nestedAst = parse(nestedDoc);
const params = { input: { na: { a: 'foo' } } };

const result = await execute(schema, nestedAst, null, null, params);
expect(result).to.deep.equal({
errors: [
{
message:
'Variable "$input" got invalid value {"na":{"a":"foo"}}; ' +
'Field value.na.c of required type String! was not provided.',
locations: [{ line: 2, column: 19 }],
path: undefined,
},
{
message:
'Variable "$input" got invalid value {"na":{"a":"foo"}}; ' +
'Field value.nb of required type String! was not provided.',
locations: [{ line: 2, column: 19 }],
path: undefined,
},
],
});
});

it('errors on addition of unknown input field', async () => {
const params = {
input: {
__inputname: 'TestUnionInputObjectB',
c: 'baz',
extra: 'dog',
},
};

const result = await execute(schema, ast, null, null, params);
expect(result).to.deep.equal({
errors: [
{
message:
'Variable "$input" got invalid value ' +
'{"__inputname":"TestUnionInputObjectB","c":"baz","extra":"dog"}; ' +
'Field "extra" is not defined by type TestUnionInputObjectB.',
locations: [{ line: 2, column: 17 }],
path: undefined,
},
],
});
});
});
});

describe('Handles nullable scalars', () => {
Expand Down
Loading