Skip to content
This repository was archived by the owner on Mar 20, 2023. It is now read-only.

Commit 2492b68

Browse files
committed
support for experimental defer-stream
1 parent b11d9bc commit 2492b68

File tree

4 files changed

+381
-18
lines changed

4 files changed

+381
-18
lines changed

package-lock.json

Lines changed: 2 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@
7878
"express": "4.17.1",
7979
"flow-bin": "0.126.1",
8080
"graphiql": "0.17.5",
81-
"graphql": "15.1.0",
81+
"graphql": "https://registry.npmjs.org/graphql-experimental/-/graphql-experimental-3.0.1.tgz",
8282
"mocha": "7.2.0",
8383
"multer": "1.4.2",
8484
"nyc": "15.1.0",

src/__tests__/http-test.ts

Lines changed: 259 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@ const QueryRootType = new GraphQLObjectType({
5656
});
5757

5858
const TestSchema = new GraphQLSchema({
59+
experimentalDefer: true,
60+
experimentalStream: true,
5961
query: QueryRootType,
6062
mutation: new GraphQLObjectType({
6163
name: 'MutationRoot',
@@ -1022,6 +1024,54 @@ function runTests(server: Server) {
10221024
errors: [{ message: 'Must provide query string.' }],
10231025
});
10241026
});
1027+
1028+
it('allows for streaming results with @defer', async () => {
1029+
const app = server();
1030+
1031+
app.post(
1032+
urlString(),
1033+
graphqlHTTP({
1034+
schema: TestSchema,
1035+
}),
1036+
);
1037+
1038+
const req = app
1039+
.request()
1040+
.post(urlString())
1041+
.send({
1042+
query:
1043+
'{ ...frag @defer(label: "deferLabel") } fragment frag on QueryRoot { test(who: "World") }',
1044+
})
1045+
.parse((res, cb) => {
1046+
res.on('data', (data) => {
1047+
res.text = `${res.text || ''}${data.toString('utf8') as string}`;
1048+
});
1049+
res.on('end', (err) => {
1050+
cb(err, null);
1051+
});
1052+
});
1053+
1054+
const response = await req;
1055+
expect(response.text).to.equal(
1056+
[
1057+
'',
1058+
'---',
1059+
'Content-Type: application/json; charset=utf-8',
1060+
'Content-Length: 26',
1061+
'',
1062+
'{"data":{},"hasNext":true}',
1063+
'',
1064+
'---',
1065+
'Content-Type: application/json; charset=utf-8',
1066+
'Content-Length: 78',
1067+
'',
1068+
'{"data":{"test":"Hello World"},"path":[],"label":"deferLabel","hasNext":false}',
1069+
'',
1070+
'-----',
1071+
'',
1072+
].join('\r\n'),
1073+
);
1074+
});
10251075
});
10261076

10271077
describe('Pretty printing', () => {
@@ -1104,6 +1154,62 @@ function runTests(server: Server) {
11041154

11051155
expect(unprettyResponse.text).to.equal('{"data":{"test":"Hello World"}}');
11061156
});
1157+
it('supports pretty printing async iterable requests', async () => {
1158+
const app = server();
1159+
1160+
app.post(
1161+
urlString(),
1162+
graphqlHTTP({
1163+
schema: TestSchema,
1164+
pretty: true,
1165+
}),
1166+
);
1167+
1168+
const req = app
1169+
.request()
1170+
.post(urlString())
1171+
.send({
1172+
query:
1173+
'{ ...frag @defer } fragment frag on QueryRoot { test(who: "World") }',
1174+
})
1175+
.parse((res, cb) => {
1176+
res.on('data', (data) => {
1177+
res.text = `${res.text || ''}${data.toString('utf8') as string}`;
1178+
});
1179+
res.on('end', (err) => {
1180+
cb(err, null);
1181+
});
1182+
});
1183+
1184+
const response = await req;
1185+
expect(response.text).to.equal(
1186+
[
1187+
'',
1188+
'---',
1189+
'Content-Type: application/json; charset=utf-8',
1190+
'Content-Length: 35',
1191+
'',
1192+
['{', ' "data": {},', ' "hasNext": true', '}'].join('\n'),
1193+
'',
1194+
'---',
1195+
'Content-Type: application/json; charset=utf-8',
1196+
'Content-Length: 79',
1197+
'',
1198+
[
1199+
'{',
1200+
' "data": {',
1201+
' "test": "Hello World"',
1202+
' },',
1203+
' "path": [],',
1204+
' "hasNext": false',
1205+
'}',
1206+
].join('\n'),
1207+
'',
1208+
'-----',
1209+
'',
1210+
].join('\r\n'),
1211+
);
1212+
});
11071213
});
11081214

11091215
it('will send request and response when using thunk', async () => {
@@ -1224,6 +1330,108 @@ function runTests(server: Server) {
12241330
});
12251331
});
12261332

