@@ -119,4 +119,102 @@ describe('handleEventStreamResponse', () => {
119
119
value : undefined ,
120
120
} ) ;
121
121
} ) ;
122
+
123
+ it . skipIf (
124
+ // we skip bun because we cant cancel the stream while reading it (it's locked)
125
+ // however, the same test from nodejs applies in bun
126
+ globalThis . Bun ,
127
+ ) ( 'should gracefully report stream cancel with aborted signal' , async ( ) => {
128
+ const ctrl = new AbortController ( ) ;
129
+ const readableStream = new ReadableStream < Uint8Array > ( {
130
+ start ( ) {
131
+ // dont enqueue anything, to hang on iterator.next()
132
+ } ,
133
+ } ) ;
134
+
135
+ const response = new Response ( readableStream ) ;
136
+ const asyncIterable = handleEventStreamResponse (
137
+ response ,
138
+ undefined ,
139
+ ctrl . signal ,
140
+ ) ;
141
+ const iterator = asyncIterable [ Symbol . asyncIterator ] ( ) ;
142
+
143
+ Promise . resolve ( ) . then ( ( ) => {
144
+ ctrl . abort ( ) ; // we abort
145
+ readableStream . cancel ( ) ; // then cancel
146
+ // so that the error reported is the abort error
147
+ } ) ;
148
+
149
+ await expect ( iterator . next ( ) ) . resolves . toMatchInlineSnapshot ( `
150
+ {
151
+ "done": false,
152
+ "value": {
153
+ "errors": [
154
+ [GraphQLError: This operation was aborted],
155
+ ],
156
+ },
157
+ }
158
+ ` ) ;
159
+
160
+ await expect ( iterator . next ( ) ) . resolves . toMatchInlineSnapshot ( `
161
+ {
162
+ "done": true,
163
+ "value": undefined,
164
+ }
165
+ ` ) ;
166
+
167
+ await expect ( iterator . return ( ) ) . resolves . toMatchInlineSnapshot ( `
168
+ {
169
+ "done": true,
170
+ "value": undefined,
171
+ }
172
+ ` ) ;
173
+ } ) ;
174
+
175
+ it . skipIf (
176
+ // we skip bun because we cant cancel the stream while reading it (it's locked)
177
+ // however, the same test from nodejs applies in bun
178
+ globalThis . Bun ,
179
+ ) ( 'should gracefully report stream errors' , async ( ) => {
180
+ const readableStream = new ReadableStream < Uint8Array > ( {
181
+ start ( ) {
182
+ // dont enqueue anything, to hang on iterator.next()
183
+ } ,
184
+ } ) ;
185
+
186
+ const response = new Response ( readableStream ) ;
187
+ const asyncIterable = handleEventStreamResponse ( response ) ;
188
+ const iterator = asyncIterable [ Symbol . asyncIterator ] ( ) ;
189
+
190
+ const originalError = new Error ( 'Oops!' ) ;
191
+ Promise . resolve ( ) . then ( ( ) => {
192
+ readableStream . cancel ( originalError ) ; // this will throw in reader.read()
193
+ } ) ;
194
+
195
+ const { value, done } = await iterator . next ( ) ;
196
+ expect ( done ) . toBeFalsy ( ) ;
197
+ expect ( value ) . toMatchInlineSnapshot ( `
198
+ {
199
+ "errors": [
200
+ [GraphQLError: Oops!],
201
+ ],
202
+ }
203
+ ` ) ;
204
+ expect ( value . errors [ 0 ] . originalError ) . toBe ( originalError ) ;
205
+
206
+ await expect ( iterator . next ( ) ) . resolves . toMatchInlineSnapshot ( `
207
+ {
208
+ "done": true,
209
+ "value": undefined,
210
+ }
211
+ ` ) ;
212
+
213
+ await expect ( iterator . return ( ) ) . resolves . toMatchInlineSnapshot ( `
214
+ {
215
+ "done": true,
216
+ "value": undefined,
217
+ }
218
+ ` ) ;
219
+ } ) ;
122
220
} ) ;
0 commit comments