11cb0ef41Sopenharmony_ci// Flags: --no-warnings --expose-gc --expose-internals 21cb0ef41Sopenharmony_ci'use strict'; 31cb0ef41Sopenharmony_ci 41cb0ef41Sopenharmony_ciconst common = require('../common'); 51cb0ef41Sopenharmony_ciconst { inspect } = require('util'); 61cb0ef41Sopenharmony_ci 71cb0ef41Sopenharmony_ciconst { 81cb0ef41Sopenharmony_ci ok, 91cb0ef41Sopenharmony_ci notStrictEqual, 101cb0ef41Sopenharmony_ci strictEqual, 111cb0ef41Sopenharmony_ci throws, 121cb0ef41Sopenharmony_ci} = require('assert'); 131cb0ef41Sopenharmony_ci 141cb0ef41Sopenharmony_ciconst { 151cb0ef41Sopenharmony_ci kWeakHandler, 161cb0ef41Sopenharmony_ci} = require('internal/event_target'); 171cb0ef41Sopenharmony_ci 181cb0ef41Sopenharmony_ciconst { setTimeout: sleep } = require('timers/promises'); 191cb0ef41Sopenharmony_ci 201cb0ef41Sopenharmony_ci{ 211cb0ef41Sopenharmony_ci // Tests that abort is fired with the correct event type on AbortControllers 221cb0ef41Sopenharmony_ci const ac = new AbortController(); 231cb0ef41Sopenharmony_ci ok(ac.signal); 241cb0ef41Sopenharmony_ci ac.signal.onabort = common.mustCall((event) => { 251cb0ef41Sopenharmony_ci ok(event); 261cb0ef41Sopenharmony_ci strictEqual(event.type, 'abort'); 271cb0ef41Sopenharmony_ci }); 281cb0ef41Sopenharmony_ci ac.signal.addEventListener('abort', common.mustCall((event) => { 291cb0ef41Sopenharmony_ci ok(event); 301cb0ef41Sopenharmony_ci strictEqual(event.type, 'abort'); 311cb0ef41Sopenharmony_ci }), { once: true }); 321cb0ef41Sopenharmony_ci ac.abort(); 331cb0ef41Sopenharmony_ci ac.abort(); 341cb0ef41Sopenharmony_ci ok(ac.signal.aborted); 351cb0ef41Sopenharmony_ci} 361cb0ef41Sopenharmony_ci 371cb0ef41Sopenharmony_ci{ 381cb0ef41Sopenharmony_ci // Tests that abort events are trusted 391cb0ef41Sopenharmony_ci const ac = new AbortController(); 401cb0ef41Sopenharmony_ci ac.signal.addEventListener('abort', common.mustCall((event) => { 411cb0ef41Sopenharmony_ci ok(event.isTrusted); 421cb0ef41Sopenharmony_ci })); 431cb0ef41Sopenharmony_ci ac.abort(); 441cb0ef41Sopenharmony_ci} 451cb0ef41Sopenharmony_ci 461cb0ef41Sopenharmony_ci{ 471cb0ef41Sopenharmony_ci // Tests that abort events have the same `isTrusted` reference 481cb0ef41Sopenharmony_ci const first = new AbortController(); 491cb0ef41Sopenharmony_ci const second = new AbortController(); 501cb0ef41Sopenharmony_ci let ev1, ev2; 511cb0ef41Sopenharmony_ci const ev3 = new Event('abort'); 521cb0ef41Sopenharmony_ci first.signal.addEventListener('abort', common.mustCall((event) => { 531cb0ef41Sopenharmony_ci ev1 = event; 541cb0ef41Sopenharmony_ci })); 551cb0ef41Sopenharmony_ci second.signal.addEventListener('abort', common.mustCall((event) => { 561cb0ef41Sopenharmony_ci ev2 = event; 571cb0ef41Sopenharmony_ci })); 581cb0ef41Sopenharmony_ci first.abort(); 591cb0ef41Sopenharmony_ci second.abort(); 601cb0ef41Sopenharmony_ci const firstTrusted = Reflect.getOwnPropertyDescriptor(Object.getPrototypeOf(ev1), 'isTrusted').get; 611cb0ef41Sopenharmony_ci const secondTrusted = Reflect.getOwnPropertyDescriptor(Object.getPrototypeOf(ev2), 'isTrusted').get; 621cb0ef41Sopenharmony_ci const untrusted = Reflect.getOwnPropertyDescriptor(Object.getPrototypeOf(ev3), 'isTrusted').get; 631cb0ef41Sopenharmony_ci strictEqual(firstTrusted, secondTrusted); 641cb0ef41Sopenharmony_ci strictEqual(untrusted, firstTrusted); 651cb0ef41Sopenharmony_ci} 661cb0ef41Sopenharmony_ci 671cb0ef41Sopenharmony_ci{ 681cb0ef41Sopenharmony_ci // Tests that AbortSignal is impossible to construct manually 691cb0ef41Sopenharmony_ci const ac = new AbortController(); 701cb0ef41Sopenharmony_ci throws(() => new ac.signal.constructor(), { 711cb0ef41Sopenharmony_ci code: 'ERR_ILLEGAL_CONSTRUCTOR', 721cb0ef41Sopenharmony_ci }); 731cb0ef41Sopenharmony_ci} 741cb0ef41Sopenharmony_ci{ 751cb0ef41Sopenharmony_ci // Symbol.toStringTag 761cb0ef41Sopenharmony_ci const toString = (o) => Object.prototype.toString.call(o); 771cb0ef41Sopenharmony_ci const ac = new AbortController(); 781cb0ef41Sopenharmony_ci strictEqual(toString(ac), '[object AbortController]'); 791cb0ef41Sopenharmony_ci strictEqual(toString(ac.signal), '[object AbortSignal]'); 801cb0ef41Sopenharmony_ci} 811cb0ef41Sopenharmony_ci 821cb0ef41Sopenharmony_ci{ 831cb0ef41Sopenharmony_ci const signal = AbortSignal.abort(); 841cb0ef41Sopenharmony_ci ok(signal.aborted); 851cb0ef41Sopenharmony_ci} 861cb0ef41Sopenharmony_ci 871cb0ef41Sopenharmony_ci{ 881cb0ef41Sopenharmony_ci // Test that AbortController properties and methods validate the receiver 891cb0ef41Sopenharmony_ci const acSignalGet = Object.getOwnPropertyDescriptor( 901cb0ef41Sopenharmony_ci AbortController.prototype, 911cb0ef41Sopenharmony_ci 'signal' 921cb0ef41Sopenharmony_ci ).get; 931cb0ef41Sopenharmony_ci const acAbort = AbortController.prototype.abort; 941cb0ef41Sopenharmony_ci 951cb0ef41Sopenharmony_ci const goodController = new AbortController(); 961cb0ef41Sopenharmony_ci ok(acSignalGet.call(goodController)); 971cb0ef41Sopenharmony_ci acAbort.call(goodController); 981cb0ef41Sopenharmony_ci 991cb0ef41Sopenharmony_ci const badAbortControllers = [ 1001cb0ef41Sopenharmony_ci null, 1011cb0ef41Sopenharmony_ci undefined, 1021cb0ef41Sopenharmony_ci 0, 1031cb0ef41Sopenharmony_ci NaN, 1041cb0ef41Sopenharmony_ci true, 1051cb0ef41Sopenharmony_ci 'AbortController', 1061cb0ef41Sopenharmony_ci Object.create(AbortController.prototype), 1071cb0ef41Sopenharmony_ci ]; 1081cb0ef41Sopenharmony_ci for (const badController of badAbortControllers) { 1091cb0ef41Sopenharmony_ci throws( 1101cb0ef41Sopenharmony_ci () => acSignalGet.call(badController), 1111cb0ef41Sopenharmony_ci { code: 'ERR_INVALID_THIS', name: 'TypeError' } 1121cb0ef41Sopenharmony_ci ); 1131cb0ef41Sopenharmony_ci throws( 1141cb0ef41Sopenharmony_ci () => acAbort.call(badController), 1151cb0ef41Sopenharmony_ci { code: 'ERR_INVALID_THIS', name: 'TypeError' } 1161cb0ef41Sopenharmony_ci ); 1171cb0ef41Sopenharmony_ci } 1181cb0ef41Sopenharmony_ci} 1191cb0ef41Sopenharmony_ci 1201cb0ef41Sopenharmony_ci{ 1211cb0ef41Sopenharmony_ci // Test that AbortSignal properties validate the receiver 1221cb0ef41Sopenharmony_ci const signalAbortedGet = Object.getOwnPropertyDescriptor( 1231cb0ef41Sopenharmony_ci AbortSignal.prototype, 1241cb0ef41Sopenharmony_ci 'aborted' 1251cb0ef41Sopenharmony_ci ).get; 1261cb0ef41Sopenharmony_ci 1271cb0ef41Sopenharmony_ci const goodSignal = new AbortController().signal; 1281cb0ef41Sopenharmony_ci strictEqual(signalAbortedGet.call(goodSignal), false); 1291cb0ef41Sopenharmony_ci 1301cb0ef41Sopenharmony_ci const badAbortSignals = [ 1311cb0ef41Sopenharmony_ci null, 1321cb0ef41Sopenharmony_ci undefined, 1331cb0ef41Sopenharmony_ci 0, 1341cb0ef41Sopenharmony_ci NaN, 1351cb0ef41Sopenharmony_ci true, 1361cb0ef41Sopenharmony_ci 'AbortSignal', 1371cb0ef41Sopenharmony_ci Object.create(AbortSignal.prototype), 1381cb0ef41Sopenharmony_ci ]; 1391cb0ef41Sopenharmony_ci for (const badSignal of badAbortSignals) { 1401cb0ef41Sopenharmony_ci throws( 1411cb0ef41Sopenharmony_ci () => signalAbortedGet.call(badSignal), 1421cb0ef41Sopenharmony_ci { code: 'ERR_INVALID_THIS', name: 'TypeError' } 1431cb0ef41Sopenharmony_ci ); 1441cb0ef41Sopenharmony_ci } 1451cb0ef41Sopenharmony_ci} 1461cb0ef41Sopenharmony_ci 1471cb0ef41Sopenharmony_ci{ 1481cb0ef41Sopenharmony_ci const ac = new AbortController(); 1491cb0ef41Sopenharmony_ci strictEqual(inspect(ac, { depth: 1 }), 1501cb0ef41Sopenharmony_ci 'AbortController { signal: [AbortSignal] }'); 1511cb0ef41Sopenharmony_ci strictEqual(inspect(ac, { depth: null }), 1521cb0ef41Sopenharmony_ci 'AbortController { signal: AbortSignal { aborted: false } }'); 1531cb0ef41Sopenharmony_ci} 1541cb0ef41Sopenharmony_ci 1551cb0ef41Sopenharmony_ci{ 1561cb0ef41Sopenharmony_ci // Test AbortSignal.reason 1571cb0ef41Sopenharmony_ci const ac = new AbortController(); 1581cb0ef41Sopenharmony_ci ac.abort('reason'); 1591cb0ef41Sopenharmony_ci strictEqual(ac.signal.reason, 'reason'); 1601cb0ef41Sopenharmony_ci} 1611cb0ef41Sopenharmony_ci 1621cb0ef41Sopenharmony_ci{ 1631cb0ef41Sopenharmony_ci // Test AbortSignal.reason 1641cb0ef41Sopenharmony_ci const signal = AbortSignal.abort('reason'); 1651cb0ef41Sopenharmony_ci strictEqual(signal.reason, 'reason'); 1661cb0ef41Sopenharmony_ci} 1671cb0ef41Sopenharmony_ci 1681cb0ef41Sopenharmony_ci{ 1691cb0ef41Sopenharmony_ci // Test AbortSignal timeout 1701cb0ef41Sopenharmony_ci const signal = AbortSignal.timeout(10); 1711cb0ef41Sopenharmony_ci ok(!signal.aborted); 1721cb0ef41Sopenharmony_ci setTimeout(common.mustCall(() => { 1731cb0ef41Sopenharmony_ci ok(signal.aborted); 1741cb0ef41Sopenharmony_ci strictEqual(signal.reason.name, 'TimeoutError'); 1751cb0ef41Sopenharmony_ci strictEqual(signal.reason.code, 23); 1761cb0ef41Sopenharmony_ci }), 20); 1771cb0ef41Sopenharmony_ci} 1781cb0ef41Sopenharmony_ci 1791cb0ef41Sopenharmony_ci{ 1801cb0ef41Sopenharmony_ci (async () => { 1811cb0ef41Sopenharmony_ci // Test AbortSignal timeout doesn't prevent the signal 1821cb0ef41Sopenharmony_ci // from being garbage collected. 1831cb0ef41Sopenharmony_ci let ref; 1841cb0ef41Sopenharmony_ci { 1851cb0ef41Sopenharmony_ci ref = new globalThis.WeakRef(AbortSignal.timeout(1_200_000)); 1861cb0ef41Sopenharmony_ci } 1871cb0ef41Sopenharmony_ci 1881cb0ef41Sopenharmony_ci await sleep(10); 1891cb0ef41Sopenharmony_ci globalThis.gc(); 1901cb0ef41Sopenharmony_ci strictEqual(ref.deref(), undefined); 1911cb0ef41Sopenharmony_ci })().then(common.mustCall()); 1921cb0ef41Sopenharmony_ci 1931cb0ef41Sopenharmony_ci (async () => { 1941cb0ef41Sopenharmony_ci // Test that an AbortSignal with a timeout is not gc'd while 1951cb0ef41Sopenharmony_ci // there is an active listener on it. 1961cb0ef41Sopenharmony_ci let ref; 1971cb0ef41Sopenharmony_ci function handler() {} 1981cb0ef41Sopenharmony_ci { 1991cb0ef41Sopenharmony_ci ref = new globalThis.WeakRef(AbortSignal.timeout(1_200_000)); 2001cb0ef41Sopenharmony_ci ref.deref().addEventListener('abort', handler); 2011cb0ef41Sopenharmony_ci } 2021cb0ef41Sopenharmony_ci 2031cb0ef41Sopenharmony_ci await sleep(10); 2041cb0ef41Sopenharmony_ci globalThis.gc(); 2051cb0ef41Sopenharmony_ci notStrictEqual(ref.deref(), undefined); 2061cb0ef41Sopenharmony_ci ok(ref.deref() instanceof AbortSignal); 2071cb0ef41Sopenharmony_ci 2081cb0ef41Sopenharmony_ci ref.deref().removeEventListener('abort', handler); 2091cb0ef41Sopenharmony_ci 2101cb0ef41Sopenharmony_ci await sleep(10); 2111cb0ef41Sopenharmony_ci globalThis.gc(); 2121cb0ef41Sopenharmony_ci strictEqual(ref.deref(), undefined); 2131cb0ef41Sopenharmony_ci })().then(common.mustCall()); 2141cb0ef41Sopenharmony_ci 2151cb0ef41Sopenharmony_ci (async () => { 2161cb0ef41Sopenharmony_ci // If the event listener is weak, however, it should not prevent gc 2171cb0ef41Sopenharmony_ci let ref; 2181cb0ef41Sopenharmony_ci function handler() {} 2191cb0ef41Sopenharmony_ci { 2201cb0ef41Sopenharmony_ci ref = new globalThis.WeakRef(AbortSignal.timeout(1_200_000)); 2211cb0ef41Sopenharmony_ci ref.deref().addEventListener('abort', handler, { [kWeakHandler]: {} }); 2221cb0ef41Sopenharmony_ci } 2231cb0ef41Sopenharmony_ci 2241cb0ef41Sopenharmony_ci await sleep(10); 2251cb0ef41Sopenharmony_ci globalThis.gc(); 2261cb0ef41Sopenharmony_ci strictEqual(ref.deref(), undefined); 2271cb0ef41Sopenharmony_ci })().then(common.mustCall()); 2281cb0ef41Sopenharmony_ci 2291cb0ef41Sopenharmony_ci // Setting a long timeout (20 minutes here) should not 2301cb0ef41Sopenharmony_ci // keep the Node.js process open (the timer is unref'd) 2311cb0ef41Sopenharmony_ci AbortSignal.timeout(1_200_000); 2321cb0ef41Sopenharmony_ci} 2331cb0ef41Sopenharmony_ci 2341cb0ef41Sopenharmony_ci{ 2351cb0ef41Sopenharmony_ci // Test AbortSignal.reason default 2361cb0ef41Sopenharmony_ci const signal = AbortSignal.abort(); 2371cb0ef41Sopenharmony_ci ok(signal.reason instanceof DOMException); 2381cb0ef41Sopenharmony_ci strictEqual(signal.reason.code, 20); 2391cb0ef41Sopenharmony_ci 2401cb0ef41Sopenharmony_ci const ac = new AbortController(); 2411cb0ef41Sopenharmony_ci ac.abort(); 2421cb0ef41Sopenharmony_ci ok(ac.signal.reason instanceof DOMException); 2431cb0ef41Sopenharmony_ci strictEqual(ac.signal.reason.code, 20); 2441cb0ef41Sopenharmony_ci} 2451cb0ef41Sopenharmony_ci 2461cb0ef41Sopenharmony_ci{ 2471cb0ef41Sopenharmony_ci // Test abortSignal.throwIfAborted() 2481cb0ef41Sopenharmony_ci throws(() => AbortSignal.abort().throwIfAborted(), { 2491cb0ef41Sopenharmony_ci code: 20, 2501cb0ef41Sopenharmony_ci name: 'AbortError', 2511cb0ef41Sopenharmony_ci }); 2521cb0ef41Sopenharmony_ci 2531cb0ef41Sopenharmony_ci // Does not throw because it's not aborted. 2541cb0ef41Sopenharmony_ci const ac = new AbortController(); 2551cb0ef41Sopenharmony_ci ac.signal.throwIfAborted(); 2561cb0ef41Sopenharmony_ci} 2571cb0ef41Sopenharmony_ci 2581cb0ef41Sopenharmony_ci{ 2591cb0ef41Sopenharmony_ci const originalDesc = Reflect.getOwnPropertyDescriptor(AbortSignal.prototype, 'aborted'); 2601cb0ef41Sopenharmony_ci const actualReason = new Error(); 2611cb0ef41Sopenharmony_ci Reflect.defineProperty(AbortSignal.prototype, 'aborted', { value: false }); 2621cb0ef41Sopenharmony_ci throws(() => AbortSignal.abort(actualReason).throwIfAborted(), actualReason); 2631cb0ef41Sopenharmony_ci Reflect.defineProperty(AbortSignal.prototype, 'aborted', originalDesc); 2641cb0ef41Sopenharmony_ci} 2651cb0ef41Sopenharmony_ci 2661cb0ef41Sopenharmony_ci{ 2671cb0ef41Sopenharmony_ci const originalDesc = Reflect.getOwnPropertyDescriptor(AbortSignal.prototype, 'reason'); 2681cb0ef41Sopenharmony_ci const actualReason = new Error(); 2691cb0ef41Sopenharmony_ci const fakeExcuse = new Error(); 2701cb0ef41Sopenharmony_ci Reflect.defineProperty(AbortSignal.prototype, 'reason', { value: fakeExcuse }); 2711cb0ef41Sopenharmony_ci throws(() => AbortSignal.abort(actualReason).throwIfAborted(), actualReason); 2721cb0ef41Sopenharmony_ci Reflect.defineProperty(AbortSignal.prototype, 'reason', originalDesc); 2731cb0ef41Sopenharmony_ci} 274