node/test/parallel/test-events-customevent.js
Santiago Gimeno 74b9cf2ee1
lib: define Event.isTrusted in the prototype
Don't conform to the spec with isTrusted. The spec defines it as
`LegacyUnforgeable` but defining it in the constructor has a big
performance impact and the property doesn't seem to be useful outside of
browsers.

Refs: https://github.com/nodejs/performance/issues/32
PR-URL: https://github.com/nodejs/node/pull/46974
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: James M Snell <jasnell@gmail.com>
2023-04-03 17:02:26 +00:00

326 lines
8.0 KiB
JavaScript

// Flags: --expose-internals
'use strict';
const common = require('../common');
const { ok, strictEqual, deepStrictEqual, throws } = require('node:assert');
const { inspect } = require('node:util');
const { Event, EventTarget, CustomEvent } = require('internal/event_target');
{
ok(CustomEvent);
// Default string
const tag = Object.prototype.toString.call(new CustomEvent('$'));
strictEqual(tag, '[object CustomEvent]');
}
{
// No argument behavior - throw TypeError
throws(() => {
new CustomEvent();
}, TypeError);
throws(() => new CustomEvent(Symbol()), TypeError);
// Too many arguments passed behavior - ignore additional arguments
const ev = new CustomEvent('foo', {}, {});
strictEqual(ev.type, 'foo');
}
{
const ev = new CustomEvent('$');
strictEqual(ev.type, '$');
strictEqual(ev.bubbles, false);
strictEqual(ev.cancelable, false);
strictEqual(ev.detail, null);
}
{
// Coercion to string works
strictEqual(new CustomEvent(1).type, '1');
strictEqual(new CustomEvent(false).type, 'false');
strictEqual(new CustomEvent({}).type, String({}));
}
{
const ev = new CustomEvent('$', {
detail: 56,
sweet: 'x',
cancelable: true,
});
strictEqual(ev.type, '$');
strictEqual(ev.bubbles, false);
strictEqual(ev.cancelable, true);
strictEqual(ev.sweet, undefined);
strictEqual(ev.detail, 56);
}
{
// Any types of value for `detail` are acceptable.
['foo', 1, false, [], {}].forEach((i) => {
const ev = new CustomEvent('$', { detail: i });
strictEqual(ev.detail, i);
});
}
{
// Readonly `detail` behavior
const ev = new CustomEvent('$', {
detail: 56,
});
strictEqual(ev.detail, 56);
try {
ev.detail = 96;
// eslint-disable-next-line no-unused-vars
} catch (error) {
common.mustCall()();
}
strictEqual(ev.detail, 56);
}
{
const ev = new Event('$', {
detail: 96,
});
strictEqual(ev.detail, undefined);
}
// The following tests verify whether CustomEvent works the same as Event
// except carrying custom data. They're based on `parallel/test-eventtarget.js`.
{
const ev = new CustomEvent('$');
strictEqual(ev.type, '$');
strictEqual(ev.bubbles, false);
strictEqual(ev.cancelable, false);
strictEqual(ev.detail, null);
strictEqual(ev.defaultPrevented, false);
strictEqual(typeof ev.timeStamp, 'number');
// Compatibility properties with the DOM
deepStrictEqual(ev.composedPath(), []);
strictEqual(ev.returnValue, true);
strictEqual(ev.composed, false);
strictEqual(ev.isTrusted, false);
strictEqual(ev.eventPhase, 0);
strictEqual(ev.cancelBubble, false);
// Not cancelable
ev.preventDefault();
strictEqual(ev.defaultPrevented, false);
}
{
// Invalid options
['foo', 1, false].forEach((i) =>
throws(() => new CustomEvent('foo', i), {
code: 'ERR_INVALID_ARG_TYPE',
name: 'TypeError',
message:
'The "options" argument must be of type object.' +
common.invalidArgTypeHelper(i),
}),
);
}
{
const ev = new CustomEvent('$');
strictEqual(ev.constructor.name, 'CustomEvent');
// CustomEvent Statics
strictEqual(CustomEvent.NONE, 0);
strictEqual(CustomEvent.CAPTURING_PHASE, 1);
strictEqual(CustomEvent.AT_TARGET, 2);
strictEqual(CustomEvent.BUBBLING_PHASE, 3);
strictEqual(new CustomEvent('foo').eventPhase, CustomEvent.NONE);
// CustomEvent is a function
strictEqual(CustomEvent.length, 1);
}
{
const ev = new CustomEvent('foo');
strictEqual(ev.cancelBubble, false);
ev.cancelBubble = true;
strictEqual(ev.cancelBubble, true);
}
{
const ev = new CustomEvent('foo');
strictEqual(ev.cancelBubble, false);
ev.stopPropagation();
strictEqual(ev.cancelBubble, true);
}
{
const ev = new CustomEvent('foo');
strictEqual(ev.cancelBubble, false);
ev.cancelBubble = 'some-truthy-value';
strictEqual(ev.cancelBubble, true);
}
{
const ev = new CustomEvent('foo');
strictEqual(ev.cancelBubble, false);
ev.cancelBubble = true;
strictEqual(ev.cancelBubble, true);
}
{
const ev = new CustomEvent('foo');
strictEqual(ev.cancelBubble, false);
ev.stopPropagation();
strictEqual(ev.cancelBubble, true);
}
{
const ev = new CustomEvent('foo');
strictEqual(ev.cancelBubble, false);
ev.cancelBubble = 'some-truthy-value';
strictEqual(ev.cancelBubble, true);
}
{
const ev = new CustomEvent('foo', { cancelable: true });
strictEqual(ev.type, 'foo');
strictEqual(ev.cancelable, true);
strictEqual(ev.defaultPrevented, false);
ev.preventDefault();
strictEqual(ev.defaultPrevented, true);
}
{
const ev = new CustomEvent('foo');
strictEqual(ev.isTrusted, false);
}
// Works with EventTarget
{
const obj = { sweet: 'x', memory: { x: 56, y: 96 } };
const et = new EventTarget();
const ev = new CustomEvent('$', { detail: obj });
const fn = common.mustCall((event) => {
strictEqual(event, ev);
deepStrictEqual(event.detail, obj);
});
et.addEventListener('$', fn);
et.dispatchEvent(ev);
}
{
const eventTarget = new EventTarget();
const event = new CustomEvent('$');
eventTarget.dispatchEvent(event);
strictEqual(event.target, eventTarget);
}
{
const obj = { sweet: 'x' };
const eventTarget = new EventTarget();
const ev1 = common.mustCall(function(event) {
strictEqual(event.type, 'foo');
strictEqual(event.detail, obj);
strictEqual(this, eventTarget);
strictEqual(event.eventPhase, 2);
}, 2);
const ev2 = {
handleEvent: common.mustCall(function(event) {
strictEqual(event.type, 'foo');
strictEqual(event.detail, obj);
strictEqual(this, ev2);
}),
};
eventTarget.addEventListener('foo', ev1);
eventTarget.addEventListener('foo', ev2, { once: true });
ok(eventTarget.dispatchEvent(new CustomEvent('foo', { detail: obj })));
eventTarget.dispatchEvent(new CustomEvent('foo', { detail: obj }));
eventTarget.removeEventListener('foo', ev1);
eventTarget.dispatchEvent(new CustomEvent('foo'));
}
{
// Same event dispatched multiple times.
const obj = { sweet: 'x' };
const event = new CustomEvent('foo', { detail: obj });
const eventTarget1 = new EventTarget();
const eventTarget2 = new EventTarget();
eventTarget1.addEventListener(
'foo',
common.mustCall((event) => {
strictEqual(event.eventPhase, CustomEvent.AT_TARGET);
strictEqual(event.target, eventTarget1);
strictEqual(event.detail, obj);
deepStrictEqual(event.composedPath(), [eventTarget1]);
}),
);
eventTarget2.addEventListener(
'foo',
common.mustCall((event) => {
strictEqual(event.eventPhase, CustomEvent.AT_TARGET);
strictEqual(event.target, eventTarget2);
strictEqual(event.detail, obj);
deepStrictEqual(event.composedPath(), [eventTarget2]);
}),
);
eventTarget1.dispatchEvent(event);
strictEqual(event.eventPhase, CustomEvent.NONE);
strictEqual(event.target, eventTarget1);
deepStrictEqual(event.composedPath(), []);
eventTarget2.dispatchEvent(event);
strictEqual(event.eventPhase, CustomEvent.NONE);
strictEqual(event.target, eventTarget2);
deepStrictEqual(event.composedPath(), []);
}
{
const obj = { sweet: 'x' };
const target = new EventTarget();
const event = new CustomEvent('foo', { detail: obj });
strictEqual(event.target, null);
target.addEventListener(
'foo',
common.mustCall((event) => {
strictEqual(event.target, target);
strictEqual(event.currentTarget, target);
strictEqual(event.srcElement, target);
strictEqual(event.detail, obj);
}),
);
target.dispatchEvent(event);
}
{
// Event subclassing
const SubEvent = class extends CustomEvent {};
const ev = new SubEvent('foo', { detail: 56 });
const eventTarget = new EventTarget();
const fn = common.mustCall((event) => {
strictEqual(event, ev);
strictEqual(event.detail, 56);
});
eventTarget.addEventListener('foo', fn, { once: true });
eventTarget.dispatchEvent(ev);
}
// Works with inspect
{
const ev = new CustomEvent('test');
const evConstructorName = inspect(ev, {
depth: -1,
});
strictEqual(evConstructorName, 'CustomEvent');
const inspectResult = inspect(ev, {
depth: 1,
});
ok(inspectResult.includes('CustomEvent'));
}