Skip to content

Commit 845da80

Browse files
committed
add tests
1 parent 21ffcc1 commit 845da80

File tree

1 file changed

+301
-1
lines changed

1 file changed

+301
-1
lines changed

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

Lines changed: 301 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// eslint-disable-next-line import/no-extraneous-dependencies
1+
22
import { inspect } from 'cross-inspect';
33
import {
44
GraphQLArgumentConfig,
@@ -30,6 +30,13 @@ const TestComplexScalar = new GraphQLScalarType({
3030
},
3131
});
3232

33+
const NestedType: GraphQLObjectType = new GraphQLObjectType({
34+
name: 'NestedType',
35+
fields: {
36+
echo: fieldWithInputArg({ type: GraphQLString }),
37+
},
38+
});
39+
3340
const TestInputObject = new GraphQLInputObjectType({
3441
name: 'TestInputObject',
3542
fields: {
@@ -98,6 +105,10 @@ const TestType = new GraphQLObjectType({
98105
defaultValue: 'Hello World',
99106
}),
100107
list: fieldWithInputArg({ type: new GraphQLList(GraphQLString) }),
108+
nested: {
109+
type: NestedType,
110+
resolve: () => ({}),
111+
},
101112
nnList: fieldWithInputArg({
102113
type: new GraphQLNonNull(new GraphQLList(GraphQLString)),
103114
}),
@@ -117,6 +128,16 @@ function executeQuery(query: string, variableValues?: { [variable: string]: unkn
117128
return executeSync({ schema, document, variableValues });
118129
}
119130

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

0 commit comments

Comments
 (0)