mirror of
https://github.com/nodejs/node.git
synced 2024-11-21 21:19:50 +01:00
74b9cf2ee1
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>
326 lines
8.0 KiB
JavaScript
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'));
|
|
}
|