11cb0ef41Sopenharmony_ci// Flags: --expose-internals 21cb0ef41Sopenharmony_ci 31cb0ef41Sopenharmony_ci'use strict'; 41cb0ef41Sopenharmony_ci 51cb0ef41Sopenharmony_ciconst common = require('../common'); 61cb0ef41Sopenharmony_ciconst { ok, strictEqual, deepStrictEqual, throws } = require('node:assert'); 71cb0ef41Sopenharmony_ciconst { inspect } = require('node:util'); 81cb0ef41Sopenharmony_ciconst { Event, EventTarget, CustomEvent } = require('internal/event_target'); 91cb0ef41Sopenharmony_ci 101cb0ef41Sopenharmony_ci{ 111cb0ef41Sopenharmony_ci ok(CustomEvent); 121cb0ef41Sopenharmony_ci 131cb0ef41Sopenharmony_ci // Default string 141cb0ef41Sopenharmony_ci const tag = Object.prototype.toString.call(new CustomEvent('$')); 151cb0ef41Sopenharmony_ci strictEqual(tag, '[object CustomEvent]'); 161cb0ef41Sopenharmony_ci} 171cb0ef41Sopenharmony_ci 181cb0ef41Sopenharmony_ci{ 191cb0ef41Sopenharmony_ci // No argument behavior - throw TypeError 201cb0ef41Sopenharmony_ci throws(() => { 211cb0ef41Sopenharmony_ci new CustomEvent(); 221cb0ef41Sopenharmony_ci }, TypeError); 231cb0ef41Sopenharmony_ci 241cb0ef41Sopenharmony_ci throws(() => new CustomEvent(Symbol()), TypeError); 251cb0ef41Sopenharmony_ci 261cb0ef41Sopenharmony_ci // Too many arguments passed behavior - ignore additional arguments 271cb0ef41Sopenharmony_ci const ev = new CustomEvent('foo', {}, {}); 281cb0ef41Sopenharmony_ci strictEqual(ev.type, 'foo'); 291cb0ef41Sopenharmony_ci} 301cb0ef41Sopenharmony_ci 311cb0ef41Sopenharmony_ci{ 321cb0ef41Sopenharmony_ci const ev = new CustomEvent('$'); 331cb0ef41Sopenharmony_ci strictEqual(ev.type, '$'); 341cb0ef41Sopenharmony_ci strictEqual(ev.bubbles, false); 351cb0ef41Sopenharmony_ci strictEqual(ev.cancelable, false); 361cb0ef41Sopenharmony_ci strictEqual(ev.detail, null); 371cb0ef41Sopenharmony_ci} 381cb0ef41Sopenharmony_ci 391cb0ef41Sopenharmony_ci{ 401cb0ef41Sopenharmony_ci // Coercion to string works 411cb0ef41Sopenharmony_ci strictEqual(new CustomEvent(1).type, '1'); 421cb0ef41Sopenharmony_ci strictEqual(new CustomEvent(false).type, 'false'); 431cb0ef41Sopenharmony_ci strictEqual(new CustomEvent({}).type, String({})); 441cb0ef41Sopenharmony_ci} 451cb0ef41Sopenharmony_ci 461cb0ef41Sopenharmony_ci{ 471cb0ef41Sopenharmony_ci const ev = new CustomEvent('$', { 481cb0ef41Sopenharmony_ci detail: 56, 491cb0ef41Sopenharmony_ci sweet: 'x', 501cb0ef41Sopenharmony_ci cancelable: true, 511cb0ef41Sopenharmony_ci }); 521cb0ef41Sopenharmony_ci strictEqual(ev.type, '$'); 531cb0ef41Sopenharmony_ci strictEqual(ev.bubbles, false); 541cb0ef41Sopenharmony_ci strictEqual(ev.cancelable, true); 551cb0ef41Sopenharmony_ci strictEqual(ev.sweet, undefined); 561cb0ef41Sopenharmony_ci strictEqual(ev.detail, 56); 571cb0ef41Sopenharmony_ci} 581cb0ef41Sopenharmony_ci 591cb0ef41Sopenharmony_ci{ 601cb0ef41Sopenharmony_ci // Any types of value for `detail` are acceptable. 611cb0ef41Sopenharmony_ci ['foo', 1, false, [], {}].forEach((i) => { 621cb0ef41Sopenharmony_ci const ev = new CustomEvent('$', { detail: i }); 631cb0ef41Sopenharmony_ci strictEqual(ev.detail, i); 641cb0ef41Sopenharmony_ci }); 651cb0ef41Sopenharmony_ci} 661cb0ef41Sopenharmony_ci 671cb0ef41Sopenharmony_ci{ 681cb0ef41Sopenharmony_ci // Readonly `detail` behavior 691cb0ef41Sopenharmony_ci const ev = new CustomEvent('$', { 701cb0ef41Sopenharmony_ci detail: 56, 711cb0ef41Sopenharmony_ci }); 721cb0ef41Sopenharmony_ci strictEqual(ev.detail, 56); 731cb0ef41Sopenharmony_ci try { 741cb0ef41Sopenharmony_ci ev.detail = 96; 751cb0ef41Sopenharmony_ci // eslint-disable-next-line no-unused-vars 761cb0ef41Sopenharmony_ci } catch (error) { 771cb0ef41Sopenharmony_ci common.mustCall()(); 781cb0ef41Sopenharmony_ci } 791cb0ef41Sopenharmony_ci strictEqual(ev.detail, 56); 801cb0ef41Sopenharmony_ci} 811cb0ef41Sopenharmony_ci 821cb0ef41Sopenharmony_ci{ 831cb0ef41Sopenharmony_ci const ev = new Event('$', { 841cb0ef41Sopenharmony_ci detail: 96, 851cb0ef41Sopenharmony_ci }); 861cb0ef41Sopenharmony_ci strictEqual(ev.detail, undefined); 871cb0ef41Sopenharmony_ci} 881cb0ef41Sopenharmony_ci 891cb0ef41Sopenharmony_ci// The following tests verify whether CustomEvent works the same as Event 901cb0ef41Sopenharmony_ci// except carrying custom data. They're based on `parallel/test-eventtarget.js`. 911cb0ef41Sopenharmony_ci 921cb0ef41Sopenharmony_ci{ 931cb0ef41Sopenharmony_ci const ev = new CustomEvent('$'); 941cb0ef41Sopenharmony_ci strictEqual(ev.type, '$'); 951cb0ef41Sopenharmony_ci strictEqual(ev.bubbles, false); 961cb0ef41Sopenharmony_ci strictEqual(ev.cancelable, false); 971cb0ef41Sopenharmony_ci strictEqual(ev.detail, null); 981cb0ef41Sopenharmony_ci 991cb0ef41Sopenharmony_ci strictEqual(ev.defaultPrevented, false); 1001cb0ef41Sopenharmony_ci strictEqual(typeof ev.timeStamp, 'number'); 1011cb0ef41Sopenharmony_ci 1021cb0ef41Sopenharmony_ci // Compatibility properties with the DOM 1031cb0ef41Sopenharmony_ci deepStrictEqual(ev.composedPath(), []); 1041cb0ef41Sopenharmony_ci strictEqual(ev.returnValue, true); 1051cb0ef41Sopenharmony_ci strictEqual(ev.composed, false); 1061cb0ef41Sopenharmony_ci strictEqual(ev.isTrusted, false); 1071cb0ef41Sopenharmony_ci strictEqual(ev.eventPhase, 0); 1081cb0ef41Sopenharmony_ci strictEqual(ev.cancelBubble, false); 1091cb0ef41Sopenharmony_ci 1101cb0ef41Sopenharmony_ci // Not cancelable 1111cb0ef41Sopenharmony_ci ev.preventDefault(); 1121cb0ef41Sopenharmony_ci strictEqual(ev.defaultPrevented, false); 1131cb0ef41Sopenharmony_ci} 1141cb0ef41Sopenharmony_ci 1151cb0ef41Sopenharmony_ci{ 1161cb0ef41Sopenharmony_ci // Invalid options 1171cb0ef41Sopenharmony_ci ['foo', 1, false].forEach((i) => 1181cb0ef41Sopenharmony_ci throws(() => new CustomEvent('foo', i), { 1191cb0ef41Sopenharmony_ci code: 'ERR_INVALID_ARG_TYPE', 1201cb0ef41Sopenharmony_ci name: 'TypeError', 1211cb0ef41Sopenharmony_ci message: 1221cb0ef41Sopenharmony_ci 'The "options" argument must be of type object.' + 1231cb0ef41Sopenharmony_ci common.invalidArgTypeHelper(i), 1241cb0ef41Sopenharmony_ci }), 1251cb0ef41Sopenharmony_ci ); 1261cb0ef41Sopenharmony_ci} 1271cb0ef41Sopenharmony_ci 1281cb0ef41Sopenharmony_ci{ 1291cb0ef41Sopenharmony_ci const ev = new CustomEvent('$'); 1301cb0ef41Sopenharmony_ci strictEqual(ev.constructor.name, 'CustomEvent'); 1311cb0ef41Sopenharmony_ci 1321cb0ef41Sopenharmony_ci // CustomEvent Statics 1331cb0ef41Sopenharmony_ci strictEqual(CustomEvent.NONE, 0); 1341cb0ef41Sopenharmony_ci strictEqual(CustomEvent.CAPTURING_PHASE, 1); 1351cb0ef41Sopenharmony_ci strictEqual(CustomEvent.AT_TARGET, 2); 1361cb0ef41Sopenharmony_ci strictEqual(CustomEvent.BUBBLING_PHASE, 3); 1371cb0ef41Sopenharmony_ci strictEqual(new CustomEvent('foo').eventPhase, CustomEvent.NONE); 1381cb0ef41Sopenharmony_ci 1391cb0ef41Sopenharmony_ci // CustomEvent is a function 1401cb0ef41Sopenharmony_ci strictEqual(CustomEvent.length, 1); 1411cb0ef41Sopenharmony_ci} 1421cb0ef41Sopenharmony_ci 1431cb0ef41Sopenharmony_ci{ 1441cb0ef41Sopenharmony_ci const ev = new CustomEvent('foo'); 1451cb0ef41Sopenharmony_ci strictEqual(ev.cancelBubble, false); 1461cb0ef41Sopenharmony_ci ev.cancelBubble = true; 1471cb0ef41Sopenharmony_ci strictEqual(ev.cancelBubble, true); 1481cb0ef41Sopenharmony_ci} 1491cb0ef41Sopenharmony_ci{ 1501cb0ef41Sopenharmony_ci const ev = new CustomEvent('foo'); 1511cb0ef41Sopenharmony_ci strictEqual(ev.cancelBubble, false); 1521cb0ef41Sopenharmony_ci ev.stopPropagation(); 1531cb0ef41Sopenharmony_ci strictEqual(ev.cancelBubble, true); 1541cb0ef41Sopenharmony_ci} 1551cb0ef41Sopenharmony_ci{ 1561cb0ef41Sopenharmony_ci const ev = new CustomEvent('foo'); 1571cb0ef41Sopenharmony_ci strictEqual(ev.cancelBubble, false); 1581cb0ef41Sopenharmony_ci ev.cancelBubble = 'some-truthy-value'; 1591cb0ef41Sopenharmony_ci strictEqual(ev.cancelBubble, true); 1601cb0ef41Sopenharmony_ci} 1611cb0ef41Sopenharmony_ci{ 1621cb0ef41Sopenharmony_ci const ev = new CustomEvent('foo'); 1631cb0ef41Sopenharmony_ci strictEqual(ev.cancelBubble, false); 1641cb0ef41Sopenharmony_ci ev.cancelBubble = true; 1651cb0ef41Sopenharmony_ci strictEqual(ev.cancelBubble, true); 1661cb0ef41Sopenharmony_ci} 1671cb0ef41Sopenharmony_ci{ 1681cb0ef41Sopenharmony_ci const ev = new CustomEvent('foo'); 1691cb0ef41Sopenharmony_ci strictEqual(ev.cancelBubble, false); 1701cb0ef41Sopenharmony_ci ev.stopPropagation(); 1711cb0ef41Sopenharmony_ci strictEqual(ev.cancelBubble, true); 1721cb0ef41Sopenharmony_ci} 1731cb0ef41Sopenharmony_ci{ 1741cb0ef41Sopenharmony_ci const ev = new CustomEvent('foo'); 1751cb0ef41Sopenharmony_ci strictEqual(ev.cancelBubble, false); 1761cb0ef41Sopenharmony_ci ev.cancelBubble = 'some-truthy-value'; 1771cb0ef41Sopenharmony_ci strictEqual(ev.cancelBubble, true); 1781cb0ef41Sopenharmony_ci} 1791cb0ef41Sopenharmony_ci{ 1801cb0ef41Sopenharmony_ci const ev = new CustomEvent('foo', { cancelable: true }); 1811cb0ef41Sopenharmony_ci strictEqual(ev.type, 'foo'); 1821cb0ef41Sopenharmony_ci strictEqual(ev.cancelable, true); 1831cb0ef41Sopenharmony_ci strictEqual(ev.defaultPrevented, false); 1841cb0ef41Sopenharmony_ci 1851cb0ef41Sopenharmony_ci ev.preventDefault(); 1861cb0ef41Sopenharmony_ci strictEqual(ev.defaultPrevented, true); 1871cb0ef41Sopenharmony_ci} 1881cb0ef41Sopenharmony_ci{ 1891cb0ef41Sopenharmony_ci const ev = new CustomEvent('foo'); 1901cb0ef41Sopenharmony_ci strictEqual(ev.isTrusted, false); 1911cb0ef41Sopenharmony_ci} 1921cb0ef41Sopenharmony_ci 1931cb0ef41Sopenharmony_ci// Works with EventTarget 1941cb0ef41Sopenharmony_ci 1951cb0ef41Sopenharmony_ci{ 1961cb0ef41Sopenharmony_ci const obj = { sweet: 'x', memory: { x: 56, y: 96 } }; 1971cb0ef41Sopenharmony_ci const et = new EventTarget(); 1981cb0ef41Sopenharmony_ci const ev = new CustomEvent('$', { detail: obj }); 1991cb0ef41Sopenharmony_ci const fn = common.mustCall((event) => { 2001cb0ef41Sopenharmony_ci strictEqual(event, ev); 2011cb0ef41Sopenharmony_ci deepStrictEqual(event.detail, obj); 2021cb0ef41Sopenharmony_ci }); 2031cb0ef41Sopenharmony_ci et.addEventListener('$', fn); 2041cb0ef41Sopenharmony_ci et.dispatchEvent(ev); 2051cb0ef41Sopenharmony_ci} 2061cb0ef41Sopenharmony_ci 2071cb0ef41Sopenharmony_ci{ 2081cb0ef41Sopenharmony_ci const eventTarget = new EventTarget(); 2091cb0ef41Sopenharmony_ci const event = new CustomEvent('$'); 2101cb0ef41Sopenharmony_ci eventTarget.dispatchEvent(event); 2111cb0ef41Sopenharmony_ci strictEqual(event.target, eventTarget); 2121cb0ef41Sopenharmony_ci} 2131cb0ef41Sopenharmony_ci 2141cb0ef41Sopenharmony_ci{ 2151cb0ef41Sopenharmony_ci const obj = { sweet: 'x' }; 2161cb0ef41Sopenharmony_ci const eventTarget = new EventTarget(); 2171cb0ef41Sopenharmony_ci 2181cb0ef41Sopenharmony_ci const ev1 = common.mustCall(function(event) { 2191cb0ef41Sopenharmony_ci strictEqual(event.type, 'foo'); 2201cb0ef41Sopenharmony_ci strictEqual(event.detail, obj); 2211cb0ef41Sopenharmony_ci strictEqual(this, eventTarget); 2221cb0ef41Sopenharmony_ci strictEqual(event.eventPhase, 2); 2231cb0ef41Sopenharmony_ci }, 2); 2241cb0ef41Sopenharmony_ci 2251cb0ef41Sopenharmony_ci const ev2 = { 2261cb0ef41Sopenharmony_ci handleEvent: common.mustCall(function(event) { 2271cb0ef41Sopenharmony_ci strictEqual(event.type, 'foo'); 2281cb0ef41Sopenharmony_ci strictEqual(event.detail, obj); 2291cb0ef41Sopenharmony_ci strictEqual(this, ev2); 2301cb0ef41Sopenharmony_ci }), 2311cb0ef41Sopenharmony_ci }; 2321cb0ef41Sopenharmony_ci 2331cb0ef41Sopenharmony_ci eventTarget.addEventListener('foo', ev1); 2341cb0ef41Sopenharmony_ci eventTarget.addEventListener('foo', ev2, { once: true }); 2351cb0ef41Sopenharmony_ci ok(eventTarget.dispatchEvent(new CustomEvent('foo', { detail: obj }))); 2361cb0ef41Sopenharmony_ci eventTarget.dispatchEvent(new CustomEvent('foo', { detail: obj })); 2371cb0ef41Sopenharmony_ci 2381cb0ef41Sopenharmony_ci eventTarget.removeEventListener('foo', ev1); 2391cb0ef41Sopenharmony_ci eventTarget.dispatchEvent(new CustomEvent('foo')); 2401cb0ef41Sopenharmony_ci} 2411cb0ef41Sopenharmony_ci 2421cb0ef41Sopenharmony_ci{ 2431cb0ef41Sopenharmony_ci // Same event dispatched multiple times. 2441cb0ef41Sopenharmony_ci const obj = { sweet: 'x' }; 2451cb0ef41Sopenharmony_ci const event = new CustomEvent('foo', { detail: obj }); 2461cb0ef41Sopenharmony_ci const eventTarget1 = new EventTarget(); 2471cb0ef41Sopenharmony_ci const eventTarget2 = new EventTarget(); 2481cb0ef41Sopenharmony_ci 2491cb0ef41Sopenharmony_ci eventTarget1.addEventListener( 2501cb0ef41Sopenharmony_ci 'foo', 2511cb0ef41Sopenharmony_ci common.mustCall((event) => { 2521cb0ef41Sopenharmony_ci strictEqual(event.eventPhase, CustomEvent.AT_TARGET); 2531cb0ef41Sopenharmony_ci strictEqual(event.target, eventTarget1); 2541cb0ef41Sopenharmony_ci strictEqual(event.detail, obj); 2551cb0ef41Sopenharmony_ci deepStrictEqual(event.composedPath(), [eventTarget1]); 2561cb0ef41Sopenharmony_ci }), 2571cb0ef41Sopenharmony_ci ); 2581cb0ef41Sopenharmony_ci 2591cb0ef41Sopenharmony_ci eventTarget2.addEventListener( 2601cb0ef41Sopenharmony_ci 'foo', 2611cb0ef41Sopenharmony_ci common.mustCall((event) => { 2621cb0ef41Sopenharmony_ci strictEqual(event.eventPhase, CustomEvent.AT_TARGET); 2631cb0ef41Sopenharmony_ci strictEqual(event.target, eventTarget2); 2641cb0ef41Sopenharmony_ci strictEqual(event.detail, obj); 2651cb0ef41Sopenharmony_ci deepStrictEqual(event.composedPath(), [eventTarget2]); 2661cb0ef41Sopenharmony_ci }), 2671cb0ef41Sopenharmony_ci ); 2681cb0ef41Sopenharmony_ci 2691cb0ef41Sopenharmony_ci eventTarget1.dispatchEvent(event); 2701cb0ef41Sopenharmony_ci strictEqual(event.eventPhase, CustomEvent.NONE); 2711cb0ef41Sopenharmony_ci strictEqual(event.target, eventTarget1); 2721cb0ef41Sopenharmony_ci deepStrictEqual(event.composedPath(), []); 2731cb0ef41Sopenharmony_ci 2741cb0ef41Sopenharmony_ci eventTarget2.dispatchEvent(event); 2751cb0ef41Sopenharmony_ci strictEqual(event.eventPhase, CustomEvent.NONE); 2761cb0ef41Sopenharmony_ci strictEqual(event.target, eventTarget2); 2771cb0ef41Sopenharmony_ci deepStrictEqual(event.composedPath(), []); 2781cb0ef41Sopenharmony_ci} 2791cb0ef41Sopenharmony_ci 2801cb0ef41Sopenharmony_ci{ 2811cb0ef41Sopenharmony_ci const obj = { sweet: 'x' }; 2821cb0ef41Sopenharmony_ci const target = new EventTarget(); 2831cb0ef41Sopenharmony_ci const event = new CustomEvent('foo', { detail: obj }); 2841cb0ef41Sopenharmony_ci 2851cb0ef41Sopenharmony_ci strictEqual(event.target, null); 2861cb0ef41Sopenharmony_ci 2871cb0ef41Sopenharmony_ci target.addEventListener( 2881cb0ef41Sopenharmony_ci 'foo', 2891cb0ef41Sopenharmony_ci common.mustCall((event) => { 2901cb0ef41Sopenharmony_ci strictEqual(event.target, target); 2911cb0ef41Sopenharmony_ci strictEqual(event.currentTarget, target); 2921cb0ef41Sopenharmony_ci strictEqual(event.srcElement, target); 2931cb0ef41Sopenharmony_ci strictEqual(event.detail, obj); 2941cb0ef41Sopenharmony_ci }), 2951cb0ef41Sopenharmony_ci ); 2961cb0ef41Sopenharmony_ci target.dispatchEvent(event); 2971cb0ef41Sopenharmony_ci} 2981cb0ef41Sopenharmony_ci 2991cb0ef41Sopenharmony_ci{ 3001cb0ef41Sopenharmony_ci // Event subclassing 3011cb0ef41Sopenharmony_ci const SubEvent = class extends CustomEvent {}; 3021cb0ef41Sopenharmony_ci const ev = new SubEvent('foo', { detail: 56 }); 3031cb0ef41Sopenharmony_ci const eventTarget = new EventTarget(); 3041cb0ef41Sopenharmony_ci const fn = common.mustCall((event) => { 3051cb0ef41Sopenharmony_ci strictEqual(event, ev); 3061cb0ef41Sopenharmony_ci strictEqual(event.detail, 56); 3071cb0ef41Sopenharmony_ci }); 3081cb0ef41Sopenharmony_ci eventTarget.addEventListener('foo', fn, { once: true }); 3091cb0ef41Sopenharmony_ci eventTarget.dispatchEvent(ev); 3101cb0ef41Sopenharmony_ci} 3111cb0ef41Sopenharmony_ci 3121cb0ef41Sopenharmony_ci// Works with inspect 3131cb0ef41Sopenharmony_ci 3141cb0ef41Sopenharmony_ci{ 3151cb0ef41Sopenharmony_ci const ev = new CustomEvent('test'); 3161cb0ef41Sopenharmony_ci const evConstructorName = inspect(ev, { 3171cb0ef41Sopenharmony_ci depth: -1, 3181cb0ef41Sopenharmony_ci }); 3191cb0ef41Sopenharmony_ci strictEqual(evConstructorName, 'CustomEvent'); 3201cb0ef41Sopenharmony_ci 3211cb0ef41Sopenharmony_ci const inspectResult = inspect(ev, { 3221cb0ef41Sopenharmony_ci depth: 1, 3231cb0ef41Sopenharmony_ci }); 3241cb0ef41Sopenharmony_ci ok(inspectResult.includes('CustomEvent')); 3251cb0ef41Sopenharmony_ci} 326