1- // Flags: --no-warnings -- expose-gc --expose-internals
1+ // Flags: --expose-gc
22'use strict' ;
33
4- const common = require ( '../common' ) ;
4+ require ( '../common' ) ;
55const { inspect } = require ( 'util' ) ;
66
77const {
@@ -12,80 +12,93 @@ const {
1212} = require ( 'assert' ) ;
1313
1414const {
15- kWeakHandler,
16- } = require ( 'internal/event_target' ) ;
15+ test,
16+ mock,
17+ } = require ( 'node:test' ) ;
1718
1819const { setTimeout : sleep } = require ( 'timers/promises' ) ;
1920
20- {
21+ // All of the the tests in this file depend on public-facing Node.js APIs.
22+ // For tests that depend on Node.js internal APIs, please add them to
23+ // test-abortcontroller-internal.js instead.
24+
25+ test ( 'Abort is fired with the correct event type on AbortControllers' , ( ) => {
2126 // Tests that abort is fired with the correct event type on AbortControllers
2227 const ac = new AbortController ( ) ;
2328 ok ( ac . signal ) ;
24- ac . signal . onabort = common . mustCall ( ( event ) => {
29+
30+ const fn = mock . fn ( ( event ) => {
2531 ok ( event ) ;
2632 strictEqual ( event . type , 'abort' ) ;
2733 } ) ;
28- ac . signal . addEventListener ( 'abort' , common . mustCall ( ( event ) => {
29- ok ( event ) ;
30- strictEqual ( event . type , 'abort' ) ;
31- } ) , { once : true } ) ;
34+
35+ ac . signal . onabort = fn ;
36+ ac . signal . addEventListener ( 'abort' , fn ) ;
37+
3238 ac . abort ( ) ;
3339 ac . abort ( ) ;
3440 ok ( ac . signal . aborted ) ;
35- }
3641
37- {
42+ strictEqual ( fn . mock . calls . length , 2 ) ;
43+ } ) ;
44+
45+ test ( 'Abort events are trusted' , ( ) => {
3846 // Tests that abort events are trusted
3947 const ac = new AbortController ( ) ;
40- ac . signal . addEventListener ( 'abort' , common . mustCall ( ( event ) => {
48+
49+ const fn = mock . fn ( ( event ) => {
4150 ok ( event . isTrusted ) ;
42- } ) ) ;
51+ } ) ;
52+
53+ ac . signal . onabort = fn ;
4354 ac . abort ( ) ;
44- }
55+ strictEqual ( fn . mock . calls . length , 1 ) ;
56+ } ) ;
4557
46- {
58+ test ( 'Abort events have the same isTrusted reference' , ( ) => {
4759 // Tests that abort events have the same `isTrusted` reference
4860 const first = new AbortController ( ) ;
4961 const second = new AbortController ( ) ;
5062 let ev1 , ev2 ;
5163 const ev3 = new Event ( 'abort' ) ;
52- first . signal . addEventListener ( 'abort' , common . mustCall ( ( event ) => {
64+
65+ first . signal . addEventListener ( 'abort' , ( event ) => {
5366 ev1 = event ;
54- } ) ) ;
55- second . signal . addEventListener ( 'abort' , common . mustCall ( ( event ) => {
67+ } ) ;
68+ second . signal . addEventListener ( 'abort' , ( event ) => {
5669 ev2 = event ;
57- } ) ) ;
70+ } ) ;
5871 first . abort ( ) ;
5972 second . abort ( ) ;
6073 const firstTrusted = Reflect . getOwnPropertyDescriptor ( Object . getPrototypeOf ( ev1 ) , 'isTrusted' ) . get ;
6174 const secondTrusted = Reflect . getOwnPropertyDescriptor ( Object . getPrototypeOf ( ev2 ) , 'isTrusted' ) . get ;
6275 const untrusted = Reflect . getOwnPropertyDescriptor ( Object . getPrototypeOf ( ev3 ) , 'isTrusted' ) . get ;
6376 strictEqual ( firstTrusted , secondTrusted ) ;
6477 strictEqual ( untrusted , firstTrusted ) ;
65- }
78+ } ) ;
6679
67- {
80+ test ( 'AbortSignal is impossible to construct manually' , ( ) => {
6881 // Tests that AbortSignal is impossible to construct manually
6982 const ac = new AbortController ( ) ;
7083 throws ( ( ) => new ac . signal . constructor ( ) , {
7184 code : 'ERR_ILLEGAL_CONSTRUCTOR' ,
7285 } ) ;
73- }
74- {
86+ } ) ;
87+
88+ test ( 'Symbol.toStringTag is correct' , ( ) => {
7589 // Symbol.toStringTag
7690 const toString = ( o ) => Object . prototype . toString . call ( o ) ;
7791 const ac = new AbortController ( ) ;
7892 strictEqual ( toString ( ac ) , '[object AbortController]' ) ;
7993 strictEqual ( toString ( ac . signal ) , '[object AbortSignal]' ) ;
80- }
94+ } ) ;
8195
82- {
96+ test ( 'AbortSignal.abort() creates an already aborted signal' , ( ) => {
8397 const signal = AbortSignal . abort ( ) ;
8498 ok ( signal . aborted ) ;
85- }
99+ } ) ;
86100
87- {
88- // Test that AbortController properties and methods validate the receiver
101+ test ( 'AbortController properties and methods valiate the receiver' , ( ) => {
89102 const acSignalGet = Object . getOwnPropertyDescriptor (
90103 AbortController . prototype ,
91104 'signal'
@@ -115,10 +128,9 @@ const { setTimeout: sleep } = require('timers/promises');
115128 { name : 'TypeError' }
116129 ) ;
117130 }
118- }
131+ } ) ;
119132
120- {
121- // Test that AbortSignal properties validate the receiver
133+ test ( 'AbortSignal properties validate the receiver' , ( ) => {
122134 const signalAbortedGet = Object . getOwnPropertyDescriptor (
123135 AbortSignal . prototype ,
124136 'aborted'
@@ -142,96 +154,87 @@ const { setTimeout: sleep } = require('timers/promises');
142154 { name : 'TypeError' }
143155 ) ;
144156 }
145- }
157+ } ) ;
146158
147- {
159+ test ( 'AbortController inspection depth 1 or null works' , ( ) => {
148160 const ac = new AbortController ( ) ;
149161 strictEqual ( inspect ( ac , { depth : 1 } ) ,
150162 'AbortController { signal: [AbortSignal] }' ) ;
151163 strictEqual ( inspect ( ac , { depth : null } ) ,
152164 'AbortController { signal: AbortSignal { aborted: false } }' ) ;
153- }
165+ } ) ;
154166
155- {
167+ test ( 'AbortSignal reason is set correctly' , ( ) => {
156168 // Test AbortSignal.reason
157169 const ac = new AbortController ( ) ;
158170 ac . abort ( 'reason' ) ;
159171 strictEqual ( ac . signal . reason , 'reason' ) ;
160- }
172+ } ) ;
161173
162- {
174+ test ( 'AbortSignal reasonable is set correctly with AbortSignal.abort()' , ( ) => {
163175 // Test AbortSignal.reason
164176 const signal = AbortSignal . abort ( 'reason' ) ;
165177 strictEqual ( signal . reason , 'reason' ) ;
166- }
178+ } ) ;
167179
168- {
180+ test ( 'AbortSignal.timeout() works as expected' , async ( ) => {
169181 // Test AbortSignal timeout
170182 const signal = AbortSignal . timeout ( 10 ) ;
171183 ok ( ! signal . aborted ) ;
172- setTimeout ( common . mustCall ( ( ) => {
184+
185+ const { promise, resolve } = Promise . withResolvers ( ) ;
186+
187+ const fn = mock . fn ( ( ) => {
173188 ok ( signal . aborted ) ;
174189 strictEqual ( signal . reason . name , 'TimeoutError' ) ;
175190 strictEqual ( signal . reason . code , 23 ) ;
176- } ) , 20 ) ;
177- }
178-
179- {
180- ( async ( ) => {
181- // Test AbortSignal timeout doesn't prevent the signal
182- // from being garbage collected.
183- let ref ;
184- {
185- ref = new globalThis . WeakRef ( AbortSignal . timeout ( 1_200_000 ) ) ;
186- }
187-
188- await sleep ( 10 ) ;
189- globalThis . gc ( ) ;
190- strictEqual ( ref . deref ( ) , undefined ) ;
191- } ) ( ) . then ( common . mustCall ( ) ) ;
192-
193- ( async ( ) => {
194- // Test that an AbortSignal with a timeout is not gc'd while
195- // there is an active listener on it.
196- let ref ;
197- function handler ( ) { }
198- {
199- ref = new globalThis . WeakRef ( AbortSignal . timeout ( 1_200_000 ) ) ;
200- ref . deref ( ) . addEventListener ( 'abort' , handler ) ;
201- }
202-
203- await sleep ( 10 ) ;
204- globalThis . gc ( ) ;
205- notStrictEqual ( ref . deref ( ) , undefined ) ;
206- ok ( ref . deref ( ) instanceof AbortSignal ) ;
207-
208- ref . deref ( ) . removeEventListener ( 'abort' , handler ) ;
209-
210- await sleep ( 10 ) ;
211- globalThis . gc ( ) ;
212- strictEqual ( ref . deref ( ) , undefined ) ;
213- } ) ( ) . then ( common . mustCall ( ) ) ;
214-
215- ( async ( ) => {
216- // If the event listener is weak, however, it should not prevent gc
217- let ref ;
218- function handler ( ) { }
219- {
220- ref = new globalThis . WeakRef ( AbortSignal . timeout ( 1_200_000 ) ) ;
221- ref . deref ( ) . addEventListener ( 'abort' , handler , { [ kWeakHandler ] : { } } ) ;
222- }
223-
224- await sleep ( 10 ) ;
225- globalThis . gc ( ) ;
226- strictEqual ( ref . deref ( ) , undefined ) ;
227- } ) ( ) . then ( common . mustCall ( ) ) ;
228-
229- // Setting a long timeout (20 minutes here) should not
230- // keep the Node.js process open (the timer is unref'd)
191+ resolve ( ) ;
192+ } ) ;
193+
194+ setTimeout ( fn , 20 ) ;
195+ await promise ;
196+ } ) ;
197+
198+ test ( 'AbortSignal.timeout() does not prevent the signal from being collected' , async ( ) => {
199+ // Test AbortSignal timeout doesn't prevent the signal
200+ // from being garbage collected.
201+ let ref ;
202+ {
203+ ref = new globalThis . WeakRef ( AbortSignal . timeout ( 1_200_000 ) ) ;
204+ }
205+
206+ await sleep ( 10 ) ;
207+ globalThis . gc ( ) ;
208+ strictEqual ( ref . deref ( ) , undefined ) ;
209+ } ) ;
210+
211+ test ( 'AbortSignal with a timeout is not collected while there is an active listener' , async ( ) => {
212+ // Test that an AbortSignal with a timeout is not gc'd while
213+ // there is an active listener on it.
214+ let ref ;
215+ function handler ( ) { }
216+ {
217+ ref = new globalThis . WeakRef ( AbortSignal . timeout ( 1_200_000 ) ) ;
218+ ref . deref ( ) . addEventListener ( 'abort' , handler ) ;
219+ }
220+
221+ await sleep ( 10 ) ;
222+ globalThis . gc ( ) ;
223+ notStrictEqual ( ref . deref ( ) , undefined ) ;
224+ ok ( ref . deref ( ) instanceof AbortSignal ) ;
225+
226+ ref . deref ( ) . removeEventListener ( 'abort' , handler ) ;
227+
228+ await sleep ( 10 ) ;
229+ globalThis . gc ( ) ;
230+ strictEqual ( ref . deref ( ) , undefined ) ;
231+ } ) ;
232+
233+ test ( 'Setting a long timeout should not keep the process open' , ( ) => {
231234 AbortSignal . timeout ( 1_200_000 ) ;
232- }
235+ } ) ;
233236
234- {
237+ test ( 'AbortSignal.reason should default' , ( ) => {
235238 // Test AbortSignal.reason default
236239 const signal = AbortSignal . abort ( ) ;
237240 ok ( signal . reason instanceof DOMException ) ;
@@ -241,9 +244,9 @@ const { setTimeout: sleep } = require('timers/promises');
241244 ac . abort ( ) ;
242245 ok ( ac . signal . reason instanceof DOMException ) ;
243246 strictEqual ( ac . signal . reason . code , 20 ) ;
244- }
247+ } ) ;
245248
246- {
249+ test ( 'abortSignal.throwIfAborted() works as expected' , ( ) => {
247250 // Test abortSignal.throwIfAborted()
248251 throws ( ( ) => AbortSignal . abort ( ) . throwIfAborted ( ) , {
249252 code : 20 ,
@@ -253,21 +256,21 @@ const { setTimeout: sleep } = require('timers/promises');
253256 // Does not throw because it's not aborted.
254257 const ac = new AbortController ( ) ;
255258 ac . signal . throwIfAborted ( ) ;
256- }
259+ } ) ;
257260
258- {
261+ test ( 'abortSignal.throwIfAobrted() works as expected (2)' , ( ) => {
259262 const originalDesc = Reflect . getOwnPropertyDescriptor ( AbortSignal . prototype , 'aborted' ) ;
260263 const actualReason = new Error ( ) ;
261264 Reflect . defineProperty ( AbortSignal . prototype , 'aborted' , { value : false } ) ;
262265 throws ( ( ) => AbortSignal . abort ( actualReason ) . throwIfAborted ( ) , actualReason ) ;
263266 Reflect . defineProperty ( AbortSignal . prototype , 'aborted' , originalDesc ) ;
264- }
267+ } ) ;
265268
266- {
269+ test ( 'abortSignal.throwIfAobrted() works as expected (3)' , ( ) => {
267270 const originalDesc = Reflect . getOwnPropertyDescriptor ( AbortSignal . prototype , 'reason' ) ;
268271 const actualReason = new Error ( ) ;
269272 const fakeExcuse = new Error ( ) ;
270273 Reflect . defineProperty ( AbortSignal . prototype , 'reason' , { value : fakeExcuse } ) ;
271274 throws ( ( ) => AbortSignal . abort ( actualReason ) . throwIfAborted ( ) , actualReason ) ;
272275 Reflect . defineProperty ( AbortSignal . prototype , 'reason' , originalDesc ) ;
273- }
276+ } ) ;
0 commit comments