@@ -5,6 +5,7 @@ import test from 'ava';
5
5
import delay from 'delay' ;
6
6
import { pEvent } from 'p-event' ;
7
7
import type { Handler } from 'express' ;
8
+ import { createSandbox } from 'sinon' ;
8
9
import got from '../source/index.js' ;
9
10
import slowDataStream from './helpers/slow-data-stream.js' ;
10
11
import type { GlobalClock } from './helpers/types.js' ;
@@ -64,9 +65,25 @@ if (globalThis.AbortController !== undefined) {
64
65
) ;
65
66
} ;
66
67
68
+ const sandbox = createSandbox ( ) ;
69
+
70
+ const createAbortController = ( ) : { controller : AbortController ; signalHandlersRemoved : ( ) => boolean } => {
71
+ const controller = new AbortController ( ) ;
72
+ sandbox . spy ( controller . signal ) ;
73
+ // @ts -expect-error AbortSignal type definition issue: https://github.com/DefinitelyTyped/DefinitelyTyped/discussions/57805
74
+ const signalHandlersRemoved = ( ) => controller . signal . addEventListener . callCount === controller . signal . removeEventListener . callCount ;
75
+ return {
76
+ controller, signalHandlersRemoved,
77
+ } ;
78
+ } ;
79
+
80
+ test . afterEach ( ( ) => {
81
+ sandbox . restore ( ) ;
82
+ } ) ;
83
+
67
84
test . serial ( 'does not retry after abort' , withServerAndFakeTimers , async ( t , server , got , clock ) => {
68
85
const { emitter, promise} = prepareServer ( server , clock ) ;
69
- const controller = new AbortController ( ) ;
86
+ const { controller, signalHandlersRemoved } = createAbortController ( ) ;
70
87
71
88
const gotPromise = got ( 'redirect' , {
72
89
signal : controller . signal ,
@@ -88,12 +105,14 @@ if (globalThis.AbortController !== undefined) {
88
105
} ) ;
89
106
90
107
await t . notThrowsAsync ( promise , 'Request finished instead of aborting.' ) ;
108
+
109
+ t . true ( signalHandlersRemoved ( ) , 'Abort signal event handlers not removed' ) ;
91
110
} ) ;
92
111
93
112
test . serial ( 'abort request timeouts' , withServer , async ( t , server , got ) => {
94
113
server . get ( '/' , ( ) => { } ) ;
95
114
96
- const controller = new AbortController ( ) ;
115
+ const { controller, signalHandlersRemoved } = createAbortController ( ) ;
97
116
98
117
const gotPromise = got ( {
99
118
signal : controller . signal ,
@@ -121,14 +140,16 @@ if (globalThis.AbortController !== undefined) {
121
140
message : 'This operation was aborted.' ,
122
141
} ) ;
123
142
143
+ t . true ( signalHandlersRemoved ( ) , 'Abort signal event handlers not removed' ) ;
144
+
124
145
// Wait for unhandled errors
125
146
await delay ( 40 ) ;
126
147
} ) ;
127
148
128
149
test . serial ( 'aborts in-progress request' , withServerAndFakeTimers , async ( t , server , got , clock ) => {
129
150
const { emitter, promise} = prepareServer ( server , clock ) ;
130
151
131
- const controller = new AbortController ( ) ;
152
+ const { controller, signalHandlersRemoved } = createAbortController ( ) ;
132
153
133
154
const body = new ReadableStream ( {
134
155
read ( ) { } ,
@@ -148,12 +169,14 @@ if (globalThis.AbortController !== undefined) {
148
169
message : 'This operation was aborted.' ,
149
170
} ) ;
150
171
await t . notThrowsAsync ( promise , 'Request finished instead of aborting.' ) ;
172
+
173
+ t . true ( signalHandlersRemoved ( ) , 'Abort signal event handlers not removed' ) ;
151
174
} ) ;
152
175
153
176
test . serial ( 'aborts in-progress request with timeout' , withServerAndFakeTimers , async ( t , server , got , clock ) => {
154
177
const { emitter, promise} = prepareServer ( server , clock ) ;
155
178
156
- const controller = new AbortController ( ) ;
179
+ const { controller, signalHandlersRemoved } = createAbortController ( ) ;
157
180
158
181
const body = new ReadableStream ( {
159
182
read ( ) { } ,
@@ -173,10 +196,12 @@ if (globalThis.AbortController !== undefined) {
173
196
message : 'This operation was aborted.' ,
174
197
} ) ;
175
198
await t . notThrowsAsync ( promise , 'Request finished instead of aborting.' ) ;
199
+
200
+ t . true ( signalHandlersRemoved ( ) , 'Abort signal event handlers not removed' ) ;
176
201
} ) ;
177
202
178
203
test . serial ( 'abort immediately' , withServerAndFakeTimers , async ( t , server , got , clock ) => {
179
- const controller = new AbortController ( ) ;
204
+ const { controller, signalHandlersRemoved } = createAbortController ( ) ;
180
205
181
206
const promise = new Promise < void > ( ( resolve , reject ) => {
182
207
// We won't get an abort or even a connection
@@ -198,11 +223,13 @@ if (globalThis.AbortController !== undefined) {
198
223
message : 'This operation was aborted.' ,
199
224
} ) ;
200
225
await t . notThrowsAsync ( promise , 'Request finished instead of aborting.' ) ;
226
+
227
+ t . true ( signalHandlersRemoved ( ) , 'Abort signal event handlers not removed' ) ;
201
228
} ) ;
202
229
203
230
test ( 'recover from abort using abortable promise attribute' , async t => {
204
231
// Abort before connection started
205
- const controller = new AbortController ( ) ;
232
+ const { controller, signalHandlersRemoved } = createAbortController ( ) ;
206
233
207
234
const p = got ( 'http://example.com' , { signal : controller . signal } ) ;
208
235
const recover = p . catch ( ( error : Error ) => {
@@ -216,10 +243,12 @@ if (globalThis.AbortController !== undefined) {
216
243
controller . abort ( ) ;
217
244
218
245
await t . notThrowsAsync ( recover ) ;
246
+
247
+ t . true ( signalHandlersRemoved ( ) , 'Abort signal event handlers not removed' ) ;
219
248
} ) ;
220
249
221
250
test ( 'recover from abort using error instance' , async t => {
222
- const controller = new AbortController ( ) ;
251
+ const { controller, signalHandlersRemoved } = createAbortController ( ) ;
223
252
224
253
const p = got ( 'http://example.com' , { signal : controller . signal } ) ;
225
254
const recover = p . catch ( ( error : Error ) => {
@@ -233,13 +262,15 @@ if (globalThis.AbortController !== undefined) {
233
262
controller . abort ( ) ;
234
263
235
264
await t . notThrowsAsync ( recover ) ;
265
+
266
+ t . true ( signalHandlersRemoved ( ) , 'Abort signal event handlers not removed' ) ;
236
267
} ) ;
237
268
238
269
// TODO: Use `fakeTimers` here
239
270
test . serial ( 'throws on incomplete (aborted) response' , withServer , async ( t , server , got ) => {
240
271
server . get ( '/' , downloadHandler ( ) ) ;
241
272
242
- const controller = new AbortController ( ) ;
273
+ const { controller, signalHandlersRemoved } = createAbortController ( ) ;
243
274
244
275
const promise = got ( '' , { signal : controller . signal } ) ;
245
276
@@ -251,6 +282,8 @@ if (globalThis.AbortController !== undefined) {
251
282
code : 'ERR_ABORTED' ,
252
283
message : 'This operation was aborted.' ,
253
284
} ) ;
285
+
286
+ t . true ( signalHandlersRemoved ( ) , 'Abort signal event handlers not removed' ) ;
254
287
} ) ;
255
288
256
289
test ( 'throws when aborting cached request' , withServer , async ( t , server , got ) => {
@@ -263,18 +296,20 @@ if (globalThis.AbortController !== undefined) {
263
296
264
297
await got ( { cache} ) ;
265
298
266
- const controller = new AbortController ( ) ;
299
+ const { controller, signalHandlersRemoved } = createAbortController ( ) ;
267
300
const promise = got ( { cache, signal : controller . signal } ) ;
268
301
controller . abort ( ) ;
269
302
270
303
await t . throwsAsync ( promise , {
271
304
code : 'ERR_ABORTED' ,
272
305
message : 'This operation was aborted.' ,
273
306
} ) ;
307
+
308
+ t . true ( signalHandlersRemoved ( ) , 'Abort signal event handlers not removed' ) ;
274
309
} ) ;
275
310
276
311
test ( 'support setting the signal as a default option' , async t => {
277
- const controller = new AbortController ( ) ;
312
+ const { controller, signalHandlersRemoved } = createAbortController ( ) ;
278
313
279
314
const got2 = got . extend ( { signal : controller . signal } ) ;
280
315
const p = got2 ( 'http://example.com' , { signal : controller . signal } ) ;
@@ -284,6 +319,8 @@ if (globalThis.AbortController !== undefined) {
284
319
code : 'ERR_ABORTED' ,
285
320
message : 'This operation was aborted.' ,
286
321
} ) ;
322
+
323
+ t . true ( signalHandlersRemoved ( ) , 'Abort signal event handlers not removed' ) ;
287
324
} ) ;
288
325
} else {
289
326
test ( 'x' , t => {
0 commit comments