1
- // eslint-disable-next-line import/no-extraneous-dependencies
1
+
2
2
import { inspect } from 'cross-inspect' ;
3
3
import {
4
4
GraphQLArgumentConfig ,
@@ -30,6 +30,13 @@ const TestComplexScalar = new GraphQLScalarType({
30
30
} ,
31
31
} ) ;
32
32
33
+ const NestedType : GraphQLObjectType = new GraphQLObjectType ( {
34
+ name : 'NestedType' ,
35
+ fields : {
36
+ echo : fieldWithInputArg ( { type : GraphQLString } ) ,
37
+ } ,
38
+ } ) ;
39
+
33
40
const TestInputObject = new GraphQLInputObjectType ( {
34
41
name : 'TestInputObject' ,
35
42
fields : {
@@ -98,6 +105,10 @@ const TestType = new GraphQLObjectType({
98
105
defaultValue : 'Hello World' ,
99
106
} ) ,
100
107
list : fieldWithInputArg ( { type : new GraphQLList ( GraphQLString ) } ) ,
108
+ nested : {
109
+ type : NestedType ,
110
+ resolve : ( ) => ( { } ) ,
111
+ } ,
101
112
nnList : fieldWithInputArg ( {
102
113
type : new GraphQLNonNull ( new GraphQLList ( GraphQLString ) ) ,
103
114
} ) ,
@@ -117,6 +128,16 @@ function executeQuery(query: string, variableValues?: { [variable: string]: unkn
117
128
return executeSync ( { schema, document, variableValues } ) ;
118
129
}
119
130
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
+
120
141
describe ( 'Execute: Handles inputs' , ( ) => {
121
142
describe ( 'Handles objects and nullability' , ( ) => {
122
143
describe ( 'using inline structs' , ( ) => {
@@ -1038,4 +1059,283 @@ describe('Execute: Handles inputs', () => {
1038
1059
} ) ;
1039
1060
} ) ;
1040
1061
} ) ;
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
+ / 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 ! " / ,
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
+ / 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 ! " / ,
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
+ } ) ;
1041
1341
} ) ;
0 commit comments