@@ -1220,4 +1220,155 @@ describe('Execute: Handles basic execution tasks', () => {
12201220 expect ( result ) . to . deep . equal ( { data : { foo : { bar : 'bar' } } } ) ;
12211221 expect ( possibleTypes ) . to . deep . equal ( [ fooObject ] ) ;
12221222 } ) ;
1223+
1224+ it ( 'bubbles null up to nearest nullable parent' , ( ) => {
1225+ const schema = new GraphQLSchema ( {
1226+ query : new GraphQLObjectType ( {
1227+ name : 'Query' ,
1228+ fields : {
1229+ food : {
1230+ type : new GraphQLObjectType ( {
1231+ name : 'Food' ,
1232+ fields : {
1233+ name : { type : GraphQLString } ,
1234+ calories : { type : GraphQLInt } ,
1235+ } ,
1236+ } ) ,
1237+ resolve ( ) {
1238+ return {
1239+ name : null ,
1240+ calories : 10 ,
1241+ } ;
1242+ } ,
1243+ } ,
1244+ } ,
1245+ } ) ,
1246+ } ) ;
1247+
1248+ const plainDocument = parse ( `
1249+ query {
1250+ food {
1251+ name
1252+ calories
1253+ }
1254+ }
1255+ ` ) ;
1256+ const plainResult = executeSync ( { schema, document : plainDocument } ) ;
1257+
1258+ expect ( plainResult ) . to . deep . equal ( {
1259+ data : { food : { name : null , calories : 10 } } ,
1260+ } ) ;
1261+
1262+ const singleNonNullOnNullValueDocument = parse ( `
1263+ query {
1264+ food {
1265+ name!
1266+ calories
1267+ }
1268+ }
1269+ ` ) ;
1270+ const singleNonNullOnNullValueResult = executeSync ( {
1271+ schema,
1272+ document : singleNonNullOnNullValueDocument ,
1273+ } ) ;
1274+
1275+ expect ( singleNonNullOnNullValueResult ) . to . deep . equal ( {
1276+ data : { food : null } ,
1277+ errors : [
1278+ {
1279+ locations : [ { column : 11 , line : 4 } ] ,
1280+ message : 'Cannot return null for non-nullable field Food.name.' ,
1281+ path : [ 'food' , 'name' ] ,
1282+ } ,
1283+ ] ,
1284+ } ) ;
1285+
1286+ const bothNonNullOnNullValueDocument = parse ( `
1287+ query {
1288+ food {
1289+ name!
1290+ calories!
1291+ }
1292+ }
1293+ ` ) ;
1294+ const bothNonNullOnNullValueResult = executeSync ( {
1295+ schema,
1296+ document : bothNonNullOnNullValueDocument ,
1297+ } ) ;
1298+
1299+ expect ( bothNonNullOnNullValueResult ) . to . deep . equal ( {
1300+ data : { food : null } ,
1301+ errors : [
1302+ {
1303+ locations : [ { column : 11 , line : 4 } ] ,
1304+ message : 'Cannot return null for non-nullable field Food.name.' ,
1305+ path : [ 'food' , 'name' ] ,
1306+ } ,
1307+ ] ,
1308+ } ) ;
1309+
1310+ const singleNonNullOnNonNullValueDocument = parse ( `
1311+ query {
1312+ food {
1313+ calories!
1314+ }
1315+ }
1316+ ` ) ;
1317+ const singleNonNullOnNonNullValueResult = executeSync ( {
1318+ schema,
1319+ document : singleNonNullOnNonNullValueDocument ,
1320+ } ) ;
1321+
1322+ expect ( singleNonNullOnNonNullValueResult ) . to . deep . equal ( {
1323+ data : { food : { calories : 10 } } ,
1324+ } ) ;
1325+
1326+ const nonNullAliasOnNullValueDocument = parse ( `
1327+ query {
1328+ food {
1329+ theNameOfTheFood: name!
1330+ }
1331+ }
1332+ ` ) ;
1333+ const nonNullAliasOnNullValueResult = executeSync ( {
1334+ schema,
1335+ document : nonNullAliasOnNullValueDocument ,
1336+ } ) ;
1337+
1338+ expect ( nonNullAliasOnNullValueResult ) . to . deep . equal ( {
1339+ data : { food : null } ,
1340+ errors : [
1341+ {
1342+ locations : [ { column : 11 , line : 4 } ] ,
1343+ message : 'Cannot return null for non-nullable field Food.name.' ,
1344+ path : [ 'food' , 'theNameOfTheFood' ] ,
1345+ } ,
1346+ ] ,
1347+ } ) ;
1348+
1349+ const nonNullInFragmentDocument = parse ( `
1350+ query {
1351+ food {
1352+ ... on Food {
1353+ name!
1354+ }
1355+ }
1356+ }
1357+ ` ) ;
1358+ const nonNullInFragmentResult = executeSync ( {
1359+ schema,
1360+ document : nonNullInFragmentDocument ,
1361+ } ) ;
1362+
1363+ expect ( nonNullInFragmentResult ) . to . deep . equal ( {
1364+ data : { food : null } ,
1365+ errors : [
1366+ {
1367+ locations : [ { column : 13 , line : 5 } ] ,
1368+ message : 'Cannot return null for non-nullable field Food.name.' ,
1369+ path : [ 'food' , 'name' ] ,
1370+ } ,
1371+ ] ,
1372+ } ) ;
1373+ } ) ;
12231374} ) ;
0 commit comments