Skip to content

Commit 6c57de1

Browse files
committed
add tests
1 parent 21ffcc1 commit 6c57de1

File tree

1 file changed

+293
-1
lines changed

1 file changed

+293
-1
lines changed

packages/executor/src/execution/__tests__/variables-test.ts

Lines changed: 293 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
// eslint-disable-next-line import/no-extraneous-dependencies
21
import { inspect } from 'cross-inspect';
32
import {
43
GraphQLArgumentConfig,
@@ -30,6 +29,13 @@ const TestComplexScalar = new GraphQLScalarType({
3029
},
3130
});
3231

32+
const NestedType: GraphQLObjectType = new GraphQLObjectType({
33+
name: 'NestedType',
34+
fields: {
35+
echo: fieldWithInputArg({ type: GraphQLString }),
36+
},
37+
});
38+
3339
const TestInputObject = new GraphQLInputObjectType({
3440
name: 'TestInputObject',
3541
fields: {
@@ -98,6 +104,10 @@ const TestType = new GraphQLObjectType({
98104
defaultValue: 'Hello World',
99105
}),
100106
list: fieldWithInputArg({ type: new GraphQLList(GraphQLString) }),
107+
nested: {
108+
type: NestedType,
109+
resolve: () => ({}),
110+
},
101111
nnList: fieldWithInputArg({
102112
type: new GraphQLNonNull(new GraphQLList(GraphQLString)),
103113
}),
@@ -117,6 +127,15 @@ function executeQuery(query: string, variableValues?: { [variable: string]: unkn
117127
return executeSync({ schema, document, variableValues });
118128
}
119129

130+
function executeQueryWithFragmentArguments(
131+
query: string,
132+
variableValues?: { [variable: string]: unknown },
133+
) {
134+
// TODO: figure out how to do custom parser here
135+
const document = parse(query, { experimentalFragmentArguments: true });
136+
return executeSync({ schema, document, variableValues });
137+
}
138+
120139
describe('Execute: Handles inputs', () => {
121140
describe('Handles objects and nullability', () => {
122141
describe('using inline structs', () => {
@@ -1038,4 +1057,277 @@ describe('Execute: Handles inputs', () => {
10381057
});
10391058
});
10401059
});
1060+
1061+
describe('using fragment arguments', () => {
1062+
it('when there are no fragment arguments', () => {
1063+
const result = executeQueryWithFragmentArguments(`
1064+
query {
1065+
...a
1066+
}
1067+
fragment a on TestType {
1068+
fieldWithNonNullableStringInput(input: "A")
1069+
}
1070+
`);
1071+
expectJSON(result).toDeepEqual({
1072+
data: {
1073+
fieldWithNonNullableStringInput: '"A"',
1074+
},
1075+
});
1076+
});
1077+
1078+
it('when a value is required and provided', () => {
1079+
const result = executeQueryWithFragmentArguments(`
1080+
query {
1081+
...a(value: "A")
1082+
}
1083+
fragment a($value: String!) on TestType {
1084+
fieldWithNonNullableStringInput(input: $value)
1085+
}
1086+
`);
1087+
expectJSON(result).toDeepEqual({
1088+
data: {
1089+
fieldWithNonNullableStringInput: '"A"',
1090+
},
1091+
});
1092+
});
1093+
1094+
it('when a value is required and not provided', () => {
1095+
const result = executeQueryWithFragmentArguments(`
1096+
query {
1097+
...a
1098+
}
1099+
fragment a($value: String!) on TestType {
1100+
fieldWithNullableStringInput(input: $value)
1101+
}
1102+
`);
1103+
1104+
expect(result).toHaveProperty('errors');
1105+
expect(result.errors).toHaveLength(1);
1106+
expect(result.errors?.at(0)?.message).toMatch(/Argument "value" of required type "String!"/);
1107+
});
1108+
1109+
it('when the definition has a default and is provided', () => {
1110+
const result = executeQueryWithFragmentArguments(`
1111+
query {
1112+
...a(value: "A")
1113+
}
1114+
fragment a($value: String! = "B") on TestType {
1115+
fieldWithNonNullableStringInput(input: $value)
1116+
}
1117+
`);
1118+
expectJSON(result).toDeepEqual({
1119+
data: {
1120+
fieldWithNonNullableStringInput: '"A"',
1121+
},
1122+
});
1123+
});
1124+
1125+
it('when the definition has a default and is not provided', () => {
1126+
const result = executeQueryWithFragmentArguments(`
1127+
query {
1128+
...a
1129+
}
1130+
fragment a($value: String! = "B") on TestType {
1131+
fieldWithNonNullableStringInput(input: $value)
1132+
}
1133+
`);
1134+
expectJSON(result).toDeepEqual({
1135+
data: {
1136+
fieldWithNonNullableStringInput: '"B"',
1137+
},
1138+
});
1139+
});
1140+
1141+
it('when a definition has a default, is not provided, and spreads another fragment', () => {
1142+
const result = executeQueryWithFragmentArguments(`
1143+
query {
1144+
...a
1145+
}
1146+
fragment a($a: String! = "B") on TestType {
1147+
...b(b: $a)
1148+
}
1149+
fragment b($b: String!) on TestType {
1150+
fieldWithNonNullableStringInput(input: $b)
1151+
}
1152+
`);
1153+
expectJSON(result).toDeepEqual({
1154+
data: {
1155+
fieldWithNonNullableStringInput: '"B"',
1156+
},
1157+
});
1158+
});
1159+
1160+
it('when the definition has a non-nullable default and is provided null', () => {
1161+
const result = executeQueryWithFragmentArguments(`
1162+
query {
1163+
...a(value: null)
1164+
}
1165+
fragment a($value: String! = "B") on TestType {
1166+
fieldWithNullableStringInput(input: $value)
1167+
}
1168+
`);
1169+
1170+
expect(result).toHaveProperty('errors');
1171+
expect(result.errors).toHaveLength(1);
1172+
expect(result.errors?.at(0)?.message).toMatch(/Argument "value" of non-null type "String!"/);
1173+
});
1174+
1175+
it('when the definition has no default and is not provided', () => {
1176+
const result = executeQueryWithFragmentArguments(`
1177+
query {
1178+
...a
1179+
}
1180+
fragment a($value: String) on TestType {
1181+
fieldWithNonNullableStringInputAndDefaultArgumentValue(input: $value)
1182+
}
1183+
`);
1184+
expectJSON(result).toDeepEqual({
1185+
data: {
1186+
fieldWithNonNullableStringInputAndDefaultArgumentValue: '"Hello World"',
1187+
},
1188+
});
1189+
});
1190+
1191+
it('when an argument is shadowed by an operation variable', () => {
1192+
const result = executeQueryWithFragmentArguments(`
1193+
query($x: String! = "A") {
1194+
...a(x: "B")
1195+
}
1196+
fragment a($x: String) on TestType {
1197+
fieldWithNullableStringInput(input: $x)
1198+
}
1199+
`);
1200+
expectJSON(result).toDeepEqual({
1201+
data: {
1202+
fieldWithNullableStringInput: '"B"',
1203+
},
1204+
});
1205+
});
1206+
1207+
it('when a nullable argument with a field default is not provided and shadowed by an operation variable', () => {
1208+
const result = executeQueryWithFragmentArguments(`
1209+
query($x: String = "A") {
1210+
...a
1211+
}
1212+
fragment a($x: String) on TestType {
1213+
fieldWithNonNullableStringInputAndDefaultArgumentValue(input: $x)
1214+
}
1215+
`);
1216+
expectJSON(result).toDeepEqual({
1217+
data: {
1218+
fieldWithNonNullableStringInputAndDefaultArgumentValue: '"Hello World"',
1219+
},
1220+
});
1221+
});
1222+
1223+
it('when a fragment-variable is shadowed by an intermediate fragment-spread but defined in the operation-variables', () => {
1224+
const result = executeQueryWithFragmentArguments(`
1225+
query($x: String = "A") {
1226+
...a
1227+
}
1228+
fragment a($x: String) on TestType {
1229+
...b
1230+
}
1231+
fragment b on TestType {
1232+
fieldWithNullableStringInput(input: $x)
1233+
}
1234+
`);
1235+
expectJSON(result).toDeepEqual({
1236+
data: {
1237+
fieldWithNullableStringInput: '"A"',
1238+
},
1239+
});
1240+
});
1241+
1242+
it('when a fragment is used with different args', () => {
1243+
const result = executeQueryWithFragmentArguments(`
1244+
query($x: String = "Hello") {
1245+
a: nested {
1246+
...a(x: "a")
1247+
}
1248+
b: nested {
1249+
...a(x: "b", b: true)
1250+
}
1251+
hello: nested {
1252+
...a(x: $x)
1253+
}
1254+
}
1255+
fragment a($x: String, $b: Boolean = false) on NestedType {
1256+
a: echo(input: $x) @skip(if: $b)
1257+
b: echo(input: $x) @include(if: $b)
1258+
}
1259+
`);
1260+
expectJSON(result).toDeepEqual({
1261+
data: {
1262+
a: {
1263+
a: '"a"',
1264+
},
1265+
b: {
1266+
b: '"b"',
1267+
},
1268+
hello: {
1269+
a: '"Hello"',
1270+
},
1271+
},
1272+
});
1273+
});
1274+
1275+
it('when the argument variable is nested in a complex type', () => {
1276+
const result = executeQueryWithFragmentArguments(`
1277+
query {
1278+
...a(value: "C")
1279+
}
1280+
fragment a($value: String) on TestType {
1281+
list(input: ["A", "B", $value, "D"])
1282+
}
1283+
`);
1284+
expectJSON(result).toDeepEqual({
1285+
data: {
1286+
list: '["A", "B", "C", "D"]',
1287+
},
1288+
});
1289+
});
1290+
1291+
it('when argument variables are used recursively', () => {
1292+
const result = executeQueryWithFragmentArguments(`
1293+
query {
1294+
...a(aValue: "C")
1295+
}
1296+
fragment a($aValue: String) on TestType {
1297+
...b(bValue: $aValue)
1298+
}
1299+
fragment b($bValue: String) on TestType {
1300+
list(input: ["A", "B", $bValue, "D"])
1301+
}
1302+
`);
1303+
expectJSON(result).toDeepEqual({
1304+
data: {
1305+
list: '["A", "B", "C", "D"]',
1306+
},
1307+
});
1308+
});
1309+
1310+
it('when argument passed in as list', () => {
1311+
const result = executeQueryWithFragmentArguments(`
1312+
query Q($opValue: String = "op") {
1313+
...a(aValue: "A")
1314+
}
1315+
fragment a($aValue: String, $bValue: String) on TestType {
1316+
...b(aValue: [$aValue, "B"], bValue: [$bValue, $opValue])
1317+
}
1318+
fragment b($aValue: [String], $bValue: [String], $cValue: String) on TestType {
1319+
aList: list(input: $aValue)
1320+
bList: list(input: $bValue)
1321+
cList: list(input: [$cValue])
1322+
}
1323+
`);
1324+
expectJSON(result).toDeepEqual({
1325+
data: {
1326+
aList: '["A", "B"]',
1327+
bList: '[null, "op"]',
1328+
cList: '[null]',
1329+
},
1330+
});
1331+
});
1332+
});
10411333
});

0 commit comments

Comments
 (0)