Skip to content

Commit 64442fc

Browse files
jasnellRafaelGSS
authored andcommitted
test: refactor test-abortcontroller to use node:test
Starting the long process of refactoring our own tests to use the node:test module and mocks. PR-URL: #54574 Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
1 parent 4baf463 commit 64442fc

File tree

2 files changed

+142
-105
lines changed

2 files changed

+142
-105
lines changed
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// Flags: --no-warnings --expose-gc --expose-internals
2+
'use strict';
3+
require('../common');
4+
5+
const {
6+
strictEqual,
7+
} = require('assert');
8+
9+
const {
10+
test,
11+
} = require('node:test');
12+
13+
const {
14+
kWeakHandler,
15+
} = require('internal/event_target');
16+
17+
const { setTimeout: sleep } = require('timers/promises');
18+
19+
// The tests in this file depend on Node.js internal APIs. These are not necessarily
20+
// portable to other runtimes
21+
22+
test('A weak event listener should not prevent gc', async () => {
23+
// If the event listener is weak, however, it should not prevent gc
24+
let ref;
25+
function handler() {}
26+
{
27+
ref = new globalThis.WeakRef(AbortSignal.timeout(1_200_000));
28+
ref.deref().addEventListener('abort', handler, { [kWeakHandler]: {} });
29+
}
30+
31+
await sleep(10);
32+
globalThis.gc();
33+
strictEqual(ref.deref(), undefined);
34+
});

test/parallel/test-abortcontroller.js

Lines changed: 108 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
// Flags: --no-warnings --expose-gc --expose-internals
1+
// Flags: --expose-gc
22
'use strict';
33

4-
const common = require('../common');
4+
require('../common');
55
const { inspect } = require('util');
66

77
const {
@@ -12,80 +12,93 @@ const {
1212
} = require('assert');
1313

1414
const {
15-
kWeakHandler,
16-
} = require('internal/event_target');
15+
test,
16+
mock,
17+
} = require('node:test');
1718

1819
const { 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

Comments
 (0)