@@ -59,6 +59,13 @@ const TestComplexScalar = new GraphQLScalarType({
5959 } ,
6060} ) ;
6161
62+ const NestedType : GraphQLObjectType = new GraphQLObjectType ( {
63+ name : 'NestedType' ,
64+ fields : {
65+ echo : fieldWithInputArg ( { type : GraphQLString } ) ,
66+ } ,
67+ } ) ;
68+
6269const TestInputObject = new GraphQLInputObjectType ( {
6370 name : 'TestInputObject' ,
6471 fields : {
@@ -129,6 +136,10 @@ const TestType = new GraphQLObjectType({
129136 defaultValue : 'Hello World' ,
130137 } ) ,
131138 list : fieldWithInputArg ( { type : new GraphQLList ( GraphQLString ) } ) ,
139+ nested : {
140+ type : NestedType ,
141+ resolve : ( ) => ( { } ) ,
142+ } ,
132143 nnList : fieldWithInputArg ( {
133144 type : new GraphQLNonNull ( new GraphQLList ( GraphQLString ) ) ,
134145 } ) ,
@@ -153,6 +164,14 @@ function executeQuery(
153164 return executeSync ( { schema, document, variableValues } ) ;
154165}
155166
167+ function executeQueryWithFragmentArguments (
168+ query : string ,
169+ variableValues ?: { [ variable : string ] : unknown } ,
170+ ) {
171+ const document = parse ( query , { experimentalFragmentArguments : true } ) ;
172+ return executeSync ( { schema, document, variableValues } ) ;
173+ }
174+
156175describe ( 'Execute: Handles inputs' , ( ) => {
157176 describe ( 'Handles objects and nullability' , ( ) => {
158177 describe ( 'using inline structs' , ( ) => {
@@ -1136,4 +1155,284 @@ describe('Execute: Handles inputs', () => {
11361155 } ) ;
11371156 } ) ;
11381157 } ) ;
1158+
1159+ describe ( 'using fragment arguments' , ( ) => {
1160+ it ( 'when there are no fragment arguments' , ( ) => {
1161+ const result = executeQueryWithFragmentArguments ( `
1162+ query {
1163+ ...a
1164+ }
1165+ fragment a on TestType {
1166+ fieldWithNonNullableStringInput(input: "A")
1167+ }
1168+ ` ) ;
1169+ expect ( result ) . to . deep . equal ( {
1170+ data : {
1171+ fieldWithNonNullableStringInput : '"A"' ,
1172+ } ,
1173+ } ) ;
1174+ } ) ;
1175+
1176+ it ( 'when a value is required and provided' , ( ) => {
1177+ const result = executeQueryWithFragmentArguments ( `
1178+ query {
1179+ ...a(value: "A")
1180+ }
1181+ fragment a($value: String!) on TestType {
1182+ fieldWithNonNullableStringInput(input: $value)
1183+ }
1184+ ` ) ;
1185+ expect ( result ) . to . deep . equal ( {
1186+ data : {
1187+ fieldWithNonNullableStringInput : '"A"' ,
1188+ } ,
1189+ } ) ;
1190+ } ) ;
1191+
1192+ it ( 'when a value is required and not provided' , ( ) => {
1193+ const result = executeQueryWithFragmentArguments ( `
1194+ query {
1195+ ...a
1196+ }
1197+ fragment a($value: String!) on TestType {
1198+ fieldWithNullableStringInput(input: $value)
1199+ }
1200+ ` ) ;
1201+
1202+ expect ( result ) . to . have . property ( 'errors' ) ;
1203+ expect ( result . errors ) . to . have . length ( 1 ) ;
1204+ expect ( result . errors ?. at ( 0 ) ?. message ) . to . match (
1205+ / A r g u m e n t " v a l u e " o f r e q u i r e d t y p e " S t r i n g ! " / ,
1206+ ) ;
1207+ } ) ;
1208+
1209+ it ( 'when the definition has a default and is provided' , ( ) => {
1210+ const result = executeQueryWithFragmentArguments ( `
1211+ query {
1212+ ...a(value: "A")
1213+ }
1214+ fragment a($value: String! = "B") on TestType {
1215+ fieldWithNonNullableStringInput(input: $value)
1216+ }
1217+ ` ) ;
1218+ expect ( result ) . to . deep . equal ( {
1219+ data : {
1220+ fieldWithNonNullableStringInput : '"A"' ,
1221+ } ,
1222+ } ) ;
1223+ } ) ;
1224+
1225+ it ( 'when the definition has a default and is not provided' , ( ) => {
1226+ const result = executeQueryWithFragmentArguments ( `
1227+ query {
1228+ ...a
1229+ }
1230+ fragment a($value: String! = "B") on TestType {
1231+ fieldWithNonNullableStringInput(input: $value)
1232+ }
1233+ ` ) ;
1234+ expect ( result ) . to . deep . equal ( {
1235+ data : {
1236+ fieldWithNonNullableStringInput : '"B"' ,
1237+ } ,
1238+ } ) ;
1239+ } ) ;
1240+
1241+ it ( 'when a definition has a default, is not provided, and spreads another fragment' , ( ) => {
1242+ const result = executeQueryWithFragmentArguments ( `
1243+ query {
1244+ ...a
1245+ }
1246+ fragment a($a: String! = "B") on TestType {
1247+ ...b(b: $a)
1248+ }
1249+ fragment b($b: String!) on TestType {
1250+ fieldWithNonNullableStringInput(input: $b)
1251+ }
1252+ ` ) ;
1253+ expect ( result ) . to . deep . equal ( {
1254+ data : {
1255+ fieldWithNonNullableStringInput : '"B"' ,
1256+ } ,
1257+ } ) ;
1258+ } ) ;
1259+
1260+ it ( 'when the definition has a non-nullable default and is provided null' , ( ) => {
1261+ const result = executeQueryWithFragmentArguments ( `
1262+ query {
1263+ ...a(value: null)
1264+ }
1265+ fragment a($value: String! = "B") on TestType {
1266+ fieldWithNullableStringInput(input: $value)
1267+ }
1268+ ` ) ;
1269+
1270+ expect ( result ) . to . have . property ( 'errors' ) ;
1271+ expect ( result . errors ) . to . have . length ( 1 ) ;
1272+ expect ( result . errors ?. at ( 0 ) ?. message ) . to . match (
1273+ / A r g u m e n t " v a l u e " o f n o n - n u l l t y p e " S t r i n g ! " / ,
1274+ ) ;
1275+ } ) ;
1276+
1277+ it ( 'when the definition has no default and is not provided' , ( ) => {
1278+ const result = executeQueryWithFragmentArguments ( `
1279+ query {
1280+ ...a
1281+ }
1282+ fragment a($value: String) on TestType {
1283+ fieldWithNonNullableStringInputAndDefaultArgumentValue(input: $value)
1284+ }
1285+ ` ) ;
1286+ expect ( result ) . to . deep . equal ( {
1287+ data : {
1288+ fieldWithNonNullableStringInputAndDefaultArgumentValue :
1289+ '"Hello World"' ,
1290+ } ,
1291+ } ) ;
1292+ } ) ;
1293+
1294+ it ( 'when an argument is shadowed by an operation variable' , ( ) => {
1295+ const result = executeQueryWithFragmentArguments ( `
1296+ query($x: String! = "A") {
1297+ ...a(x: "B")
1298+ }
1299+ fragment a($x: String) on TestType {
1300+ fieldWithNullableStringInput(input: $x)
1301+ }
1302+ ` ) ;
1303+ expect ( result ) . to . deep . equal ( {
1304+ data : {
1305+ fieldWithNullableStringInput : '"B"' ,
1306+ } ,
1307+ } ) ;
1308+ } ) ;
1309+
1310+ it ( 'when a nullable argument with a field default is not provided and shadowed by an operation variable' , ( ) => {
1311+ const result = executeQueryWithFragmentArguments ( `
1312+ query($x: String = "A") {
1313+ ...a
1314+ }
1315+ fragment a($x: String) on TestType {
1316+ fieldWithNonNullableStringInputAndDefaultArgumentValue(input: $x)
1317+ }
1318+ ` ) ;
1319+ expect ( result ) . to . deep . equal ( {
1320+ data : {
1321+ fieldWithNonNullableStringInputAndDefaultArgumentValue :
1322+ '"Hello World"' ,
1323+ } ,
1324+ } ) ;
1325+ } ) ;
1326+
1327+ it ( 'when a fragment-variable is shadowed by an intermediate fragment-spread but defined in the operation-variables' , ( ) => {
1328+ const result = executeQueryWithFragmentArguments ( `
1329+ query($x: String = "A") {
1330+ ...a
1331+ }
1332+ fragment a($x: String) on TestType {
1333+ ...b
1334+ }
1335+
1336+ fragment b on TestType {
1337+ fieldWithNullableStringInput(input: $x)
1338+ }
1339+ ` ) ;
1340+ expect ( result ) . to . deep . equal ( {
1341+ data : {
1342+ fieldWithNullableStringInput : '"A"' ,
1343+ } ,
1344+ } ) ;
1345+ } ) ;
1346+
1347+ it ( 'when a fragment is used with different args' , ( ) => {
1348+ const result = executeQueryWithFragmentArguments ( `
1349+ query($x: String = "Hello") {
1350+ a: nested {
1351+ ...a(x: "a")
1352+ }
1353+ b: nested {
1354+ ...a(x: "b", b: true)
1355+ }
1356+ hello: nested {
1357+ ...a(x: $x)
1358+ }
1359+ }
1360+ fragment a($x: String, $b: Boolean = false) on NestedType {
1361+ a: echo(input: $x) @skip(if: $b)
1362+ b: echo(input: $x) @include(if: $b)
1363+ }
1364+ ` ) ;
1365+ expect ( result ) . to . deep . equal ( {
1366+ data : {
1367+ a : {
1368+ a : '"a"' ,
1369+ } ,
1370+ b : {
1371+ b : '"b"' ,
1372+ } ,
1373+ hello : {
1374+ a : '"Hello"' ,
1375+ } ,
1376+ } ,
1377+ } ) ;
1378+ } ) ;
1379+
1380+ it ( 'when the argument variable is nested in a complex type' , ( ) => {
1381+ const result = executeQueryWithFragmentArguments ( `
1382+ query {
1383+ ...a(value: "C")
1384+ }
1385+ fragment a($value: String) on TestType {
1386+ list(input: ["A", "B", $value, "D"])
1387+ }
1388+ ` ) ;
1389+ expect ( result ) . to . deep . equal ( {
1390+ data : {
1391+ list : '["A", "B", "C", "D"]' ,
1392+ } ,
1393+ } ) ;
1394+ } ) ;
1395+
1396+ it ( 'when argument variables are used recursively' , ( ) => {
1397+ const result = executeQueryWithFragmentArguments ( `
1398+ query {
1399+ ...a(aValue: "C")
1400+ }
1401+ fragment a($aValue: String) on TestType {
1402+ ...b(bValue: $aValue)
1403+ }
1404+ fragment b($bValue: String) on TestType {
1405+ list(input: ["A", "B", $bValue, "D"])
1406+ }
1407+ ` ) ;
1408+ expect ( result ) . to . deep . equal ( {
1409+ data : {
1410+ list : '["A", "B", "C", "D"]' ,
1411+ } ,
1412+ } ) ;
1413+ } ) ;
1414+
1415+ it ( 'when argument passed in as list' , ( ) => {
1416+ const result = executeQueryWithFragmentArguments ( `
1417+ query Q($opValue: String = "op") {
1418+ ...a(aValue: "A")
1419+ }
1420+ fragment a($aValue: String, $bValue: String) on TestType {
1421+ ...b(aValue: [$aValue, "B"], bValue: [$bValue, $opValue])
1422+ }
1423+ fragment b($aValue: [String], $bValue: [String], $cValue: String) on TestType {
1424+ aList: list(input: $aValue)
1425+ bList: list(input: $bValue)
1426+ cList: list(input: [$cValue])
1427+ }
1428+ ` ) ;
1429+ expect ( result ) . to . deep . equal ( {
1430+ data : {
1431+ aList : '["A", "B"]' ,
1432+ bList : '[null, "op"]' ,
1433+ cList : '[null]' ,
1434+ } ,
1435+ } ) ;
1436+ } ) ;
1437+ } ) ;
11391438} ) ;
0 commit comments