1333+
it('allows for custom error formatting in initial payload of async iterator', async () => {
1334+
const app = server();
1335+
1336+
app.post(
1337+
urlString(),
1338+
graphqlHTTP({
1339+
schema: TestSchema,
1340+
customFormatErrorFn(error) {
1341+
return { message: 'Custom error format: ' + error.message };
1342+
},
1343+
}),
1344+
);
1345+
1346+
const req = app
1347+
.request()
1348+
.post(urlString())
1349+
.send({
1350+
query:
1351+
'{ thrower, ...frag @defer } fragment frag on QueryRoot { test(who: "World") }',
1352+
})
1353+
.parse((res, cb) => {
1354+
res.on('data', (data) => {
1355+
res.text = `${res.text || ''}${data.toString('utf8') as string}`;
1356+
});
1357+
res.on('end', (err) => {
1358+
cb(err, null);
1359+
});
1360+
});
1361+
1362+
const response = await req;
1363+
expect(response.text).to.equal(
1364+
[
1365+
'',
1366+
'---',
1367+
'Content-Type: application/json; charset=utf-8',
1368+
'Content-Length: 94',
1369+
'',
1370+
'{"errors":[{"message":"Custom error format: Throws!"}],"data":{"thrower":null},"hasNext":true}',
1371+
'',
1372+
'---',
1373+
'Content-Type: application/json; charset=utf-8',
1374+
'Content-Length: 57',
1375+
'',
1376+
'{"data":{"test":"Hello World"},"path":[],"hasNext":false}',
1377+
'',
1378+
'-----',
1379+
'',
1380+
].join('\r\n'),
1381+
);
1382+
});
1383+
1384+
it('allows for custom error formatting in subsequent payloads of async iterator', async () => {
1385+
const app = server();
1386+
1387+
app.post(
1388+
urlString(),
1389+
graphqlHTTP({
1390+
schema: TestSchema,
1391+
customFormatErrorFn(error) {
1392+
return { message: 'Custom error format: ' + error.message };
1393+
},
1394+
}),
1395+
);
1396+
1397+
const req = app
1398+
.request()
1399+
.post(urlString())
1400+
.send({
1401+
query:
1402+
'{ test(who: "World"), ...frag @defer } fragment frag on QueryRoot { thrower }',
1403+
})
1404+
.parse((res, cb) => {
1405+
res.on('data', (data) => {
1406+
res.text = `${res.text || ''}${data.toString('utf8') as string}`;
1407+
});
1408+
res.on('end', (err) => {
1409+
cb(err, null);
1410+
});
1411+
});
1412+
1413+
const response = await req;
1414+
expect(response.text).to.equal(
1415+
[
1416+
'',
1417+
'---',
1418+
'Content-Type: application/json; charset=utf-8',
1419+
'Content-Length: 46',
1420+
'',
1421+
'{"data":{"test":"Hello World"},"hasNext":true}',
1422+
'',
1423+
'---',
1424+
'Content-Type: application/json; charset=utf-8',
1425+
'Content-Length: 105',
1426+
'',
1427+
'{"data":{"thrower":null},"path":[],"errors":[{"message":"Custom error format: Throws!"}],"hasNext":false}',
1428+
'',
1429+
'-----',
1430+
'',
1431+
].join('\r\n'),
1432+
);
1433+
});
1434+
12271435
it('allows for custom error formatting to elaborate', async () => {
12281436
const app = server();
12291437

@@ -2215,6 +2423,57 @@ function runTests(server: Server) {
22152423
});
22162424
});
22172425

2426+
it('allows for custom extensions in initial and subsequent payloads of async iterator', async () => {
2427+
const app = server();
2428+
2429+
app.post(
2430+
urlString(),
2431+
graphqlHTTP({
2432+
schema: TestSchema,
2433+
extensions({ result }) {
2434+
return { preservedResult: { ...result } };
2435+
},
2436+
}),
2437+
);
2438+
2439+
const req = app
2440+
.request()
2441+
.post(urlString())
2442+
.send({
2443+
query:
2444+
'{ hello: test(who: "Rob"), ...frag @defer } fragment frag on QueryRoot { test(who: "World") }',
2445+
})
2446+
.parse((res, cb) => {
2447+
res.on('data', (data) => {
2448+
res.text = `${res.text || ''}${data.toString('utf8') as string}`;
2449+
});
2450+
res.on('end', (err) => {
2451+
cb(err, null);
2452+
});
2453+
});
2454+
2455+
const response = await req;
2456+
expect(response.text).to.equal(
2457+
[
2458+
'',
2459+
'---',
2460+
'Content-Type: application/json; charset=utf-8',
2461+
'Content-Length: 124',
2462+
'',
2463+
'{"data":{"hello":"Hello Rob"},"hasNext":true,"extensions":{"preservedResult":{"data":{"hello":"Hello Rob"},"hasNext":true}}}',
2464+
'',
2465+
'---',
2466+
'Content-Type: application/json; charset=utf-8',
2467+
'Content-Length: 148',
2468+
'',
2469+
'{"data":{"test":"Hello World"},"path":[],"hasNext":false,"extensions":{"preservedResult":{"data":{"test":"Hello World"},"path":[],"hasNext":false}}}',
2470+
'',
2471+
'-----',
2472+
'',
2473+
].join('\r\n'),
2474+
);
2475+
});
2476+
22182477
it('extension function may be async', async () => {
22192478
const app = server();
22202479

0 commit comments

Comments
 (0)