@@ -56,6 +56,8 @@ const QueryRootType = new GraphQLObjectType({
5656} ) ;
5757
5858const TestSchema = new GraphQLSchema ( {
59+ experimentalDefer : true ,
60+ experimentalStream : true ,
5961 query : QueryRootType ,
6062 mutation : new GraphQLObjectType ( {
6163 name : 'MutationRoot' ,
@@ -1027,6 +1029,54 @@ function runTests(server: Server) {
10271029 errors : [ { message : 'Must provide query string.' } ] ,
10281030 } ) ;
10291031 } ) ;
1032+
1033+ it ( 'allows for streaming results with @defer' , async ( ) => {
1034+ const app = server ( ) ;
1035+
1036+ app . post (
1037+ urlString ( ) ,
1038+ graphqlHTTP ( {
1039+ schema : TestSchema ,
1040+ } ) ,
1041+ ) ;
1042+
1043+ const req = app
1044+ . request ( )
1045+ . post ( urlString ( ) )
1046+ . send ( {
1047+ query :
1048+ '{ ...frag @defer(label: "deferLabel") } fragment frag on QueryRoot { test(who: "World") }' ,
1049+ } )
1050+ . parse ( ( res , cb ) => {
1051+ res . on ( 'data' , ( data ) => {
1052+ res . text = `${ res . text || '' } ${ data . toString ( 'utf8' ) as string } ` ;
1053+ } ) ;
1054+ res . on ( 'end' , ( err ) => {
1055+ cb ( err , null ) ;
1056+ } ) ;
1057+ } ) ;
1058+
1059+ const response = await req ;
1060+ expect ( response . text ) . to . equal (
1061+ [
1062+ '' ,
1063+ '---' ,
1064+ 'Content-Type: application/json; charset=utf-8' ,
1065+ 'Content-Length: 26' ,
1066+ '' ,
1067+ '{"data":{},"hasNext":true}' ,
1068+ '' ,
1069+ '---' ,
1070+ 'Content-Type: application/json; charset=utf-8' ,
1071+ 'Content-Length: 78' ,
1072+ '' ,
1073+ '{"data":{"test":"Hello World"},"path":[],"label":"deferLabel","hasNext":false}' ,
1074+ '' ,
1075+ '-----' ,
1076+ '' ,
1077+ ] . join ( '\r\n' ) ,
1078+ ) ;
1079+ } ) ;
10301080 } ) ;
10311081
10321082 describe ( 'Pretty printing' , ( ) => {
@@ -1109,6 +1159,62 @@ function runTests(server: Server) {
11091159
11101160 expect ( unprettyResponse . text ) . to . equal ( '{"data":{"test":"Hello World"}}' ) ;
11111161 } ) ;
1162+ it ( 'supports pretty printing async iterable requests' , async ( ) => {
1163+ const app = server ( ) ;
1164+
1165+ app . post (
1166+ urlString ( ) ,
1167+ graphqlHTTP ( {
1168+ schema : TestSchema ,
1169+ pretty : true ,
1170+ } ) ,
1171+ ) ;
1172+
1173+ const req = app
1174+ . request ( )
1175+ . post ( urlString ( ) )
1176+ . send ( {
1177+ query :
1178+ '{ ...frag @defer } fragment frag on QueryRoot { test(who: "World") }' ,
1179+ } )
1180+ . parse ( ( res , cb ) => {
1181+ res . on ( 'data' , ( data ) => {
1182+ res . text = `${ res . text || '' } ${ data . toString ( 'utf8' ) as string } ` ;
1183+ } ) ;
1184+ res . on ( 'end' , ( err ) => {
1185+ cb ( err , null ) ;
1186+ } ) ;
1187+ } ) ;
1188+
1189+ const response = await req ;
1190+ expect ( response . text ) . to . equal (
1191+ [
1192+ '' ,
1193+ '---' ,
1194+ 'Content-Type: application/json; charset=utf-8' ,
1195+ 'Content-Length: 35' ,
1196+ '' ,
1197+ [ '{' , ' "data": {},' , ' "hasNext": true' , '}' ] . join ( '\n' ) ,
1198+ '' ,
1199+ '---' ,
1200+ 'Content-Type: application/json; charset=utf-8' ,
1201+ 'Content-Length: 79' ,
1202+ '' ,
1203+ [
1204+ '{' ,
1205+ ' "data": {' ,
1206+ ' "test": "Hello World"' ,
1207+ ' },' ,
1208+ ' "path": [],' ,
1209+ ' "hasNext": false' ,
1210+ '}' ,
1211+ ] . join ( '\n' ) ,
1212+ '' ,
1213+ '-----' ,
1214+ '' ,
1215+ ] . join ( '\r\n' ) ,
1216+ ) ;
1217+ } ) ;
11121218 } ) ;
11131219
11141220 it ( 'will send request and response when using thunk' , async ( ) => {
@@ -1229,6 +1335,108 @@ function runTests(server: Server) {
12291335 } ) ;
12301336 } ) ;
12311337
1338+ it ( 'allows for custom error formatting in initial payload of async iterator' , async ( ) => {
1339+ const app = server ( ) ;
1340+
1341+ app . post (
1342+ urlString ( ) ,
1343+ graphqlHTTP ( {
1344+ schema : TestSchema ,
1345+ customFormatErrorFn ( error ) {
1346+ return { message : 'Custom error format: ' + error . message } ;
1347+ } ,
1348+ } ) ,
1349+ ) ;
1350+
1351+ const req = app
1352+ . request ( )
1353+ . post ( urlString ( ) )
1354+ . send ( {
1355+ query :
1356+ '{ thrower, ...frag @defer } fragment frag on QueryRoot { test(who: "World") }' ,
1357+ } )
1358+ . parse ( ( res , cb ) => {
1359+ res . on ( 'data' , ( data ) => {
1360+ res . text = `${ res . text || '' } ${ data . toString ( 'utf8' ) as string } ` ;
1361+ } ) ;
1362+ res . on ( 'end' , ( err ) => {
1363+ cb ( err , null ) ;
1364+ } ) ;
1365+ } ) ;
1366+
1367+ const response = await req ;
1368+ expect ( response . text ) . to . equal (
1369+ [
1370+ '' ,
1371+ '---' ,
1372+ 'Content-Type: application/json; charset=utf-8' ,
1373+ 'Content-Length: 94' ,
1374+ '' ,
1375+ '{"errors":[{"message":"Custom error format: Throws!"}],"data":{"thrower":null},"hasNext":true}' ,
1376+ '' ,
1377+ '---' ,
1378+ 'Content-Type: application/json; charset=utf-8' ,
1379+ 'Content-Length: 57' ,
1380+ '' ,
1381+ '{"data":{"test":"Hello World"},"path":[],"hasNext":false}' ,
1382+ '' ,
1383+ '-----' ,
1384+ '' ,
1385+ ] . join ( '\r\n' ) ,
1386+ ) ;
1387+ } ) ;
1388+
1389+ it ( 'allows for custom error formatting in subsequent payloads of async iterator' , async ( ) => {
1390+ const app = server ( ) ;
1391+
1392+ app . post (
1393+ urlString ( ) ,
1394+ graphqlHTTP ( {
1395+ schema : TestSchema ,
1396+ customFormatErrorFn ( error ) {
1397+ return { message : 'Custom error format: ' + error . message } ;
1398+ } ,
1399+ } ) ,
1400+ ) ;
1401+
1402+ const req = app
1403+ . request ( )
1404+ . post ( urlString ( ) )
1405+ . send ( {
1406+ query :
1407+ '{ test(who: "World"), ...frag @defer } fragment frag on QueryRoot { thrower }' ,
1408+ } )
1409+ . parse ( ( res , cb ) => {
1410+ res . on ( 'data' , ( data ) => {
1411+ res . text = `${ res . text || '' } ${ data . toString ( 'utf8' ) as string } ` ;
1412+ } ) ;
1413+ res . on ( 'end' , ( err ) => {
1414+ cb ( err , null ) ;
1415+ } ) ;
1416+ } ) ;
1417+
1418+ const response = await req ;
1419+ expect ( response . text ) . to . equal (
1420+ [
1421+ '' ,
1422+ '---' ,
1423+ 'Content-Type: application/json; charset=utf-8' ,
1424+ 'Content-Length: 46' ,
1425+ '' ,
1426+ '{"data":{"test":"Hello World"},"hasNext":true}' ,
1427+ '' ,
1428+ '---' ,
1429+ 'Content-Type: application/json; charset=utf-8' ,
1430+ 'Content-Length: 105' ,
1431+ '' ,
1432+ '{"data":{"thrower":null},"path":[],"errors":[{"message":"Custom error format: Throws!"}],"hasNext":false}' ,
1433+ '' ,
1434+ '-----' ,
1435+ '' ,
1436+ ] . join ( '\r\n' ) ,
1437+ ) ;
1438+ } ) ;
1439+
12321440 it ( 'allows for custom error formatting to elaborate' , async ( ) => {
12331441 const app = server ( ) ;
12341442
@@ -2220,6 +2428,57 @@ function runTests(server: Server) {
22202428 } ) ;
22212429 } ) ;
22222430
2431+ it ( 'allows for custom extensions in initial and subsequent payloads of async iterator' , async ( ) => {
2432+ const app = server ( ) ;
2433+
2434+ app . post (
2435+ urlString ( ) ,
2436+ graphqlHTTP ( {
2437+ schema : TestSchema ,
2438+ extensions ( { result } ) {
2439+ return { preservedResult : { ...result } } ;
2440+ } ,
2441+ } ) ,
2442+ ) ;
2443+
2444+ const req = app
2445+ . request ( )
2446+ . post ( urlString ( ) )
2447+ . send ( {
2448+ query :
2449+ '{ hello: test(who: "Rob"), ...frag @defer } fragment frag on QueryRoot { test(who: "World") }' ,
2450+ } )
2451+ . parse ( ( res , cb ) => {
2452+ res . on ( 'data' , ( data ) => {
2453+ res . text = `${ res . text || '' } ${ data . toString ( 'utf8' ) as string } ` ;
2454+ } ) ;
2455+ res . on ( 'end' , ( err ) => {
2456+ cb ( err , null ) ;
2457+ } ) ;
2458+ } ) ;
2459+
2460+ const response = await req ;
2461+ expect ( response . text ) . to . equal (
2462+ [
2463+ '' ,
2464+ '---' ,
2465+ 'Content-Type: application/json; charset=utf-8' ,
2466+ 'Content-Length: 124' ,
2467+ '' ,
2468+ '{"data":{"hello":"Hello Rob"},"hasNext":true,"extensions":{"preservedResult":{"data":{"hello":"Hello Rob"},"hasNext":true}}}' ,
2469+ '' ,
2470+ '---' ,
2471+ 'Content-Type: application/json; charset=utf-8' ,
2472+ 'Content-Length: 148' ,
2473+ '' ,
2474+ '{"data":{"test":"Hello World"},"path":[],"hasNext":false,"extensions":{"preservedResult":{"data":{"test":"Hello World"},"path":[],"hasNext":false}}}' ,
2475+ '' ,
2476+ '-----' ,
2477+ '' ,
2478+ ] . join ( '\r\n' ) ,
2479+ ) ;
2480+ } ) ;
2481+
22232482 it ( 'extension function may be async' , async ( ) => {
22242483 const app = server ( ) ;
22252484
@@ -2260,12 +2519,44 @@ function runTests(server: Server) {
22602519
22612520 const response = await app
22622521 . request ( )
2263- . get ( urlString ( { query : '{test}' , raw : '' } ) )
2264- . set ( 'Accept' , 'text/html' ) ;
2522+ . get (
2523+ urlString ( {
2524+ query :
2525+ '{ hello: test(who: "Rob"), ...frag @defer } fragment frag on QueryRoot { test(who: "World") }' ,
2526+ raw : '' ,
2527+ } ) ,
2528+ )
2529+ . set ( 'Accept' , 'text/html' )
2530+ . parse ( ( res , cb ) => {
2531+ res . on ( 'data' , ( data ) => {
2532+ res . text = `${ res . text || '' } ${ data . toString ( 'utf8' ) as string } ` ;
2533+ } ) ;
2534+ res . on ( 'end' , ( err ) => {
2535+ cb ( err , null ) ;
2536+ } ) ;
2537+ } ) ;
22652538
22662539 expect ( response . status ) . to . equal ( 200 ) ;
2267- expect ( response . type ) . to . equal ( 'application/json' ) ;
2268- expect ( response . text ) . to . equal ( '{"data":{"test":"Hello World"}}' ) ;
2540+ expect ( response . type ) . to . equal ( 'multipart/mixed' ) ;
2541+ expect ( response . text ) . to . equal (
2542+ [
2543+ '' ,
2544+ '---' ,
2545+ 'Content-Type: application/json; charset=utf-8' ,
2546+ 'Content-Length: 45' ,
2547+ '' ,
2548+ '{"data":{"hello":"Hello Rob"},"hasNext":true}' ,
2549+ '' ,
2550+ '---' ,
2551+ 'Content-Type: application/json; charset=utf-8' ,
2552+ 'Content-Length: 57' ,
2553+ '' ,
2554+ '{"data":{"test":"Hello World"},"path":[],"hasNext":false}' ,
2555+ '' ,
2556+ '-----' ,
2557+ '' ,
2558+ ] . join ( '\r\n' ) ,
2559+ ) ;
22692560 } ) ;
22702561 } ) ;
22712562}
0 commit comments