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