@@ -60,6 +60,13 @@ const TestComplexScalar = new GraphQLScalarType({
6060 } ,
6161} ) ;
6262
63+ const NestedType : GraphQLObjectType = new GraphQLObjectType ( {
64+ name : 'NestedType' ,
65+ fields : {
66+ echo : fieldWithInputArg ( { type : GraphQLString } ) ,
67+ } ,
68+ } ) ;
69+
6370const TestInputObject = new GraphQLInputObjectType ( {
6471 name : 'TestInputObject' ,
6572 fields : {
@@ -129,6 +136,10 @@ const TestType = new GraphQLObjectType({
129136 type : TestNestedInputObject ,
130137 defaultValue : 'Hello World' ,
131138 } ) ,
139+ nested : {
140+ type : NestedType ,
141+ resolve : ( ) => ( { } ) ,
142+ } ,
132143 list : fieldWithInputArg ( { type : new GraphQLList ( GraphQLString ) } ) ,
133144 nnList : fieldWithInputArg ( {
134145 type : new GraphQLNonNull ( new GraphQLList ( GraphQLString ) ) ,
@@ -154,6 +165,14 @@ function executeQuery(
154165 return executeSync ( { schema, document, variableValues } ) ;
155166}
156167
168+ function executeQueryWithFragmentArguments (
169+ query : string ,
170+ variableValues ?: { [ variable : string ] : unknown } ,
171+ ) {
172+ const document = parse ( query , { experimentalFragmentArguments : true } ) ;
173+ return executeSync ( { schema, document, variableValues } ) ;
174+ }
175+
157176describe ( 'Execute: Handles inputs' , ( ) => {
158177 describe ( 'Handles objects and nullability' , ( ) => {
159178 describe ( 'using inline structs' , ( ) => {
@@ -1136,4 +1155,283 @@ 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 ?. [ 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 ?. [ 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+ fragment b on TestType {
1336+ fieldWithNullableStringInput(input: $x)
1337+ }
1338+ ` ) ;
1339+ expect ( result ) . to . deep . equal ( {
1340+ data : {
1341+ fieldWithNullableStringInput : '"A"' ,
1342+ } ,
1343+ } ) ;
1344+ } ) ;
1345+
1346+ it ( 'when a fragment is used with different args' , ( ) => {
1347+ const result = executeQueryWithFragmentArguments ( `
1348+ query($x: String = "Hello") {
1349+ a: nested {
1350+ ...a(x: "a")
1351+ }
1352+ b: nested {
1353+ ...a(x: "b", b: true)
1354+ }
1355+ hello: nested {
1356+ ...a(x: $x)
1357+ }
1358+ }
1359+ fragment a($x: String, $b: Boolean = false) on NestedType {
1360+ a: echo(input: $x) @skip(if: $b)
1361+ b: echo(input: $x) @include(if: $b)
1362+ }
1363+ ` ) ;
1364+ expect ( result ) . to . deep . equal ( {
1365+ data : {
1366+ a : {
1367+ a : '"a"' ,
1368+ } ,
1369+ b : {
1370+ b : '"b"' ,
1371+ } ,
1372+ hello : {
1373+ a : '"Hello"' ,
1374+ } ,
1375+ } ,
1376+ } ) ;
1377+ } ) ;
1378+
1379+ it ( 'when the argument variable is nested in a complex type' , ( ) => {
1380+ const result = executeQueryWithFragmentArguments ( `
1381+ query {
1382+ ...a(value: "C")
1383+ }
1384+ fragment a($value: String) on TestType {
1385+ list(input: ["A", "B", $value, "D"])
1386+ }
1387+ ` ) ;
1388+ expect ( result ) . to . deep . equal ( {
1389+ data : {
1390+ list : '["A", "B", "C", "D"]' ,
1391+ } ,
1392+ } ) ;
1393+ } ) ;
1394+
1395+ it ( 'when argument variables are used recursively' , ( ) => {
1396+ const result = executeQueryWithFragmentArguments ( `
1397+ query {
1398+ ...a(aValue: "C")
1399+ }
1400+ fragment a($aValue: String) on TestType {
1401+ ...b(bValue: $aValue)
1402+ }
1403+ fragment b($bValue: String) on TestType {
1404+ list(input: ["A", "B", $bValue, "D"])
1405+ }
1406+ ` ) ;
1407+ expect ( result ) . to . deep . equal ( {
1408+ data : {
1409+ list : '["A", "B", "C", "D"]' ,
1410+ } ,
1411+ } ) ;
1412+ } ) ;
1413+
1414+ it ( 'when argument passed in as list' , ( ) => {
1415+ const result = executeQueryWithFragmentArguments ( `
1416+ query Q($opValue: String = "op") {
1417+ ...a(aValue: "A")
1418+ }
1419+ fragment a($aValue: String, $bValue: String) on TestType {
1420+ ...b(aValue: [$aValue, "B"], bValue: [$bValue, $opValue])
1421+ }
1422+ fragment b($aValue: [String], $bValue: [String], $cValue: String) on TestType {
1423+ aList: list(input: $aValue)
1424+ bList: list(input: $bValue)
1425+ cList: list(input: [$cValue])
1426+ }
1427+ ` ) ;
1428+ expect ( result ) . to . deep . equal ( {
1429+ data : {
1430+ aList : '["A", "B"]' ,
1431+ bList : '[null, "op"]' ,
1432+ cList : '[null]' ,
1433+ } ,
1434+ } ) ;
1435+ } ) ;
1436+ } ) ;
11391437} ) ;
0 commit comments