Skip to content

Commit fa06509

Browse files
authored
polish: fix stream test cases (#4812)
-remove inadvertent double defers on some test operations -add inner-defer that triggers the actual test case requiring the rewriting of streamedFieldDetailsList
1 parent 0e1e368 commit fa06509

2 files changed

Lines changed: 80 additions & 5 deletions

File tree

src/execution/incremental/__tests__/stream-test.ts

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2324,6 +2324,28 @@ describe('Execute: stream directive', () => {
23242324
]);
23252325
});
23262326
it('Handles overlapping deferred and non-deferred streams', async () => {
2327+
// NOTE: This is an *invalid* query, but it should be an *executable* query.
2328+
// Validation rejects the overlapping @stream selections. See
2329+
// https://github.com/graphql/defer-stream-wg/discussions/100.
2330+
//
2331+
// The query selects the same stream field twice. The non-deferred selection
2332+
// asks for `id`. The deferred stream selection asks for `id`, `name`, and
2333+
// an inner deferred `innerName`.
2334+
//
2335+
// Stream item completion later sees one merged stream. Without rewriting
2336+
// the stream field details to clear inherited defer usage, `name` would be
2337+
// treated as still belonging to the outer @defer instead of to the stream
2338+
// item. The bad stream payload would be `items: [{ id: '1' }]` and then
2339+
// `items: [{ id: '2' }]`; the `name` fields would be dropped even though
2340+
// the `innerName` payloads would still be emitted.
2341+
//
2342+
// `getStreamUsage` avoids that by rewriting the stream field details to
2343+
// clear inherited defer usage before those details are reused to complete
2344+
// stream items.
2345+
//
2346+
// The inner @defer is included only because it forces stream item
2347+
// completion through execution planning. Without it, a fast path executes
2348+
// all collected fields directly and this bug would not be exposed.
23272349
const document = parse(`
23282350
query {
23292351
nestedObject {
@@ -2336,6 +2358,9 @@ describe('Execute: stream directive', () => {
23362358
nestedFriendList @stream(initialCount: 0) {
23372359
id
23382360
name
2361+
... @defer {
2362+
innerName: name
2363+
}
23392364
}
23402365
}
23412366
}
@@ -2360,29 +2385,43 @@ describe('Execute: stream directive', () => {
23602385
hasNext: true,
23612386
},
23622387
{
2388+
pending: [{ id: '1', path: ['nestedObject', 'nestedFriendList', 0] }],
23632389
incremental: [
23642390
{
23652391
items: [{ id: '1', name: 'Luke' }],
23662392
id: '0',
23672393
},
2394+
{
2395+
data: { innerName: 'Luke' },
2396+
id: '1',
2397+
},
23682398
],
2399+
completed: [{ id: '1' }],
23692400
hasNext: true,
23702401
},
23712402
{
2403+
pending: [{ id: '2', path: ['nestedObject', 'nestedFriendList', 1] }],
23722404
incremental: [
23732405
{
23742406
items: [{ id: '2', name: 'Han' }],
23752407
id: '0',
23762408
},
2409+
{
2410+
data: { innerName: 'Han' },
2411+
id: '2',
2412+
},
23772413
],
2378-
completed: [{ id: '0' }],
2414+
completed: [{ id: '0' }, { id: '2' }],
23792415
hasNext: false,
23802416
},
23812417
]);
23822418
});
23832419
it('Re-promotes a completed stream when a slower sibling defer resolves later', async () => {
23842420
const { promise: slowFieldPromise, resolve: resolveSlowField } =
23852421
promiseWithResolvers<string>();
2422+
// NOTE: This is an *invalid* query, but it should be an *executable* query.
2423+
// Validation rejects the overlapping @stream selections. See
2424+
// https://github.com/graphql/defer-stream-wg/discussions/100.
23862425
const document = parse(`
23872426
query {
23882427
nestedObject {
@@ -2584,7 +2623,7 @@ describe('Execute: stream directive', () => {
25842623
const document = parse(`
25852624
query {
25862625
friendList @stream(label:"stream-label") {
2587-
...NameFragment @defer(label: "DeferName") @defer(label: "DeferName")
2626+
...NameFragment @defer(label: "DeferName")
25882627
id
25892628
}
25902629
}
@@ -2689,7 +2728,7 @@ describe('Execute: stream directive', () => {
26892728
const document = parse(`
26902729
query {
26912730
friendList @stream(initialCount: 1, label:"stream-label") {
2692-
...NameFragment @defer(label: "DeferName") @defer(label: "DeferName")
2731+
...NameFragment @defer(label: "DeferName")
26932732
id
26942733
}
26952734
}

src/execution/legacyIncremental/__tests__/legacy-stream-test.ts

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2117,6 +2117,28 @@ describe('Execute: stream directive (legacy)', () => {
21172117
]);
21182118
});
21192119
it('Handles overlapping deferred and non-deferred streams', async () => {
2120+
// NOTE: This is an *invalid* query, but it should be an *executable* query.
2121+
// Validation rejects the overlapping @stream selections. See
2122+
// https://github.com/graphql/defer-stream-wg/discussions/100.
2123+
//
2124+
// The query selects the same stream field twice. The non-deferred selection
2125+
// asks for `id`. The deferred stream selection asks for `id`, `name`, and
2126+
// an inner deferred `innerName`.
2127+
//
2128+
// Stream item completion later sees one merged stream. Without rewriting
2129+
// the stream field details to clear inherited defer usage, `name` would be
2130+
// treated as still belonging to the outer @defer instead of to the stream
2131+
// item. The bad stream payload would be `items: [{ id: '1' }]` and then
2132+
// `items: [{ id: '2' }]`; the `name` fields would be dropped even though
2133+
// the `innerName` payloads would still be emitted.
2134+
//
2135+
// `getStreamUsage` avoids that by rewriting the stream field details to
2136+
// clear inherited defer usage before those details are reused to complete
2137+
// stream items.
2138+
//
2139+
// The inner @defer is included only because it forces stream item
2140+
// completion through execution planning. Without it, a fast path executes
2141+
// all collected fields directly and this bug would not be exposed.
21202142
const document = parse(`
21212143
query {
21222144
nestedObject {
@@ -2129,6 +2151,9 @@ describe('Execute: stream directive (legacy)', () => {
21292151
nestedFriendList @stream(initialCount: 0) {
21302152
id
21312153
name
2154+
... @defer {
2155+
innerName: name
2156+
}
21322157
}
21332158
}
21342159
}
@@ -2176,6 +2201,10 @@ describe('Execute: stream directive (legacy)', () => {
21762201
items: [{ id: '2' }],
21772202
path: ['nestedObject', 'nestedFriendList', 1],
21782203
},
2204+
{
2205+
data: { innerName: 'Luke' },
2206+
path: ['nestedObject', 'nestedFriendList', 0],
2207+
},
21792208
],
21802209
hasNext: true,
21812210
},
@@ -2185,6 +2214,10 @@ describe('Execute: stream directive (legacy)', () => {
21852214
items: [{ id: '2', name: 'Han' }],
21862215
path: ['nestedObject', 'nestedFriendList', 1],
21872216
},
2217+
{
2218+
data: { innerName: 'Han' },
2219+
path: ['nestedObject', 'nestedFriendList', 1],
2220+
},
21882221
],
21892222
hasNext: false,
21902223
},
@@ -2193,6 +2226,9 @@ describe('Execute: stream directive (legacy)', () => {
21932226
it('Re-promotes a completed stream when a slower sibling defer resolves later', async () => {
21942227
const { promise: slowFieldPromise, resolve: resolveSlowField } =
21952228
promiseWithResolvers<string>();
2229+
// NOTE: This is an *invalid* query, but it should be an *executable* query.
2230+
// Validation rejects the overlapping @stream selections. See
2231+
// https://github.com/graphql/defer-stream-wg/discussions/100.
21962232
const document = parse(`
21972233
query {
21982234
nestedObject {
@@ -2397,7 +2433,7 @@ describe('Execute: stream directive (legacy)', () => {
23972433
const document = parse(`
23982434
query {
23992435
friendList @stream(label:"stream-label") {
2400-
...NameFragment @defer(label: "DeferName") @defer(label: "DeferName")
2436+
...NameFragment @defer(label: "DeferName")
24012437
id
24022438
}
24032439
}
@@ -2500,7 +2536,7 @@ describe('Execute: stream directive (legacy)', () => {
25002536
const document = parse(`
25012537
query {
25022538
friendList @stream(initialCount: 1, label:"stream-label") {
2503-
...NameFragment @defer(label: "DeferName") @defer(label: "DeferName")
2539+
...NameFragment @defer(label: "DeferName")
25042540
id
25052541
}
25062542
}

0 commit comments

Comments
 (0)