Upload Kmake

This commit is contained in:
Gorochu
2026-05-26 23:36:42 -07:00
parent ba051b2f74
commit 555ec72358
41615 changed files with 13344630 additions and 1 deletions

View File

@ -0,0 +1,96 @@
// META: title=AddEventListenerOptions.once
"use strict";
test(function() {
var invoked_once = false;
var invoked_normal = false;
function handler_once() {
invoked_once = true;
}
function handler_normal() {
invoked_normal = true;
}
const et = new EventTarget();
et.addEventListener('test', handler_once, {once: true});
et.addEventListener('test', handler_normal);
et.dispatchEvent(new Event('test'));
assert_equals(invoked_once, true, "Once handler should be invoked");
assert_equals(invoked_normal, true, "Normal handler should be invoked");
invoked_once = false;
invoked_normal = false;
et.dispatchEvent(new Event('test'));
assert_equals(invoked_once, false, "Once handler shouldn't be invoked again");
assert_equals(invoked_normal, true, "Normal handler should be invoked again");
et.removeEventListener('test', handler_normal);
}, "Once listener should be invoked only once");
test(function() {
const et = new EventTarget();
var invoked_count = 0;
function handler() {
invoked_count++;
if (invoked_count == 1)
et.dispatchEvent(new Event('test'));
}
et.addEventListener('test', handler, {once: true});
et.dispatchEvent(new Event('test'));
assert_equals(invoked_count, 1, "Once handler should only be invoked once");
invoked_count = 0;
function handler2() {
invoked_count++;
if (invoked_count == 1)
et.addEventListener('test', handler2, {once: true});
if (invoked_count <= 2)
et.dispatchEvent(new Event('test'));
}
et.addEventListener('test', handler2, {once: true});
et.dispatchEvent(new Event('test'));
assert_equals(invoked_count, 2, "Once handler should only be invoked once after each adding");
}, "Once listener should be invoked only once even if the event is nested");
test(function() {
var invoked_count = 0;
function handler() {
invoked_count++;
}
const et = new EventTarget();
et.addEventListener('test', handler, {once: true});
et.addEventListener('test', handler);
et.dispatchEvent(new Event('test'));
assert_equals(invoked_count, 1, "The handler should only be added once");
invoked_count = 0;
et.dispatchEvent(new Event('test'));
assert_equals(invoked_count, 0, "The handler was added as a once listener");
invoked_count = 0;
et.addEventListener('test', handler, {once: true});
et.removeEventListener('test', handler);
et.dispatchEvent(new Event('test'));
assert_equals(invoked_count, 0, "The handler should have been removed");
}, "Once listener should be added / removed like normal listeners");
test(function() {
const et = new EventTarget();
var invoked_count = 0;
for (let n = 4; n > 0; n--) {
et.addEventListener('test', (e) => {
invoked_count++;
e.stopImmediatePropagation();
}, {once: true});
}
for (let n = 4; n > 0; n--) {
et.dispatchEvent(new Event('test'));
}
assert_equals(invoked_count, 4, "The listeners should be invoked");
}, "Multiple once listeners should be invoked even if the stopImmediatePropagation is set");

View File

@ -0,0 +1,134 @@
// META: title=AddEventListenerOptions.passive
test(function() {
var supportsPassive = false;
var query_options = {
get passive() {
supportsPassive = true;
return false;
},
get dummy() {
assert_unreached("dummy value getter invoked");
return false;
}
};
const et = new EventTarget();
et.addEventListener('test_event', null, query_options);
assert_true(supportsPassive, "addEventListener doesn't support the passive option");
supportsPassive = false;
et.removeEventListener('test_event', null, query_options);
assert_false(supportsPassive, "removeEventListener supports the passive option when it should not");
}, "Supports passive option on addEventListener only");
function testPassiveValue(optionsValue, expectedDefaultPrevented, existingEventTarget) {
var defaultPrevented = undefined;
var handler = function handler(e) {
assert_false(e.defaultPrevented, "Event prematurely marked defaultPrevented");
e.preventDefault();
defaultPrevented = e.defaultPrevented;
}
const et = existingEventTarget || new EventTarget();
et.addEventListener('test', handler, optionsValue);
var uncanceled = et.dispatchEvent(new Event('test', {bubbles: true, cancelable: true}));
assert_equals(defaultPrevented, expectedDefaultPrevented, "Incorrect defaultPrevented for options: " + JSON.stringify(optionsValue));
assert_equals(uncanceled, !expectedDefaultPrevented, "Incorrect return value from dispatchEvent");
et.removeEventListener('test', handler, optionsValue);
}
test(function() {
testPassiveValue(undefined, true);
testPassiveValue({}, true);
testPassiveValue({passive: false}, true);
testPassiveValue({passive: true}, false);
testPassiveValue({passive: 0}, true);
testPassiveValue({passive: 1}, false);
}, "preventDefault should be ignored if-and-only-if the passive option is true");
function testPassiveValueOnReturnValue(test, optionsValue, expectedDefaultPrevented) {
var defaultPrevented = undefined;
var handler = test.step_func(e => {
assert_false(e.defaultPrevented, "Event prematurely marked defaultPrevented");
e.returnValue = false;
defaultPrevented = e.defaultPrevented;
});
const et = new EventTarget();
et.addEventListener('test', handler, optionsValue);
var uncanceled = et.dispatchEvent(new Event('test', {bubbles: true, cancelable: true}));
assert_equals(defaultPrevented, expectedDefaultPrevented, "Incorrect defaultPrevented for options: " + JSON.stringify(optionsValue));
assert_equals(uncanceled, !expectedDefaultPrevented, "Incorrect return value from dispatchEvent");
et.removeEventListener('test', handler, optionsValue);
}
async_test(t => {
testPassiveValueOnReturnValue(t, undefined, true);
testPassiveValueOnReturnValue(t, {}, true);
testPassiveValueOnReturnValue(t, {passive: false}, true);
testPassiveValueOnReturnValue(t, {passive: true}, false);
testPassiveValueOnReturnValue(t, {passive: 0}, true);
testPassiveValueOnReturnValue(t, {passive: 1}, false);
t.done();
}, "returnValue should be ignored if-and-only-if the passive option is true");
function testPassiveWithOtherHandlers(optionsValue, expectedDefaultPrevented) {
var handlerInvoked1 = false;
var dummyHandler1 = function() {
handlerInvoked1 = true;
};
var handlerInvoked2 = false;
var dummyHandler2 = function() {
handlerInvoked2 = true;
};
const et = new EventTarget();
et.addEventListener('test', dummyHandler1, {passive:true});
et.addEventListener('test', dummyHandler2);
testPassiveValue(optionsValue, expectedDefaultPrevented, et);
assert_true(handlerInvoked1, "Extra passive handler not invoked");
assert_true(handlerInvoked2, "Extra non-passive handler not invoked");
et.removeEventListener('test', dummyHandler1);
et.removeEventListener('test', dummyHandler2);
}
test(function() {
testPassiveWithOtherHandlers({}, true);
testPassiveWithOtherHandlers({passive: false}, true);
testPassiveWithOtherHandlers({passive: true}, false);
}, "passive behavior of one listener should be unaffected by the presence of other listeners");
function testOptionEquivalence(optionValue1, optionValue2, expectedEquality) {
var invocationCount = 0;
var handler = function handler(e) {
invocationCount++;
}
const et = new EventTarget();
et.addEventListener('test', handler, optionValue1);
et.addEventListener('test', handler, optionValue2);
et.dispatchEvent(new Event('test', {bubbles: true}));
assert_equals(invocationCount, expectedEquality ? 1 : 2, "equivalence of options " +
JSON.stringify(optionValue1) + " and " + JSON.stringify(optionValue2));
et.removeEventListener('test', handler, optionValue1);
et.removeEventListener('test', handler, optionValue2);
}
test(function() {
// Sanity check options that should be treated as distinct handlers
testOptionEquivalence({capture:true}, {capture:false, passive:false}, false);
testOptionEquivalence({capture:true}, {passive:true}, false);
// Option values that should be treated as equivalent
testOptionEquivalence({}, {passive:false}, true);
testOptionEquivalence({passive:true}, {passive:false}, true);
testOptionEquivalence(undefined, {passive:true}, true);
testOptionEquivalence({capture: true, passive: false}, {capture: true, passive: true}, true);
}, "Equivalence of option values");

View File

@ -0,0 +1,143 @@
'use strict';
test(function() {
let count = 0;
function handler() {
count++;
}
const et = new EventTarget();
const controller = new AbortController();
et.addEventListener('test', handler, { signal: controller.signal });
et.dispatchEvent(new Event('test'));
assert_equals(count, 1, "Adding a signal still adds a listener");
et.dispatchEvent(new Event('test'));
assert_equals(count, 2, "The listener was not added with the once flag");
controller.abort();
et.dispatchEvent(new Event('test'));
assert_equals(count, 2, "Aborting on the controller removes the listener");
et.addEventListener('test', handler, { signal: controller.signal });
et.dispatchEvent(new Event('test'));
assert_equals(count, 2, "Passing an aborted signal never adds the handler");
}, "Passing an AbortSignal to addEventListener options should allow removing a listener");
test(function() {
let count = 0;
function handler() {
count++;
}
const et = new EventTarget();
const controller = new AbortController();
et.addEventListener('test', handler, { signal: controller.signal });
et.removeEventListener('test', handler);
et.dispatchEvent(new Event('test'));
assert_equals(count, 0, "The listener was still removed");
}, "Passing an AbortSignal to addEventListener does not prevent removeEventListener");
test(function() {
let count = 0;
function handler() {
count++;
}
const et = new EventTarget();
const controller = new AbortController();
et.addEventListener('test', handler, { signal: controller.signal, once: true });
controller.abort();
et.dispatchEvent(new Event('test'));
assert_equals(count, 0, "The listener was still removed");
}, "Passing an AbortSignal to addEventListener works with the once flag");
test(function() {
let count = 0;
function handler() {
count++;
}
const et = new EventTarget();
const controller = new AbortController();
et.addEventListener('test', handler, { signal: controller.signal, once: true });
et.removeEventListener('test', handler);
et.dispatchEvent(new Event('test'));
assert_equals(count, 0, "The listener was still removed");
}, "Removing a once listener works with a passed signal");
test(function() {
let count = 0;
function handler() {
count++;
}
const et = new EventTarget();
const controller = new AbortController();
et.addEventListener('first', handler, { signal: controller.signal, once: true });
et.addEventListener('second', handler, { signal: controller.signal, once: true });
controller.abort();
et.dispatchEvent(new Event('first'));
et.dispatchEvent(new Event('second'));
assert_equals(count, 0, "The listener was still removed");
}, "Passing an AbortSignal to multiple listeners");
test(function() {
let count = 0;
function handler() {
count++;
}
const et = new EventTarget();
const controller = new AbortController();
et.addEventListener('test', handler, { signal: controller.signal, capture: true });
controller.abort();
et.dispatchEvent(new Event('test'));
assert_equals(count, 0, "The listener was still removed");
}, "Passing an AbortSignal to addEventListener works with the capture flag");
test(function() {
let count = 0;
function handler() {
count++;
}
const et = new EventTarget();
const controller = new AbortController();
et.addEventListener('test', () => {
controller.abort();
}, { signal: controller.signal });
et.addEventListener('test', handler, { signal: controller.signal });
et.dispatchEvent(new Event('test'));
assert_equals(count, 0, "The listener was still removed");
}, "Aborting from a listener does not call future listeners");
test(function() {
let count = 0;
function handler() {
count++;
}
const et = new EventTarget();
const controller = new AbortController();
et.addEventListener('test', () => {
et.addEventListener('test', handler, { signal: controller.signal });
controller.abort();
}, { signal: controller.signal });
et.dispatchEvent(new Event('test'));
assert_equals(count, 0, "The listener was still removed");
}, "Adding then aborting a listener in another listener does not call it");
test(function() {
const et = new EventTarget();
const ac = new AbortController();
let count = 0;
et.addEventListener('foo', () => {
et.addEventListener('foo', () => {
count++;
if (count > 5) ac.abort();
et.dispatchEvent(new Event('foo'));
}, { signal: ac.signal });
et.dispatchEvent(new Event('foo'));
}, { once: true });
et.dispatchEvent(new Event('foo'));
}, "Aborting from a nested listener should remove it");
test(function() {
const et = new EventTarget();
assert_throws_js(TypeError, () => { et.addEventListener("foo", () => {}, { signal: null }); });
}, "Passing null as the signal should throw");
test(function() {
const et = new EventTarget();
assert_throws_js(TypeError, () => { et.addEventListener("foo", null, { signal: null }); });
}, "Passing null as the signal should throw (listener is also null)");

View File

@ -0,0 +1,123 @@
<!DOCTYPE html>
<html>
<title>HTMLBodyElement and HTMLFrameSetElement Event Handler Tests</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script>
function getObject(interface) {
switch(interface) {
case "Element":
var e = document.createElementNS("http://example.com/", "example");
assert_true(e instanceof Element);
assert_false(e instanceof HTMLElement);
assert_false(e instanceof SVGElement);
return e;
case "HTMLElement":
var e = document.createElement("html");
assert_true(e instanceof HTMLElement);
return e;
case "HTMLBodyElement":
var e = document.createElement("body");
assert_true(e instanceof HTMLBodyElement);
return e;
case "HTMLFormElement":
var e = document.createElement("form");
assert_true(e instanceof HTMLFormElement);
return e;
case "HTMLFrameSetElement":
var e = document.createElement("frameset");
assert_true(e instanceof HTMLFrameSetElement);
return e;
case "SVGElement":
var e = document.createElementNS("http://www.w3.org/2000/svg", "rect");
assert_true(e instanceof SVGElement);
return e;
case "Document":
assert_true(document instanceof Document);
return document;
case "Window":
assert_true(window instanceof Window);
return window;
}
assert_unreached();
}
function testSet(interface, attribute) {
test(function() {
var object = getObject(interface);
function nop() {}
assert_equals(object[attribute], null, "Initially null");
object[attribute] = nop;
assert_equals(object[attribute], nop, "Return same function");
object[attribute] = "";
assert_equals(object[attribute], null, "Return null after setting string");
object[attribute] = null;
assert_equals(object[attribute], null, "Finally null");
}, "Set " + interface + "." + attribute);
}
function testReflect(interface, attribute) {
test(function() {
var element = getObject(interface);
assert_false(element.hasAttribute(attribute), "Initially missing");
element.setAttribute(attribute, "return");
assert_equals(element.getAttribute(attribute), "return", "Return same string");
assert_equals(typeof element[attribute], "function", "Convert to function");
element.removeAttribute(attribute);
}, "Reflect " + interface + "." + attribute);
}
function testForwardToWindow(interface, attribute) {
test(function() {
var element = getObject(interface);
window[attribute] = null;
element.setAttribute(attribute, "return");
assert_equals(typeof window[attribute], "function", "Convert to function");
assert_equals(window[attribute], element[attribute], "Forward content attribute");
function nop() {}
element[attribute] = nop;
assert_equals(window[attribute], nop, "Forward IDL attribute");
window[attribute] = null;
}, "Forward " + interface + "." + attribute + " to Window");
}
// Object.propertyIsEnumerable cannot be used because it doesn't
// work with properties inherited through the prototype chain.
function getEnumerable(interface) {
var enumerable = {};
for (var attribute in getObject(interface)) {
enumerable[attribute] = true;
}
return enumerable;
}
var enumerableCache = {};
function testEnumerate(interface, attribute) {
if (!(interface in enumerableCache)) {
enumerableCache[interface] = getEnumerable(interface);
}
test(function() {
assert_true(enumerableCache[interface][attribute]);
}, "Enumerate " + interface + "." + attribute);
}
[
"onblur",
"onerror",
"onfocus",
"onload",
"onscroll",
"onresize"
].forEach(function(attribute) {
testSet("HTMLBodyElement", attribute);
testEnumerate("HTMLBodyElement", attribute);
testReflect("HTMLBodyElement", attribute);
testForwardToWindow("HTMLBodyElement", attribute);
testSet("HTMLFrameSetElement", attribute);
testEnumerate("HTMLFrameSetElement", attribute);
testReflect("HTMLFrameSetElement", attribute);
testForwardToWindow("HTMLFrameSetElement", attribute);
});
</script>
</html>

View File

@ -0,0 +1,35 @@
<!doctype html>
<title>CustomEvent</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<div id="log"></div>
<script>
test(function() {
var type = "foo";
var target = document.createElement("div");
target.addEventListener(type, this.step_func(function(evt) {
assert_equals(evt.type, type);
}), true);
var fooEvent = document.createEvent("CustomEvent");
fooEvent.initEvent(type, true, true);
target.dispatchEvent(fooEvent);
}, "CustomEvent dispatching.");
test(function() {
var e = document.createEvent("CustomEvent");
assert_throws_js(TypeError, function() {
e.initCustomEvent();
});
}, "First parameter to initCustomEvent should be mandatory.");
test(function() {
var e = document.createEvent("CustomEvent");
e.initCustomEvent("foo");
assert_equals(e.type, "foo", "type");
assert_false(e.bubbles, "bubbles");
assert_false(e.cancelable, "cancelable");
assert_equals(e.detail, null, "detail");
}, "initCustomEvent's default parameter values.");
</script>

View File

@ -0,0 +1,132 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Event.cancelBubble</title>
<link rel="author" title="Chris Rebert" href="http://chrisrebert.com">
<link rel="help" href="https://dom.spec.whatwg.org/#dom-event-cancelbubble">
<meta name="flags" content="dom">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
</head>
<body>
<div id="outer">
<div id="middle">
<div id="inner"></div>
</div>
</div>
<script>
test(function () {
// See https://dom.spec.whatwg.org/#stop-propagation-flag
var e = document.createEvent('Event');
assert_false(e.cancelBubble, "cancelBubble must be false after event creation.");
}, "cancelBubble must be false when an event is initially created.");
test(function () {
// See https://dom.spec.whatwg.org/#concept-event-initialize
// Event which bubbles.
var one = document.createEvent('Event');
one.cancelBubble = true;
one.initEvent('foo', true/*bubbles*/, false/*cancelable*/);
assert_false(one.cancelBubble, "initEvent() must set cancelBubble to false. [bubbles=true]");
// Re-initialization.
one.cancelBubble = true;
one.initEvent('foo', true/*bubbles*/, false/*cancelable*/);
assert_false(one.cancelBubble, "2nd initEvent() call must set cancelBubble to false. [bubbles=true]");
// Event which doesn't bubble.
var two = document.createEvent('Event');
two.cancelBubble = true;
two.initEvent('foo', false/*bubbles*/, false/*cancelable*/);
assert_false(two.cancelBubble, "initEvent() must set cancelBubble to false. [bubbles=false]");
// Re-initialization.
two.cancelBubble = true;
two.initEvent('foo', false/*bubbles*/, false/*cancelable*/);
assert_false(two.cancelBubble, "2nd initEvent() call must set cancelBubble to false. [bubbles=false]");
}, "Initializing an event must set cancelBubble to false.");
test(function () {
// See https://dom.spec.whatwg.org/#dom-event-stoppropagation
var e = document.createEvent('Event');
e.stopPropagation();
assert_true(e.cancelBubble, "stopPropagation() must set cancelBubble to true.");
}, "stopPropagation() must set cancelBubble to true.");
test(function () {
// See https://dom.spec.whatwg.org/#dom-event-stopimmediatepropagation
var e = document.createEvent('Event');
e.stopImmediatePropagation();
assert_true(e.cancelBubble, "stopImmediatePropagation() must set cancelBubble to true.");
}, "stopImmediatePropagation() must set cancelBubble to true.");
test(function () {
var one = document.createEvent('Event');
one.stopPropagation();
one.cancelBubble = false;
assert_true(one.cancelBubble, "cancelBubble must still be true after attempting to set it to false.");
}, "Event.cancelBubble=false must have no effect.");
test(function (t) {
var outer = document.getElementById('outer');
var middle = document.getElementById('middle');
var inner = document.getElementById('inner');
outer.addEventListener('barbaz', t.step_func(function () {
assert_unreached("Setting Event.cancelBubble=false after setting Event.cancelBubble=true should have no effect.");
}), false/*useCapture*/);
middle.addEventListener('barbaz', function (e) {
e.cancelBubble = true;// Stop propagation.
e.cancelBubble = false;// Should be a no-op.
}, false/*useCapture*/);
var barbazEvent = document.createEvent('Event');
barbazEvent.initEvent('barbaz', true/*bubbles*/, false/*cancelable*/);
inner.dispatchEvent(barbazEvent);
}, "Event.cancelBubble=false must have no effect during event propagation.");
test(function () {
// See https://dom.spec.whatwg.org/#concept-event-dispatch
// "14. Unset events [...] stop propagation flag,"
var e = document.createEvent('Event');
e.initEvent('foobar', true/*bubbles*/, true/*cancelable*/);
document.body.addEventListener('foobar', function listener(e) {
e.stopPropagation();
});
document.body.dispatchEvent(e);
assert_false(e.cancelBubble, "cancelBubble must be false after an event has been dispatched.");
}, "cancelBubble must be false after an event has been dispatched.");
test(function (t) {
var outer = document.getElementById('outer');
var middle = document.getElementById('middle');
var inner = document.getElementById('inner');
var propagationStopper = function (e) {
e.cancelBubble = true;
};
// Bubble phase
middle.addEventListener('bar', propagationStopper, false/*useCapture*/);
outer.addEventListener('bar', t.step_func(function listenerOne() {
assert_unreached("Setting cancelBubble=true should stop the event from bubbling further.");
}), false/*useCapture*/);
var barEvent = document.createEvent('Event');
barEvent.initEvent('bar', true/*bubbles*/, false/*cancelable*/);
inner.dispatchEvent(barEvent);
// Capture phase
outer.addEventListener('qux', propagationStopper, true/*useCapture*/);
middle.addEventListener('qux', t.step_func(function listenerTwo() {
assert_unreached("Setting cancelBubble=true should stop the event from propagating further, including during the Capture Phase.");
}), true/*useCapture*/);
var quxEvent = document.createEvent('Event');
quxEvent.initEvent('qux', false/*bubbles*/, false/*cancelable*/);
inner.dispatchEvent(quxEvent);
}, "Event.cancelBubble=true must set the stop propagation flag.");
</script>
</body>
</html>

View File

@ -0,0 +1,23 @@
<!doctype html>
<title>Event constants</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="../constants.js"></script>
<div id="log"></div>
<script>
var objects;
setup(function() {
objects = [
[Event, "Event interface object"],
[Event.prototype, "Event prototype object"],
[document.createEvent("Event"), "Event object"],
[document.createEvent("CustomEvent"), "CustomEvent object"]
]
})
testConstants(objects, [
["NONE", 0],
["CAPTURING_PHASE", 1],
["AT_TARGET", 2],
["BUBBLING_PHASE", 3]
], "eventPhase")
</script>

View File

@ -0,0 +1,120 @@
// META: title=Event constructors
test(function() {
assert_throws_js(
TypeError,
() => Event(""),
"Calling Event constructor without 'new' must throw")
})
test(function() {
assert_throws_js(TypeError, function() {
new Event()
})
})
test(function() {
var test_error = { name: "test" }
assert_throws_exactly(test_error, function() {
new Event({ toString: function() { throw test_error; } })
})
})
test(function() {
var ev = new Event("")
assert_equals(ev.type, "")
assert_equals(ev.target, null)
assert_equals(ev.srcElement, null)
assert_equals(ev.currentTarget, null)
assert_equals(ev.eventPhase, Event.NONE)
assert_equals(ev.bubbles, false)
assert_equals(ev.cancelable, false)
assert_equals(ev.defaultPrevented, false)
assert_equals(ev.returnValue, true)
assert_equals(ev.isTrusted, false)
assert_true(ev.timeStamp > 0)
assert_true("initEvent" in ev)
})
test(function() {
var ev = new Event("test")
assert_equals(ev.type, "test")
assert_equals(ev.target, null)
assert_equals(ev.srcElement, null)
assert_equals(ev.currentTarget, null)
assert_equals(ev.eventPhase, Event.NONE)
assert_equals(ev.bubbles, false)
assert_equals(ev.cancelable, false)
assert_equals(ev.defaultPrevented, false)
assert_equals(ev.returnValue, true)
assert_equals(ev.isTrusted, false)
assert_true(ev.timeStamp > 0)
assert_true("initEvent" in ev)
})
test(function() {
assert_throws_js(TypeError, function() { Event("test") },
'Calling Event constructor without "new" must throw');
})
test(function() {
var ev = new Event("I am an event", { bubbles: true, cancelable: false})
assert_equals(ev.type, "I am an event")
assert_equals(ev.bubbles, true)
assert_equals(ev.cancelable, false)
})
test(function() {
var ev = new Event("@", { bubblesIGNORED: true, cancelable: true})
assert_equals(ev.type, "@")
assert_equals(ev.bubbles, false)
assert_equals(ev.cancelable, true)
})
test(function() {
var ev = new Event("@", { "bubbles\0IGNORED": true, cancelable: true})
assert_equals(ev.type, "@")
assert_equals(ev.bubbles, false)
assert_equals(ev.cancelable, true)
})
test(function() {
var ev = new Event("Xx", { cancelable: true})
assert_equals(ev.type, "Xx")
assert_equals(ev.bubbles, false)
assert_equals(ev.cancelable, true)
})
test(function() {
var ev = new Event("Xx", {})
assert_equals(ev.type, "Xx")
assert_equals(ev.bubbles, false)
assert_equals(ev.cancelable, false)
})
test(function() {
var ev = new Event("Xx", {bubbles: true, cancelable: false, sweet: "x"})
assert_equals(ev.type, "Xx")
assert_equals(ev.bubbles, true)
assert_equals(ev.cancelable, false)
assert_equals(ev.sweet, undefined)
})
test(function() {
var called = []
var ev = new Event("Xx", {
get cancelable() {
called.push("cancelable")
return false
},
get bubbles() {
called.push("bubbles")
return true;
},
get sweet() {
called.push("sweet")
return "x"
}
})
assert_array_equals(called, ["bubbles", "cancelable"])
assert_equals(ev.type, "Xx")
assert_equals(ev.bubbles, true)
assert_equals(ev.cancelable, false)
assert_equals(ev.sweet, undefined)
})
test(function() {
var ev = new CustomEvent("$", {detail: 54, sweet: "x", sweet2: "x", cancelable:true})
assert_equals(ev.type, "$")
assert_equals(ev.bubbles, false)
assert_equals(ev.cancelable, true)
assert_equals(ev.sweet, undefined)
assert_equals(ev.detail, 54)
})

View File

@ -0,0 +1,44 @@
<!DOCTYPE html>
<meta charset=utf-8>
<title>Event.defaultPrevented is not reset after dispatchEvent()</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
</head>
<body>
<div id=log></div>
<input id="target" type="hidden" value=""/>
<script>
test(function() {
var EVENT = "foo";
var TARGET = document.getElementById("target");
var evt = document.createEvent("Event");
evt.initEvent(EVENT, true, true);
TARGET.addEventListener(EVENT, this.step_func(function(e) {
e.preventDefault();
assert_true(e.defaultPrevented, "during dispatch");
}), true);
TARGET.dispatchEvent(evt);
assert_true(evt.defaultPrevented, "after dispatch");
assert_equals(evt.target, TARGET);
assert_equals(evt.srcElement, TARGET);
}, "Default prevention via preventDefault");
test(function() {
var EVENT = "foo";
var TARGET = document.getElementById("target");
var evt = document.createEvent("Event");
evt.initEvent(EVENT, true, true);
TARGET.addEventListener(EVENT, this.step_func(function(e) {
e.returnValue = false;
assert_true(e.defaultPrevented, "during dispatch");
}), true);
TARGET.dispatchEvent(evt);
assert_true(evt.defaultPrevented, "after dispatch");
assert_equals(evt.target, TARGET);
assert_equals(evt.srcElement, TARGET);
}, "Default prevention via returnValue");
</script>

View File

@ -0,0 +1,55 @@
<!doctype html>
<title>Event.defaultPrevented</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<div id="log"></div>
<script>
var ev;
test(function() {
ev = document.createEvent("Event");
assert_equals(ev.defaultPrevented, false, "defaultPrevented");
}, "When an event is created, defaultPrevented should be initialized to false.");
test(function() {
ev.initEvent("foo", true, false);
assert_equals(ev.bubbles, true, "bubbles");
assert_equals(ev.cancelable, false, "cancelable");
assert_equals(ev.defaultPrevented, false, "defaultPrevented");
}, "initEvent should work correctly (not cancelable).");
test(function() {
assert_equals(ev.cancelable, false, "cancelable (before)");
ev.preventDefault();
assert_equals(ev.cancelable, false, "cancelable (after)");
assert_equals(ev.defaultPrevented, false, "defaultPrevented");
}, "preventDefault() should not change defaultPrevented if cancelable is false.");
test(function() {
assert_equals(ev.cancelable, false, "cancelable (before)");
ev.returnValue = false;
assert_equals(ev.cancelable, false, "cancelable (after)");
assert_equals(ev.defaultPrevented, false, "defaultPrevented");
}, "returnValue should not change defaultPrevented if cancelable is false.");
test(function() {
ev.initEvent("foo", true, true);
assert_equals(ev.bubbles, true, "bubbles");
assert_equals(ev.cancelable, true, "cancelable");
assert_equals(ev.defaultPrevented, false, "defaultPrevented");
}, "initEvent should work correctly (cancelable).");
test(function() {
assert_equals(ev.cancelable, true, "cancelable (before)");
ev.preventDefault();
assert_equals(ev.cancelable, true, "cancelable (after)");
assert_equals(ev.defaultPrevented, true, "defaultPrevented");
}, "preventDefault() should change defaultPrevented if cancelable is true.");
test(function() {
ev.initEvent("foo", true, true);
assert_equals(ev.cancelable, true, "cancelable (before)");
ev.returnValue = false;
assert_equals(ev.cancelable, true, "cancelable (after)");
assert_equals(ev.defaultPrevented, true, "defaultPrevented");
}, "returnValue should change defaultPrevented if cancelable is true.");
test(function() {
ev.initEvent("foo", true, true);
assert_equals(ev.bubbles, true, "bubbles");
assert_equals(ev.cancelable, true, "cancelable");
assert_equals(ev.defaultPrevented, false, "defaultPrevented");
}, "initEvent should unset defaultPrevented.");
</script>

View File

@ -0,0 +1,59 @@
<!DOCTYPE html>
<html>
<head>
<title>Setting cancelBubble=true prior to dispatchEvent()</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
</head>
<body>
<div id="log"></div>
<table id="table" border="1" style="display: none">
<tbody id="table-body">
<tr id="table-row">
<td id="table-cell">Shady Grove</td>
<td>Aeolian</td>
</tr>
<tr id="parent">
<td id="target">Over the river, Charlie</td>
<td>Dorian</td>
</tr>
</tbody>
</table>
<script>
test(function() {
var event = "foo";
var target = document.getElementById("target");
var parent = document.getElementById("parent");
var tbody = document.getElementById("table-body");
var table = document.getElementById("table");
var body = document.body;
var html = document.documentElement;
var current_targets = [window, document, html, body, table, tbody, parent, target];
var expected_targets = [];
var actual_targets = [];
var expected_phases = [];
var actual_phases = [];
var test_event = function(evt) {
actual_targets.push(evt.currentTarget);
actual_phases.push(evt.eventPhase);
};
for (var i = 0; i < current_targets.length; ++i) {
current_targets[i].addEventListener(event, test_event, true);
current_targets[i].addEventListener(event, test_event, false);
}
var evt = document.createEvent("Event");
evt.initEvent(event, true, true);
evt.cancelBubble = true;
target.dispatchEvent(evt);
assert_array_equals(actual_targets, expected_targets, "actual_targets");
assert_array_equals(actual_phases, expected_phases, "actual_phases");
});
</script>
</body>
</html>

View File

@ -0,0 +1,98 @@
<!DOCTYPE html>
<meta charset=utf-8>
<title> Event.bubbles attribute is set to false </title>
<link rel="help" href="https://dom.spec.whatwg.org/#dom-event-initevent">
<link rel="help" href="https://dom.spec.whatwg.org/#concept-event-dispatch">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<div id=log></div>
<table id="table" border="1" style="display: none">
<tbody id="table-body">
<tr id="table-row">
<td id="table-cell">Shady Grove</td>
<td>Aeolian</td>
</tr>
<tr id="parent">
<td id="target">Over the river, Charlie</td>
<td>Dorian</td>
</tr>
</tbody>
</table>
<script>
function targetsForDocumentChain(document) {
return [
document,
document.documentElement,
document.getElementsByTagName("body")[0],
document.getElementById("table"),
document.getElementById("table-body"),
document.getElementById("parent")
];
}
function testChain(document, targetParents, phases, event_type) {
var target = document.getElementById("target");
var targets = targetParents.concat(target);
var expected_targets = targets.concat(target);
var actual_targets = [], actual_phases = [];
var test_event = function(evt) {
actual_targets.push(evt.currentTarget);
actual_phases.push(evt.eventPhase);
}
for (var i = 0; i < targets.length; i++) {
targets[i].addEventListener(event_type, test_event, true);
targets[i].addEventListener(event_type, test_event, false);
}
var evt = document.createEvent("Event");
evt.initEvent(event_type, false, true);
target.dispatchEvent(evt);
assert_array_equals(actual_targets, expected_targets, "targets");
assert_array_equals(actual_phases, phases, "phases");
}
var phasesForDocumentChain = [
Event.CAPTURING_PHASE,
Event.CAPTURING_PHASE,
Event.CAPTURING_PHASE,
Event.CAPTURING_PHASE,
Event.CAPTURING_PHASE,
Event.CAPTURING_PHASE,
Event.AT_TARGET,
Event.AT_TARGET,
];
test(function () {
var chainWithWindow = [window].concat(targetsForDocumentChain(document));
testChain(
document, chainWithWindow, [Event.CAPTURING_PHASE].concat(phasesForDocumentChain), "click");
}, "In window.document with click event");
test(function () {
testChain(document, targetsForDocumentChain(document), phasesForDocumentChain, "load");
}, "In window.document with load event")
test(function () {
var documentClone = document.cloneNode(true);
testChain(
documentClone, targetsForDocumentChain(documentClone), phasesForDocumentChain, "click");
}, "In window.document.cloneNode(true)");
test(function () {
var newDocument = new Document();
newDocument.appendChild(document.documentElement.cloneNode(true));
testChain(
newDocument, targetsForDocumentChain(newDocument), phasesForDocumentChain, "click");
}, "In new Document()");
test(function () {
var HTMLDocument = document.implementation.createHTMLDocument();
HTMLDocument.body.appendChild(document.getElementById("table").cloneNode(true));
testChain(
HTMLDocument, targetsForDocumentChain(HTMLDocument), phasesForDocumentChain, "click");
}, "In DOMImplementation.createHTMLDocument()");
</script>

View File

@ -0,0 +1,108 @@
<!DOCTYPE html>
<meta charset=utf-8>
<title> Event.bubbles attribute is set to false </title>
<link rel="help" href="https://dom.spec.whatwg.org/#dom-event-initevent">
<link rel="help" href="https://dom.spec.whatwg.org/#concept-event-dispatch">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<div id=log></div>
<table id="table" border="1" style="display: none">
<tbody id="table-body">
<tr id="table-row">
<td id="table-cell">Shady Grove</td>
<td>Aeolian</td>
</tr>
<tr id="parent">
<td id="target">Over the river, Charlie</td>
<td>Dorian</td>
</tr>
</tbody>
</table>
<script>
function concatReverse(a) {
return a.concat(a.map(function(x) { return x }).reverse());
}
function targetsForDocumentChain(document) {
return [
document,
document.documentElement,
document.getElementsByTagName("body")[0],
document.getElementById("table"),
document.getElementById("table-body"),
document.getElementById("parent")
];
}
function testChain(document, targetParents, phases, event_type) {
var target = document.getElementById("target");
var targets = targetParents.concat(target);
var expected_targets = concatReverse(targets);
var actual_targets = [], actual_phases = [];
var test_event = function(evt) {
actual_targets.push(evt.currentTarget);
actual_phases.push(evt.eventPhase);
}
for (var i = 0; i < targets.length; i++) {
targets[i].addEventListener(event_type, test_event, true);
targets[i].addEventListener(event_type, test_event, false);
}
var evt = document.createEvent("Event");
evt.initEvent(event_type, true, true);
target.dispatchEvent(evt);
assert_array_equals(actual_targets, expected_targets, "targets");
assert_array_equals(actual_phases, phases, "phases");
}
var phasesForDocumentChain = [
Event.CAPTURING_PHASE,
Event.CAPTURING_PHASE,
Event.CAPTURING_PHASE,
Event.CAPTURING_PHASE,
Event.CAPTURING_PHASE,
Event.CAPTURING_PHASE,
Event.AT_TARGET,
Event.AT_TARGET,
Event.BUBBLING_PHASE,
Event.BUBBLING_PHASE,
Event.BUBBLING_PHASE,
Event.BUBBLING_PHASE,
Event.BUBBLING_PHASE,
Event.BUBBLING_PHASE,
];
test(function () {
var chainWithWindow = [window].concat(targetsForDocumentChain(document));
var phases = [Event.CAPTURING_PHASE].concat(phasesForDocumentChain, Event.BUBBLING_PHASE);
testChain(document, chainWithWindow, phases, "click");
}, "In window.document with click event");
test(function () {
testChain(document, targetsForDocumentChain(document), phasesForDocumentChain, "load");
}, "In window.document with load event")
test(function () {
var documentClone = document.cloneNode(true);
testChain(
documentClone, targetsForDocumentChain(documentClone), phasesForDocumentChain, "click");
}, "In window.document.cloneNode(true)");
test(function () {
var newDocument = new Document();
newDocument.appendChild(document.documentElement.cloneNode(true));
testChain(
newDocument, targetsForDocumentChain(newDocument), phasesForDocumentChain, "click");
}, "In new Document()");
test(function () {
var HTMLDocument = document.implementation.createHTMLDocument();
HTMLDocument.body.appendChild(document.getElementById("table").cloneNode(true));
testChain(
HTMLDocument, targetsForDocumentChain(HTMLDocument), phasesForDocumentChain, "click");
}, "In DOMImplementation.createHTMLDocument()");
</script>

View File

@ -0,0 +1,425 @@
<!doctype html>
<title>Synthetic click event "magic"</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<div id=log></div>
<div id=dump style=display:none></div>
<script>
var dump = document.getElementById("dump")
async_test(function(t) {
var input = document.createElement("input")
input.type = "checkbox"
dump.appendChild(input)
input.onclick = t.step_func_done(function() {
assert_true(input.checked)
})
input.click()
}, "basic with click()")
async_test(function(t) {
var input = document.createElement("input")
input.type = "checkbox"
dump.appendChild(input)
input.onclick = t.step_func_done(function() {
assert_true(input.checked)
})
input.dispatchEvent(new MouseEvent("click", {bubbles:true})) // equivalent to the above
}, "basic with dispatchEvent()")
async_test(function(t) {
var input = document.createElement("input")
input.type = "checkbox"
dump.appendChild(input)
input.onclick = t.step_func_done(function() {
assert_false(input.checked)
})
input.dispatchEvent(new Event("click", {bubbles:true})) // no MouseEvent
}, "basic with wrong event class")
async_test(function(t) {
var input = document.createElement("input")
input.type = "checkbox"
dump.appendChild(input)
var child = input.appendChild(new Text("does not matter"))
child.dispatchEvent(new MouseEvent("click")) // does not bubble
assert_false(input.checked)
t.done()
}, "look at parents only when event bubbles")
async_test(function(t) {
var input = document.createElement("input")
input.type = "checkbox"
dump.appendChild(input)
input.onclick = t.step_func_done(function() {
assert_true(input.checked)
})
var child = input.appendChild(new Text("does not matter"))
child.dispatchEvent(new MouseEvent("click", {bubbles:true}))
}, "look at parents when event bubbles")
async_test(function(t) {
var input = document.createElement("input")
input.type = "checkbox"
dump.appendChild(input)
input.onclick = t.step_func(function() {
assert_false(input.checked, "input pre-click must not be triggered")
})
var child = input.appendChild(document.createElement("input"))
child.type = "checkbox"
child.onclick = t.step_func(function() {
assert_true(child.checked, "child pre-click must be triggered")
})
child.dispatchEvent(new MouseEvent("click", {bubbles:true}))
t.done()
}, "pick the first with activation behavior <input type=checkbox>")
async_test(function(t) { // as above with <a>
window.hrefComplete = t.step_func(function(a) {
assert_equals(a, 'child');
t.done();
});
var link = document.createElement("a")
link.href = "javascript:hrefComplete('link')" // must not be triggered
dump.appendChild(link)
var child = link.appendChild(document.createElement("a"))
child.href = "javascript:hrefComplete('child')"
child.dispatchEvent(new MouseEvent("click", {bubbles:true}))
}, "pick the first with activation behavior <a href>")
async_test(function(t) {
var input = document.createElement("input")
input.type = "radio"
dump.appendChild(input)
input.onclick = t.step_func(function() {
assert_false(input.checked, "input pre-click must not be triggered")
})
var child = input.appendChild(document.createElement("input"))
child.type = "radio"
child.onclick = t.step_func(function() {
assert_true(child.checked, "child pre-click must be triggered")
})
child.dispatchEvent(new MouseEvent("click", {bubbles:true}))
t.done()
}, "pick the first with activation behavior <input type=radio>")
async_test(function(t) {
var input = document.createElement("input")
input.type = "checkbox"
dump.appendChild(input)
var clickEvent = new MouseEvent("click")
input.onchange = t.step_func_done(function() {
assert_false(clickEvent.defaultPrevented)
assert_true(clickEvent.returnValue)
assert_equals(clickEvent.eventPhase, 0)
assert_equals(clickEvent.currentTarget, null)
assert_equals(clickEvent.target, input)
assert_equals(clickEvent.srcElement, input)
assert_equals(clickEvent.composedPath().length, 0)
})
input.dispatchEvent(clickEvent)
}, "event state during post-click handling")
async_test(function(t) {
var input = document.createElement("input")
input.type = "checkbox"
dump.appendChild(input)
var clickEvent = new MouseEvent("click")
var finalTarget = document.createElement("doesnotmatter")
finalTarget.onclick = t.step_func_done(function() {
assert_equals(clickEvent.target, finalTarget)
assert_equals(clickEvent.srcElement, finalTarget)
})
input.onchange = t.step_func(function() {
finalTarget.dispatchEvent(clickEvent)
})
input.dispatchEvent(clickEvent)
}, "redispatch during post-click handling")
async_test(function(t) {
var input = document.createElement("input")
input.type = "checkbox"
dump.appendChild(input)
var child = input.appendChild(document.createElement("input"))
child.type = "checkbox"
child.disabled = true
child.click()
assert_false(input.checked)
assert_false(child.checked)
t.done()
}, "disabled checkbox still has activation behavior")
async_test(function(t) {
var state = "start"
var form = document.createElement("form")
form.onsubmit = t.step_func(() => {
if(state == "start" || state == "checkbox") {
state = "failure"
} else if(state == "form") {
state = "done"
}
return false
})
dump.appendChild(form)
var button = form.appendChild(document.createElement("button"))
button.type = "submit"
var checkbox = button.appendChild(document.createElement("input"))
checkbox.type = "checkbox"
checkbox.onclick = t.step_func(() => {
if(state == "start") {
assert_unreached()
} else if(state == "checkbox") {
assert_true(checkbox.checked)
}
})
checkbox.disabled = true
checkbox.click()
assert_equals(state, "start")
state = "checkbox"
checkbox.disabled = false
checkbox.click()
assert_equals(state, "checkbox")
state = "form"
button.click()
assert_equals(state, "done")
t.done()
}, "disabled checkbox still has activation behavior, part 2")
async_test(function(t) {
var state = "start"
var form = document.createElement("form")
form.onsubmit = t.step_func(() => {
if(state == "start" || state == "radio") {
state = "failure"
} else if(state == "form") {
state = "done"
}
return false
})
dump.appendChild(form)
var button = form.appendChild(document.createElement("button"))
button.type = "submit"
var radio = button.appendChild(document.createElement("input"))
radio.type = "radio"
radio.onclick = t.step_func(() => {
if(state == "start") {
assert_unreached()
} else if(state == "radio") {
assert_true(radio.checked)
}
})
radio.disabled = true
radio.click()
assert_equals(state, "start")
state = "radio"
radio.disabled = false
radio.click()
assert_equals(state, "radio")
state = "form"
button.click()
assert_equals(state, "done")
t.done()
}, "disabled radio still has activation behavior")
async_test(function(t) {
var input = document.createElement("input")
input.type = "checkbox"
input.onclick = t.step_func_done(function() {
assert_true(input.checked)
})
input.click()
}, "disconnected checkbox should be checked")
async_test(function(t) {
var input = document.createElement("input")
input.type = "radio"
input.onclick = t.step_func_done(function() {
assert_true(input.checked)
})
input.click()
}, "disconnected radio should be checked")
async_test(t => {
const input = document.createElement('input');
input.type = 'checkbox';
input.onclick = t.step_func_done(() => {
assert_true(input.checked);
});
input.dispatchEvent(new MouseEvent('click'));
}, `disconnected checkbox should be checked from dispatchEvent(new MouseEvent('click'))`);
async_test(t => {
const input = document.createElement('input');
input.type = 'radio';
input.onclick = t.step_func_done(() => {
assert_true(input.checked);
});
input.dispatchEvent(new MouseEvent('click'));
}, `disconnected radio should be checked from dispatchEvent(new MouseEvent('click'))`);
test(() => {
const input = document.createElement("input");
input.type = "checkbox";
input.disabled = true;
input.dispatchEvent(new MouseEvent("click"));
assert_true(input.checked);
}, `disabled checkbox should be checked from dispatchEvent(new MouseEvent("click"))`);
test(() => {
const input = document.createElement("input");
input.type = "radio";
input.disabled = true;
input.dispatchEvent(new MouseEvent("click"));
assert_true(input.checked);
}, `disabled radio should be checked from dispatchEvent(new MouseEvent("click"))`);
async_test(t => {
const input = document.createElement("input");
input.type = "checkbox";
input.disabled = true;
input.onclick = t.step_func_done();
input.dispatchEvent(new MouseEvent("click"));
}, `disabled checkbox should fire onclick`);
async_test(t => {
const input = document.createElement("input");
input.type = "radio";
input.disabled = true;
input.onclick = t.step_func_done();
input.dispatchEvent(new MouseEvent("click"));
}, `disabled radio should fire onclick`);
async_test(t => {
const input = document.createElement("input");
input.type = "checkbox";
input.disabled = true;
input.onclick = t.step_func(ev => {
assert_true(input.checked);
ev.preventDefault();
queueMicrotask(t.step_func_done(() => {
assert_false(input.checked);
}));
});
input.dispatchEvent(new MouseEvent("click", { cancelable: true }));
}, `disabled checkbox should get legacy-canceled-activation behavior`);
async_test(t => {
const input = document.createElement("input");
input.type = "radio";
input.disabled = true;
input.onclick = t.step_func(ev => {
assert_true(input.checked);
ev.preventDefault();
queueMicrotask(t.step_func_done(() => {
assert_false(input.checked);
}));
});
input.dispatchEvent(new MouseEvent("click", { cancelable: true }));
}, `disabled radio should get legacy-canceled-activation behavior`);
test(t => {
const input = document.createElement("input");
input.type = "checkbox";
input.disabled = true;
const ev = new MouseEvent("click", { cancelable: true });
ev.preventDefault();
input.dispatchEvent(ev);
assert_false(input.checked);
}, `disabled checkbox should get legacy-canceled-activation behavior 2`);
test(t => {
const input = document.createElement("input");
input.type = "radio";
input.disabled = true;
const ev = new MouseEvent("click", { cancelable: true });
ev.preventDefault();
input.dispatchEvent(ev);
assert_false(input.checked);
}, `disabled radio should get legacy-canceled-activation behavior 2`);
for (const type of ["checkbox", "radio"]) {
for (const handler of ["oninput", "onchange"]) {
async_test(t => {
const input = document.createElement("input");
input.type = type;
input.onclick = t.step_func(ev => {
input.disabled = true;
});
input[handler] = t.step_func(ev => {
assert_equals(input.checked, true);
t.done();
});
dump.append(input);
input.click();
}, `disabling ${type} in onclick listener shouldn't suppress ${handler}`);
}
}
async_test(function(t) {
var form = document.createElement("form")
var didSubmit = false
form.onsubmit = t.step_func(() => {
didSubmit = true
return false
})
var input = form.appendChild(document.createElement("input"))
input.type = "submit"
input.click()
assert_false(didSubmit)
t.done()
}, "disconnected form should not submit")
async_test(t => {
const form = document.createElement("form");
form.onsubmit = t.step_func(ev => {
ev.preventDefault();
assert_unreached("The form is unexpectedly submitted.");
});
dump.append(form);
const input = form.appendChild(document.createElement("input"));
input.type = "submit"
input.disabled = true;
input.dispatchEvent(new MouseEvent("click", { cancelable: true }));
t.done();
}, "disabled submit button should not activate");
async_test(t => {
const form = document.createElement("form");
form.onsubmit = t.step_func(ev => {
ev.preventDefault();
assert_unreached("The form is unexpectedly submitted.");
});
dump.append(form);
const input = form.appendChild(document.createElement("input"));
input.onclick = t.step_func(() => {
input.disabled = true;
});
input.type = "submit"
input.dispatchEvent(new MouseEvent("click", { cancelable: true }));
t.done();
}, "submit button should not activate if the event listener disables it");
async_test(t => {
const form = document.createElement("form");
form.onsubmit = t.step_func(ev => {
ev.preventDefault();
assert_unreached("The form is unexpectedly submitted.");
});
dump.append(form);
const input = form.appendChild(document.createElement("input"));
input.onclick = t.step_func(() => {
input.type = "submit"
input.disabled = true;
});
input.click();
t.done();
}, "submit button that morphed from checkbox should not activate");
</script>

View File

@ -0,0 +1,78 @@
<!doctype html>
<title>Clicks on input element</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<div id=dump style=display:none></div>
<script>
var dump = document.getElementById("dump")
test(t => {
const input = document.createElement("input");
input.type = "checkbox";
input.disabled = true;
const label = document.createElement("label");
label.append(input);
dump.append(label);
label.click();
assert_false(input.checked);
}, "disabled checkbox should not be checked from label click");
test(t => {
const input = document.createElement("input");
input.type = "radio";
input.disabled = true;
const label = document.createElement("label");
label.append(input);
dump.append(label);
label.click();
assert_false(input.checked);
}, "disabled radio should not be checked from label click");
test(t => {
const input = document.createElement("input");
input.type = "checkbox";
input.disabled = true;
const label = document.createElement("label");
label.append(input);
dump.append(label);
label.dispatchEvent(new MouseEvent("click"));
assert_false(input.checked);
}, "disabled checkbox should not be checked from label click by dispatchEvent");
test(t => {
const input = document.createElement("input");
input.type = "radio";
input.disabled = true;
const label = document.createElement("label");
label.append(input);
dump.append(label);
label.dispatchEvent(new MouseEvent("click"));
assert_false(input.checked);
}, "disabled radio should not be checked from label click by dispatchEvent");
test(t => {
const checkbox = dump.appendChild(document.createElement("input"));
checkbox.type = "checkbox";
checkbox.onclick = ev => {
checkbox.type = "date";
ev.preventDefault();
};
checkbox.dispatchEvent(new MouseEvent("click", { cancelable: true }));
assert_false(checkbox.checked);
}, "checkbox morphed into another type should not mutate checked state");
test(t => {
const radio1 = dump.appendChild(document.createElement("input"));
const radio2 = dump.appendChild(radio1.cloneNode());
radio1.type = radio2.type = "radio";
radio1.name = radio2.name = "foo";
radio2.checked = true;
radio1.onclick = ev => {
radio1.type = "date";
ev.preventDefault();
};
radio1.dispatchEvent(new MouseEvent("click", { cancelable: true }));
assert_false(radio1.checked);
assert_true(radio2.checked);
}, "radio morphed into another type should not steal the existing checked state");
</script>

View File

@ -0,0 +1,20 @@
<!DOCTYPE html>
<title>Click event on an element not in the document</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<div id=log></div>
<script>
test(function() {
var EVENT = "click";
var TARGET = document.createElement("somerandomelement");
var t = async_test("Click event can be dispatched to an element that is not in the document.")
TARGET.addEventListener(EVENT, t.step_func(function(evt) {
assert_equals(evt.target, TARGET);
assert_equals(evt.srcElement, TARGET);
t.done();
}), true);
var e = document.createEvent("Event");
e.initEvent(EVENT, true, true);
TARGET.dispatchEvent(e);
});
</script>

View File

@ -0,0 +1,190 @@
<!DOCTYPE html>
<meta charset="utf-8">
<link rel="author" title="Joey Arhar" href="mailto:jarhar@chromium.org">
<title>input and change events for detached checkbox and radio elements</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<body>
<script>
test(() => {
const input = document.createElement('input');
input.type = 'checkbox';
let inputEventFired = false;
input.addEventListener('input', () => inputEventFired = true);
let changeEventFired = false;
input.addEventListener('change', () => changeEventFired = true);
input.click();
assert_false(inputEventFired);
assert_false(changeEventFired);
}, 'detached checkbox should not emit input or change events on click().');
test(() => {
const input = document.createElement('input');
input.type = 'radio';
let inputEventFired = false;
input.addEventListener('input', () => inputEventFired = true);
let changeEventFired = false;
input.addEventListener('change', () => changeEventFired = true);
input.click();
assert_false(inputEventFired);
assert_false(changeEventFired);
}, 'detached radio should not emit input or change events on click().');
test(() => {
const input = document.createElement('input');
input.type = 'checkbox';
let inputEventFired = false;
input.addEventListener('input', () => inputEventFired = true);
let changeEventFired = false;
input.addEventListener('change', () => changeEventFired = true);
input.dispatchEvent(new MouseEvent('click'));
assert_false(inputEventFired);
assert_false(changeEventFired);
}, `detached checkbox should not emit input or change events on dispatchEvent(new MouseEvent('click')).`);
test(() => {
const input = document.createElement('input');
input.type = 'radio';
let inputEventFired = false;
input.addEventListener('input', () => inputEventFired = true);
let changeEventFired = false;
input.addEventListener('change', () => changeEventFired = true);
input.dispatchEvent(new MouseEvent('click'));
assert_false(inputEventFired);
assert_false(changeEventFired);
}, `detached radio should not emit input or change events on dispatchEvent(new MouseEvent('click')).`);
test(() => {
const input = document.createElement('input');
input.type = 'checkbox';
document.body.appendChild(input);
let inputEventFired = false;
input.addEventListener('input', () => inputEventFired = true);
let changeEventFired = false;
input.addEventListener('change', () => changeEventFired = true);
input.click();
assert_true(inputEventFired);
assert_true(changeEventFired);
}, 'attached checkbox should emit input and change events on click().');
test(() => {
const input = document.createElement('input');
input.type = 'radio';
document.body.appendChild(input);
let inputEventFired = false;
input.addEventListener('input', () => inputEventFired = true);
let changeEventFired = false;
input.addEventListener('change', () => changeEventFired = true);
input.click();
assert_true(inputEventFired);
assert_true(changeEventFired);
}, 'attached radio should emit input and change events on click().');
test(() => {
const input = document.createElement('input');
input.type = 'checkbox';
document.body.appendChild(input);
let inputEventFired = false;
input.addEventListener('input', () => inputEventFired = true);
let changeEventFired = false;
input.addEventListener('change', () => changeEventFired = true);
input.dispatchEvent(new MouseEvent('click'));
assert_true(inputEventFired);
assert_true(changeEventFired);
}, `attached checkbox should emit input and change events on dispatchEvent(new MouseEvent('click')).`);
test(() => {
const input = document.createElement('input');
input.type = 'radio';
document.body.appendChild(input);
let inputEventFired = false;
input.addEventListener('input', () => inputEventFired = true);
let changeEventFired = false;
input.addEventListener('change', () => changeEventFired = true);
input.dispatchEvent(new MouseEvent('click'));
assert_true(inputEventFired);
assert_true(changeEventFired);
}, `attached radio should emit input and change events on dispatchEvent(new MouseEvent('click')).`);
test(() => {
const input = document.createElement('input');
input.type = 'checkbox';
const shadowHost = document.createElement('div');
document.body.appendChild(shadowHost);
const shadowRoot = shadowHost.attachShadow({mode: 'open'});
shadowRoot.appendChild(input);
let inputEventFired = false;
input.addEventListener('input', () => inputEventFired = true);
let changeEventFired = false;
input.addEventListener('change', () => changeEventFired = true);
input.click();
assert_true(inputEventFired);
assert_true(changeEventFired);
}, 'attached to shadow dom checkbox should emit input and change events on click().');
test(() => {
const input = document.createElement('input');
input.type = 'radio';
const shadowHost = document.createElement('div');
document.body.appendChild(shadowHost);
const shadowRoot = shadowHost.attachShadow({mode: 'open'});
shadowRoot.appendChild(input);
let inputEventFired = false;
input.addEventListener('input', () => inputEventFired = true);
let changeEventFired = false;
input.addEventListener('change', () => changeEventFired = true);
input.click();
assert_true(inputEventFired);
assert_true(changeEventFired);
}, 'attached to shadow dom radio should emit input and change events on click().');
test(() => {
const input = document.createElement('input');
input.type = 'checkbox';
const shadowHost = document.createElement('div');
document.body.appendChild(shadowHost);
const shadowRoot = shadowHost.attachShadow({mode: 'open'});
shadowRoot.appendChild(input);
let inputEventFired = false;
input.addEventListener('input', () => inputEventFired = true);
let changeEventFired = false;
input.addEventListener('change', () => changeEventFired = true);
input.dispatchEvent(new MouseEvent('click'));
assert_true(inputEventFired);
assert_true(changeEventFired);
}, `attached to shadow dom checkbox should emit input and change events on dispatchEvent(new MouseEvent('click')).`);
test(() => {
const input = document.createElement('input');
input.type = 'radio';
const shadowHost = document.createElement('div');
document.body.appendChild(shadowHost);
const shadowRoot = shadowHost.attachShadow({mode: 'open'});
shadowRoot.appendChild(input);
let inputEventFired = false;
input.addEventListener('input', () => inputEventFired = true);
let changeEventFired = false;
input.addEventListener('change', () => changeEventFired = true);
input.dispatchEvent(new MouseEvent('click'));
assert_true(inputEventFired);
assert_true(changeEventFired);
}, `attached to shadow dom radio should emit input and change events on dispatchEvent(new MouseEvent('click')).`);
</script>
</body>

View File

@ -0,0 +1,91 @@
<!DOCTYPE html>
<meta charset=utf-8>
<title> Dispatch additional events inside an event listener </title>
<link rel="help" href="https://dom.spec.whatwg.org/#concept-event-dispatch">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<div id=log></div>
<table id="table" border="1" style="display: none">
<tbody id="table-body">
<tr id="table-row">
<td id="table-cell">Shady Grove</td>
<td>Aeolian</td>
</tr>
<tr id="parent">
<td id="target">Over the river, Charlie</td>
<td>Dorian</td>
</tr>
</tbody>
</table>
<script>
test(function() {
var event_type = "bar";
var target = document.getElementById("target");
var parent = document.getElementById("parent");
var tbody = document.getElementById("table-body");
var table = document.getElementById("table");
var body = document.body;
var html = document.documentElement;
var targets = [window, document, html, body, table, tbody, parent, target];
var expected_targets = [
window,
document,
html,
body,
table,
tbody,
parent,
target,
target,
target, // The additional listener for target runs as we copy its listeners twice
parent,
tbody,
table,
body,
html,
document,
window
];
var expected_listeners = [0,0,0,0,0,0,0,0,1,3,1,1,1,1,1,1,1];
var actual_targets = [], actual_listeners = [];
var test_event_function = function(i) {
return this.step_func(function(evt) {
actual_targets.push(evt.currentTarget);
actual_listeners.push(i);
if (evt.eventPhase != evt.BUBBLING_PHASE && evt.currentTarget.foo != 1) {
evt.currentTarget.removeEventListener(event_type, event_handlers[0], true);
evt.currentTarget.addEventListener(event_type, event_handlers[2], true);
evt.currentTarget.foo = 1;
}
if (evt.eventPhase != evt.CAPTURING_PHASE && evt.currentTarget.foo != 3) {
evt.currentTarget.removeEventListener(event_type, event_handlers[0], false);
evt.currentTarget.addEventListener(event_type, event_handlers[3], false);
evt.currentTarget.foo = 3;
}
});
}.bind(this);
var event_handlers = [
test_event_function(0),
test_event_function(1),
test_event_function(2),
test_event_function(3),
];
for (var i = 0; i < targets.length; ++i) {
targets[i].addEventListener(event_type, event_handlers[0], true);
targets[i].addEventListener(event_type, event_handlers[1], false);
}
var evt = document.createEvent("Event");
evt.initEvent(event_type, true, true);
target.dispatchEvent(evt);
assert_array_equals(actual_targets, expected_targets, "actual_targets");
assert_array_equals(actual_listeners, expected_listeners, "actual_listeners");
});
</script>

View File

@ -0,0 +1,20 @@
test(t => {
const hostParent = document.createElement("section"),
host = hostParent.appendChild(document.createElement("div")),
shadowRoot = host.attachShadow({ mode: "closed" }),
targetParent = shadowRoot.appendChild(document.createElement("p")),
target = targetParent.appendChild(document.createElement("span")),
path = [hostParent, host, shadowRoot, targetParent, target],
expected = [],
result = [];
path.forEach((node, index) => {
expected.splice(index, 0, "capturing " + node.nodeName);
expected.splice(index + 1, 0, "bubbling " + node.nodeName);
});
path.forEach(node => {
node.addEventListener("test", () => { result.push("bubbling " + node.nodeName) });
node.addEventListener("test", () => { result.push("capturing " + node.nodeName) }, true);
});
target.dispatchEvent(new CustomEvent('test', { detail: {}, bubbles: true, composed: true }));
assert_array_equals(result, expected);
});

View File

@ -0,0 +1,51 @@
<!DOCTYPE html>
<html>
<head>
<title>Multiple dispatchEvent() and cancelBubble</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
</head>
<body>
<div id=log></div>
<div id="parent" style="display: none">
<input id="target" type="hidden" value=""/>
</div>
<script>
test(function() {
var event_type = "foo";
var target = document.getElementById("target");
var parent = document.getElementById("parent");
var actual_result;
var test_event = function(evt) {
actual_result.push(evt.currentTarget);
if (parent == evt.currentTarget) {
evt.cancelBubble = true;
}
};
var evt = document.createEvent("Event");
evt.initEvent(event_type, true, true);
target.addEventListener(event_type, test_event, false);
parent.addEventListener(event_type, test_event, false);
document.addEventListener(event_type, test_event, false);
window.addEventListener(event_type, test_event, false);
actual_result = [];
target.dispatchEvent(evt);
assert_array_equals(actual_result, [target, parent]);
actual_result = [];
parent.dispatchEvent(evt);
assert_array_equals(actual_result, [parent]);
actual_result = [];
document.dispatchEvent(evt);
assert_array_equals(actual_result, [document, window]);
});
</script>
</body>
</html>

View File

@ -0,0 +1,51 @@
<!DOCTYPE html>
<html>
<head>
<title> Multiple dispatchEvent() and stopPropagation() </title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
</head>
<body>
<div id=log></div>
<div id="parent" style="display: none">
<input id="target" type="hidden" value=""/>
</div>
<script>
test(function() {
var event_type = "foo";
var target = document.getElementById("target");
var parent = document.getElementById("parent");
var actual_result;
var test_event = function(evt) {
actual_result.push(evt.currentTarget);
if (parent == evt.currentTarget) {
evt.stopPropagation();
}
};
var evt = document.createEvent("Event");
evt.initEvent(event_type, true, true);
target.addEventListener(event_type, test_event, false);
parent.addEventListener(event_type, test_event, false);
document.addEventListener(event_type, test_event, false);
window.addEventListener(event_type, test_event, false);
actual_result = [];
target.dispatchEvent(evt);
assert_array_equals(actual_result, [target, parent]);
actual_result = [];
parent.dispatchEvent(evt);
assert_array_equals(actual_result, [parent]);
actual_result = [];
document.dispatchEvent(evt);
assert_array_equals(actual_result, [document, window]);
});
</script>
</body>
</html>

View File

@ -0,0 +1,70 @@
<!DOCTYPE html>
<meta charset=utf-8>
<title>EventTarget.addEventListener: capture argument omitted</title>
<link rel="help" href="https://dom.spec.whatwg.org/#dom-eventtarget-addeventlistener">
<link rel="help" href="https://dom.spec.whatwg.org/#concept-event-dispatch">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<div id=log></div>
<table id="table" border="1" style="display: none">
<tbody id="table-body">
<tr id="table-row">
<td id="table-cell">Shady Grove</td>
<td>Aeolian</td>
</tr>
<tr id="parent">
<td id="target">Over the river, Charlie</td>
<td>Dorian</td>
</tr>
</tbody>
</table>
<script>
test(function() {
var event_type = "foo";
var target = document.getElementById("target");
var targets = [
target,
document.getElementById("parent"),
document.getElementById("table-body"),
document.getElementById("table"),
document.body,
document.documentElement,
document,
window
];
var phases = [
Event.AT_TARGET,
Event.BUBBLING_PHASE,
Event.BUBBLING_PHASE,
Event.BUBBLING_PHASE,
Event.BUBBLING_PHASE,
Event.BUBBLING_PHASE,
Event.BUBBLING_PHASE,
Event.BUBBLING_PHASE
];
var actual_targets = [], actual_phases = [];
var test_event = function(evt) {
actual_targets.push(evt.currentTarget);
actual_phases.push(evt.eventPhase);
}
for (var i = 0; i < targets.length; i++) {
targets[i].addEventListener(event_type, test_event);
}
var evt = document.createEvent("Event");
evt.initEvent(event_type, true, true);
target.dispatchEvent(evt);
for (var i = 0; i < targets.length; i++) {
targets[i].removeEventListener(event_type, test_event);
}
target.dispatchEvent(evt);
assert_array_equals(actual_targets, targets, "targets");
assert_array_equals(actual_phases, phases, "phases");
}, "EventTarget.addEventListener with the capture argument omitted");
</script>

View File

@ -0,0 +1,251 @@
<!doctype html>
<meta charset="utf8">
<meta name="timeout" content="long">
<title>Events must dispatch on disabled elements</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
<style>
@keyframes fade {
0% {
opacity: 1;
}
100% {
opacity: 0;
}
}
</style>
<body>
<script>
// HTML elements that can be disabled
const formElements = ["button", "input", "select", "textarea"];
test(() => {
for (const localName of formElements) {
const elem = document.createElement(localName);
elem.disabled = true;
// pass becomes true if the event is called and it's the right type.
let pass = false;
const listener = ({ type }) => {
pass = type === "click";
};
elem.addEventListener("click", listener, { once: true });
elem.dispatchEvent(new Event("click"));
assert_true(
pass,
`Untrusted "click" Event didn't dispatch on ${elem.constructor.name}.`
);
}
}, "Can dispatch untrusted 'click' Events at disabled HTML elements.");
test(() => {
for (const localName of formElements) {
const elem = document.createElement(localName);
elem.disabled = true;
// pass becomes true if the event is called and it's the right type.
let pass = false;
const listener = ({ type }) => {
pass = type === "pass";
};
elem.addEventListener("pass", listener, { once: true });
elem.dispatchEvent(new Event("pass"));
assert_true(
pass,
`Untrusted "pass" Event didn't dispatch on ${elem.constructor.name}`
);
}
}, "Can dispatch untrusted Events at disabled HTML elements.");
test(() => {
for (const localName of formElements) {
const elem = document.createElement(localName);
elem.disabled = true;
// pass becomes true if the event is called and it's the right type.
let pass = false;
const listener = ({ type }) => {
pass = type === "custom-pass";
};
elem.addEventListener("custom-pass", listener, { once: true });
elem.dispatchEvent(new CustomEvent("custom-pass"));
assert_true(
pass,
`CustomEvent "custom-pass" didn't dispatch on ${elem.constructor.name}`
);
}
}, "Can dispatch CustomEvents at disabled HTML elements.");
test(() => {
for (const localName of formElements) {
const elem = document.createElement(localName);
// Element is disabled... so this click() MUST NOT fire an event.
elem.disabled = true;
let pass = true;
elem.onclick = e => {
pass = false;
};
elem.click();
assert_true(
pass,
`.click() must not dispatch "click" event on disabled ${
elem.constructor.name
}.`
);
// Element is (re)enabled... so this click() fires an event.
elem.disabled = false;
pass = false;
elem.onclick = e => {
pass = true;
};
elem.click();
assert_true(
pass,
`.click() must dispatch "click" event on enabled ${
elem.constructor.name
}.`
);
}
}, "Calling click() on disabled elements must not dispatch events.");
promise_test(async () => {
// For each form element type, set up transition event handlers.
for (const localName of formElements) {
const elem = document.createElement(localName);
elem.disabled = true;
document.body.appendChild(elem);
const eventPromises = [
"transitionrun",
"transitionstart",
"transitionend",
].map(eventType => {
return new Promise(r => {
elem.addEventListener(eventType, r);
});
});
// Flushing style triggers transition.
getComputedStyle(elem).opacity;
elem.style.transition = "opacity .1s";
elem.style.opacity = 0;
getComputedStyle(elem).opacity;
// All the events fire...
await Promise.all(eventPromises);
elem.remove();
}
}, "CSS Transitions transitionrun, transitionstart, transitionend events fire on disabled form elements");
promise_test(async () => {
// For each form element type, set up transition event handlers.
for (const localName of formElements) {
const elem = document.createElement(localName);
elem.disabled = true;
document.body.appendChild(elem);
getComputedStyle(elem).opacity;
elem.style.transition = "opacity 100s";
// We use ontransitionstart to cancel the event.
elem.ontransitionstart = () => {
elem.style.display = "none";
};
const promiseToCancel = new Promise(r => {
elem.ontransitioncancel = r;
});
// Flushing style triggers the transition.
elem.style.opacity = 0;
getComputedStyle(elem).opacity;
await promiseToCancel;
// And we are done with this element.
elem.remove();
}
}, "CSS Transitions transitioncancel event fires on disabled form elements");
promise_test(async () => {
// For each form element type, set up transition event handlers.
for (const localName of formElements) {
const elem = document.createElement(localName);
document.body.appendChild(elem);
elem.disabled = true;
const animationStartPromise = new Promise(r => {
elem.addEventListener("animationstart", () => {
// Seek to the second iteration to trigger the animationiteration event
elem.style.animationDelay = "-100s"
r();
});
});
const animationIterationPromise = new Promise(r => {
elem.addEventListener("animationiteration", ()=>{
elem.style.animationDelay = "-200s"
r();
});
});
const animationEndPromise = new Promise(r => {
elem.addEventListener("animationend", r);
});
elem.style.animation = "fade 100s 2";
elem.classList.add("animate");
// All the events fire...
await Promise.all([
animationStartPromise,
animationIterationPromise,
animationEndPromise,
]);
elem.remove();
}
}, "CSS Animation animationstart, animationiteration, animationend fire on disabled form elements");
promise_test(async () => {
// For each form element type, set up transition event handlers.
for (const localName of formElements) {
const elem = document.createElement(localName);
document.body.appendChild(elem);
elem.disabled = true;
const promiseToCancel = new Promise(r => {
elem.addEventListener("animationcancel", r);
});
elem.addEventListener("animationstart", () => {
// Cancel the animation by hiding it.
elem.style.display = "none";
});
// Trigger the animation
elem.style.animation = "fade 100s";
elem.classList.add("animate");
await promiseToCancel;
// And we are done with this element.
elem.remove();
}
}, "CSS Animation's animationcancel event fires on disabled form elements");
promise_test(async () => {
for (const localName of formElements) {
const elem = document.createElement(localName);
elem.disabled = true;
document.body.appendChild(elem);
// Element is disabled, so clicking must not fire events
let pass = true;
elem.onclick = e => {
pass = false;
};
// Disabled elements are not clickable.
await test_driver.click(elem);
assert_true(
pass,
`${elem.constructor.name} is disabled, so onclick must not fire.`
);
// Element is (re)enabled... so this click() will fire an event.
pass = false;
elem.disabled = false;
elem.onclick = () => {
pass = true;
};
await test_driver.click(elem);
assert_true(
pass,
`${elem.constructor.name} is enabled, so onclick must fire.`
);
elem.remove();
}
}, "Real clicks on disabled elements must not dispatch events.");
</script>

View File

@ -0,0 +1,31 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>Listeners are invoked in correct order (AT_TARGET phase)</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<div id="log"></div>
<script>
"use strict";
test(() => {
const el = document.createElement("div");
const expectedOrder = ["capturing", "bubbling"];
let actualOrder = [];
el.addEventListener("click", evt => {
assert_equals(evt.eventPhase, Event.AT_TARGET);
actualOrder.push("bubbling");
}, false);
el.addEventListener("click", evt => {
assert_equals(evt.eventPhase, Event.AT_TARGET);
actualOrder.push("capturing");
}, true);
el.dispatchEvent(new Event("click", {bubbles: true}));
assert_array_equals(actualOrder, expectedOrder, "bubbles: true");
actualOrder = [];
el.dispatchEvent(new Event("click", {bubbles: false}));
assert_array_equals(actualOrder, expectedOrder, "bubbles: false");
}, "Listeners are invoked in correct order (AT_TARGET phase)");
</script>

View File

@ -0,0 +1,26 @@
<!DOCTYPE html>
<title>Event phases order</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<div id="log"></div>
<script>
async_test(function() {
document.addEventListener('DOMContentLoaded', this.step_func_done(function() {
var parent = document.getElementById('parent');
var child = document.getElementById('child');
var order = [];
parent.addEventListener('click', this.step_func(function(){ order.push(1) }), true);
child.addEventListener('click', this.step_func(function(){ order.push(2) }), false);
parent.addEventListener('click', this.step_func(function(){ order.push(3) }), false);
child.dispatchEvent(new Event('click', {bubbles: true}));
assert_array_equals(order, [1, 2, 3]);
}));
}, "Event phases order");
</script>
<div id="parent">
<div id="child"></div>
</div>

View File

@ -0,0 +1,23 @@
<!doctype html>
<title>Custom event on an element in another document</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<div id=log></div>
<script>
test(function() {
var doc = document.implementation.createHTMLDocument("Demo");
var element = doc.createElement("div");
var called = false;
element.addEventListener("foo", this.step_func(function(ev) {
assert_false(called);
called = true;
assert_equals(ev.target, element);
assert_equals(ev.srcElement, element);
}));
doc.body.appendChild(element);
var event = new Event("foo");
element.dispatchEvent(event);
assert_true(called);
});
</script>

View File

@ -0,0 +1,59 @@
<!DOCTYPE html>
<html>
<head>
<title> Calling stopPropagation() prior to dispatchEvent() </title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
</head>
<body>
<div id=log></div>
<table id="table" border="1" style="display: none">
<tbody id="table-body">
<tr id="table-row">
<td id="table-cell">Shady Grove</td>
<td>Aeolian</td>
</tr>
<tr id="parent">
<td id="target">Over the river, Charlie</td>
<td>Dorian</td>
</tr>
</tbody>
</table>
<script>
test(function() {
var event = "foo";
var target = document.getElementById("target");
var parent = document.getElementById("parent");
var tbody = document.getElementById("table-body");
var table = document.getElementById("table");
var body = document.body;
var html = document.documentElement;
var current_targets = [window, document, html, body, table, tbody, parent, target];
var expected_targets = [];
var actual_targets = [];
var expected_phases = [];
var actual_phases = [];
var test_event = function(evt) {
actual_targets.push(evt.currentTarget);
actual_phases.push(evt.eventPhase);
};
for (var i = 0; i < current_targets.length; ++i) {
current_targets[i].addEventListener(event, test_event, true);
current_targets[i].addEventListener(event, test_event, false);
}
var evt = document.createEvent("Event");
evt.initEvent(event, true, true);
evt.stopPropagation();
target.dispatchEvent(evt);
assert_array_equals(actual_targets, expected_targets, "actual_targets");
assert_array_equals(actual_phases, expected_phases, "actual_phases");
});
</script>
</body>
</html>

View File

@ -0,0 +1,124 @@
<!DOCTYPE html>
<meta charset=urf-8>
<title>EventTarget#dispatchEvent(): redispatching a native event</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-actions.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
<button>click me!</button>
<div id=log></div>
<script>
var test_contentLoaded_redispatching = async_test("Redispatching DOMContentLoaded event after being dispatched");
var test_mouseup_redispatching = async_test("Redispatching mouseup event whose default action dispatches a click event");
var test_redispatching_of_dispatching_event = async_test("Redispatching event which is being dispatched");
var buttonElement = document.querySelector("button");
var contentLoadedEvent;
var waitForLoad = new Promise(resolve => {
window.addEventListener("load", () => { requestAnimationFrame(resolve); }, {capture: false, once: true});
});
document.addEventListener("DOMContentLoaded", event => {
contentLoadedEvent = event;
test_redispatching_of_dispatching_event.step(() => {
assert_throws_dom("InvalidStateError", () => {
document.dispatchEvent(contentLoadedEvent);
}, "Trusted DOMContentLoaded event");
});
}, {capture: true, once: true});
window.addEventListener("load", loadEvent => {
let untrustedContentLoadedEvent;
buttonElement.addEventListener("DOMContentLoaded", event => {
untrustedContentLoadedEvent = event;
test_contentLoaded_redispatching.step(() => {
assert_false(untrustedContentLoadedEvent.isTrusted, "Redispatched DOMContentLoaded event shouldn't be trusted");
});
test_redispatching_of_dispatching_event.step(() => {
assert_throws_dom("InvalidStateError", () => {
document.dispatchEvent(untrustedContentLoadedEvent);
}, "Untrusted DOMContentLoaded event");
});
});
test_contentLoaded_redispatching.step(() => {
assert_true(contentLoadedEvent.isTrusted, "Received DOMContentLoaded event should be trusted before redispatching");
buttonElement.dispatchEvent(contentLoadedEvent);
assert_false(contentLoadedEvent.isTrusted, "Received DOMContentLoaded event shouldn't be trusted after redispatching");
assert_not_equals(untrustedContentLoadedEvent, undefined, "Untrusted DOMContentLoaded event should've been fired");
test_contentLoaded_redispatching.done();
});
}, {capture: true, once: true});
async function testMouseUpAndClickEvent() {
let mouseupEvent;
buttonElement.addEventListener("mouseup", event => {
mouseupEvent = event;
test_mouseup_redispatching.step(() => {
assert_true(mouseupEvent.isTrusted, "First mouseup event should be trusted");
});
test_redispatching_of_dispatching_event.step(() => {
assert_throws_dom("InvalidStateError", () => {
buttonElement.dispatchEvent(mouseupEvent);
}, "Trusted mouseup event");
});
}, {once: true});
let clickEvent;
buttonElement.addEventListener("click", event => {
clickEvent = event;
test_mouseup_redispatching.step(() => {
assert_true(clickEvent.isTrusted, "First click event should be trusted");
});
test_redispatching_of_dispatching_event.step(() => {
assert_throws_dom("InvalidStateError", function() {
buttonElement.dispatchEvent(event);
}, "Trusted click event");
});
buttonElement.addEventListener("mouseup", event => {
test_mouseup_redispatching.step(() => {
assert_false(event.isTrusted, "Redispatched mouseup event shouldn't be trusted");
});
test_redispatching_of_dispatching_event.step(() => {
assert_throws_dom("InvalidStateError", function() {
buttonElement.dispatchEvent(event);
}, "Untrusted mouseup event");
});
}, {once: true});
function onClick() {
test_mouseup_redispatching.step(() => {
assert_true(false, "click event shouldn't be fired for dispatched mouseup event");
});
}
test_mouseup_redispatching.step(() => {
assert_true(mouseupEvent.isTrusted, "Received mouseup event should be trusted before redispatching from click event listener");
buttonElement.addEventListener("click", onClick);
buttonElement.dispatchEvent(mouseupEvent);
buttonElement.removeEventListener("click", onClick);
assert_false(mouseupEvent.isTrusted, "Received mouseup event shouldn't be trusted after redispatching");
assert_true(clickEvent.isTrusted, "First click event should still be trusted even after redispatching mouseup event");
});
}, {once: true});
await waitForLoad;
let bounds = buttonElement.getBoundingClientRect();
test(() => { assert_true(true); }, `Synthesizing click on button...`);
new test_driver.click(buttonElement)
.then(() => {
test_mouseup_redispatching.step(() => {
assert_not_equals(clickEvent, undefined, "mouseup and click events should've been fired");
});
test_mouseup_redispatching.done();
test_redispatching_of_dispatching_event.done();
}, (reason) => {
test_mouseup_redispatching.step(() => {
assert_true(false, `Failed to send mouse click due to ${reason}`);
});
test_mouseup_redispatching.done();
test_redispatching_of_dispatching_event.done();
});
}
testMouseUpAndClickEvent();
</script>

View File

@ -0,0 +1,66 @@
<!DOCTYPE html>
<meta charset=utf-8>
<title> Dispatch additional events inside an event listener </title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<div id=log></div>
<table id="table" border="1" style="display: none">
<tbody id="table-body">
<tr id="table-row">
<td id="table-cell">Shady Grove</td>
<td>Aeolian</td>
</tr>
<tr id="parent">
<td id="target">Over the river, Charlie</td>
<td>Dorian</td>
</tr>
</tbody>
</table>
<script>
test(function() {
var event_type = "foo";
var target = document.getElementById("target");
var parent = document.getElementById("parent");
var tbody = document.getElementById("table-body");
var table = document.getElementById("table");
var body = document.body;
var html = document.documentElement;
var targets = [window, document, html, body, table, tbody, parent, target];
var expected_targets = [
window, document, html, body, table,
target, parent, tbody,
table, body, html, document, window,
tbody, parent, target];
var actual_targets = [];
var expected_types = [
"foo", "foo", "foo", "foo", "foo",
"bar", "bar", "bar",
"bar", "bar", "bar", "bar", "bar",
"foo", "foo", "foo"
];
var actual_targets = [], actual_types = [];
var test_event = this.step_func(function(evt) {
actual_targets.push(evt.currentTarget);
actual_types.push(evt.type);
if (table == evt.currentTarget && event_type == evt.type) {
var e = document.createEvent("Event");
e.initEvent("bar", true, true);
target.dispatchEvent(e);
}
});
for (var i = 0; i < targets.length; ++i) {
targets[i].addEventListener(event_type, test_event, true);
targets[i].addEventListener("bar", test_event, false);
}
var evt = document.createEvent("Event");
evt.initEvent(event_type, false, true);
target.dispatchEvent(evt);
assert_array_equals(actual_targets, expected_targets, "actual_targets");
assert_array_equals(actual_types, expected_types, "actual_types");
});
</script>

View File

@ -0,0 +1,164 @@
<!DOCTYPE html>
<meta charset=utf-8>
<title> Only one activation behavior is executed during dispatch</title>
<link rel="author" title="Vincent Hilla" href="mailto:vhilla@mozilla.com">
<link rel="help" href="https://dom.spec.whatwg.org/#eventtarget-activation-behavior">
<link rel="help" href="https://dom.spec.whatwg.org/#concept-event-dispatch">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<div id=log></div>
<div id=test_container></div>
<!--
Three classes:
click
Element to be clicked to cause activation behavior
activates
Element that registers the activation behavior
container
Element in which other elements with activation behavior are placed.
We test that those won't be activated too.
-->
<template>
<!--input, change event bubble, so have to check if checked is true-->
<input class="click activates container" type="checkbox" oninput="this.checked ? activated(this) : null">
<input class="click activates container" type="radio" oninput="this.checked ? activated(this) : null">
<form onsubmit="activated(this); return false" class="activates">
<input class="click container" type="submit">
</form>
<form onsubmit="activated(this); return false" class="activates">
<input class="click container" type="image">
</form>
<form onreset="activated(this)" class="activates">
<input class="click container" type="reset">
</form>
<form onsubmit="activated(this); return false" class="activates">
<button class="click container" type="submit"></button>
</form>
<form onreset="activated(this)" class="activates">
<button class="click container" type="reset"></button>
</form>
<a href="#link" class="click container activates"></a>
<area href="#link" class="click container activates">
<details ontoggle="activated(this)" class="activates">
<summary class="click container"></summary>
</details>
<label>
<input type=checkbox onclick="this.checked ? activated(this) : null" class="activates">
<span class="click container">label</span>
</label>
<!--activation behavior of label for event targeted at interactive content descendant is to do nothing-->
<label class="container">
<button class="click" type="button"></button>
</label>
</template>
<script>
let activations = [];
function activated(e) {
activations.push(e);
}
function getActivations(testidx) {
return activations.filter(a =>
(a.endsWith && a.endsWith("test"+testidx+"_link"))
|| (a.classList && a.classList.contains("test"+testidx))
);
}
// for a and area elements
window.onhashchange = function(e) {
if (e.newURL.endsWith("link")) {
activated(e.newURL);
}
window.location.hash = "";
};
function getElementsByClassNameInclusive(e, clsname) {
let ls = Array.from(e.getElementsByClassName(clsname));
if (e.classList.contains(clsname)) ls.push(e);
return ls;
}
function getClickTarget(e) {
return getElementsByClassNameInclusive(e, "click")[0];
}
function getContainer(e) {
return getElementsByClassNameInclusive(e, "container")[0];
}
function getExpectedActivations(e) {
let ls = getElementsByClassNameInclusive(e, "activates");
// special case, for a and area the window registers the activation
// have to use string, as testrunner cannot stringify the window object
ls = ls.map(e => e.tagName === "A" || e.tagName === "AREA" ? e.href : e);
return ls;
}
function toString(e) {
const children = Array.from(e.children);
const childstr = (children.map(toString)).join("");
const tag = e.tagName;
const typestr = e.type ? " type="+e.type : "";
return `<${tag}${typestr}>${childstr}</${tag}>`;
}
// generate O(n^2) test combinations
const template = document.querySelector("template");
const elements = Array.from(template.content.children);
const tests = []
for (const target of elements) {
for (const parent of elements) {
if (target === parent) continue;
tests.push([target.cloneNode(true), parent.cloneNode(true)])
}
}
const test_container = document.getElementById("test_container");
/**
* Test that if two elements in an event target chain have activation behavior,
* only one of them will be activated.
*
* Each child of <template> represents one case of activation behavior.
* The behavior should be triggered by clicking the element of class click
* and will manifest as a call to activated().
*
* For each [target, parent] in tests, we make target a descendant of parent
* and test that only target gets activated when dispatching a click.
*/
for (let i = 0; i < tests.length; i++) {
let [target, parent] = tests[i];
async_test(function(t) {
let test = document.createElement("div");
test_container.appendChild(test);
test.appendChild(parent);
getContainer(parent).appendChild(target);
// for later filtering out the activations belonging to this test
for (let e of test.getElementsByClassName("activates")) {
e.classList.add("test"+i);
}
for (let e of test.querySelectorAll("a, area")) {
e.href = "#test"+i+"_link";
}
getClickTarget(target).click();
// Need to spin event loop twice, as some clicks might dispatch another task
t.step_timeout(() => {
t.step_timeout(t.step_func_done(() => {
assert_array_equals(getActivations(i), getExpectedActivations(target));
}), 0);
}, 0);
t.add_cleanup(function() {
test_container.removeChild(test);
});
}, `When clicking child ${toString(target)} of parent ${toString(parent)}, only child should be activated.`);
}
</script>

View File

@ -0,0 +1,73 @@
<!DOCTYPE html>
<meta charset=utf-8>
<title> Determined event propagation path - target moved </title>
<link rel="help" href="https://dom.spec.whatwg.org/#concept-event-dispatch">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<div id=log></div>
<table id="table" border="1" style="display: none">
<tbody id="table-body">
<tr id="table-row">
<td id="table-cell">Shady Grove</td>
<td>Aeolian</td>
</tr>
<tr id="parent">
<td id="target">Over the river, Charlie</td>
<td>Dorian</td>
</tr>
</tbody>
</table>
<script>
test(function() {
var event_type = "foo";
var target = document.getElementById("target");
var parent = document.getElementById("parent");
var tbody = document.getElementById("table-body");
var table = document.getElementById("table");
var body = document.body;
var html = document.documentElement;
var targets = [window, document, html, body, table, tbody, parent, target];
var expected_targets = targets.concat([target, parent, tbody, table, body, html, document, window]);
var phases = [
Event.CAPTURING_PHASE,
Event.CAPTURING_PHASE,
Event.CAPTURING_PHASE,
Event.CAPTURING_PHASE,
Event.CAPTURING_PHASE,
Event.CAPTURING_PHASE,
Event.CAPTURING_PHASE,
Event.AT_TARGET,
Event.AT_TARGET,
Event.BUBBLING_PHASE,
Event.BUBBLING_PHASE,
Event.BUBBLING_PHASE,
Event.BUBBLING_PHASE,
Event.BUBBLING_PHASE,
Event.BUBBLING_PHASE,
Event.BUBBLING_PHASE,
];
var actual_targets = [], actual_phases = [];
var test_event = this.step_func(function(evt) {
if (parent === target.parentNode) {
var table_row = document.getElementById("table-row");
table_row.appendChild(parent.removeChild(target));
}
actual_targets.push(evt.currentTarget);
actual_phases.push(evt.eventPhase);
});
for (var i = 0; i < targets.length; i++) {
targets[i].addEventListener(event_type, test_event, true);
targets[i].addEventListener(event_type, test_event, false);
}
var evt = document.createEvent("Event");
evt.initEvent(event_type, true, true);
target.dispatchEvent(evt);
assert_array_equals(actual_targets, expected_targets, "targets");
assert_array_equals(actual_phases, phases, "phases");
}, "Event propagation path when an element in it is moved within the DOM");
</script>

View File

@ -0,0 +1,72 @@
<!DOCTYPE html>
<meta charset=utf-8>
<title>Determined event propagation path - target removed</title>
<link rel="help" href="https://dom.spec.whatwg.org/#concept-event-dispatch">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<div id=log></div>
<table id="table" border="1" style="display: none">
<tbody id="table-body">
<tr id="table-row">
<td id="table-cell">Shady Grove</td>
<td>Aeolian</td>
</tr>
<tr id="parent">
<td id="target">Over the river, Charlie</td>
<td>Dorian</td>
</tr>
</tbody>
</table>
<script>
test(function() {
var event_type = "foo";
var target = document.getElementById("target");
var parent = document.getElementById("parent");
var tbody = document.getElementById("table-body");
var table = document.getElementById("table");
var body = document.body;
var html = document.documentElement;
var targets = [window, document, html, body, table, tbody, parent, target];
var expected_targets = targets.concat([target, parent, tbody, table, body, html, document, window]);
var phases = [
Event.CAPTURING_PHASE,
Event.CAPTURING_PHASE,
Event.CAPTURING_PHASE,
Event.CAPTURING_PHASE,
Event.CAPTURING_PHASE,
Event.CAPTURING_PHASE,
Event.CAPTURING_PHASE,
Event.AT_TARGET,
Event.AT_TARGET,
Event.BUBBLING_PHASE,
Event.BUBBLING_PHASE,
Event.BUBBLING_PHASE,
Event.BUBBLING_PHASE,
Event.BUBBLING_PHASE,
Event.BUBBLING_PHASE,
Event.BUBBLING_PHASE,
];
var actual_targets = [], actual_phases = [];
var test_event = this.step_func(function(evt) {
if (parent === target.parentNode) {
parent.removeChild(target);
}
actual_targets.push(evt.currentTarget);
actual_phases.push(evt.eventPhase);
});
for (var i = 0; i < targets.length; i++) {
targets[i].addEventListener(event_type, test_event, true);
targets[i].addEventListener(event_type, test_event, false);
}
var evt = document.createEvent("Event");
evt.initEvent(event_type, true, true);
target.dispatchEvent(evt);
assert_array_equals(actual_targets, expected_targets, "targets");
assert_array_equals(actual_phases, phases, "phases");
}, "Event propagation path when an element in it is removed from the DOM");
</script>

View File

@ -0,0 +1,69 @@
<!DOCTYPE html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<body>
<script>
function createIframe(t, srcdoc = '') {
let iframe = document.createElement('iframe');
iframe.srcdoc = srcdoc;
t.add_cleanup(() => iframe.remove());
return new Promise((resolve, reject) => {
iframe.addEventListener('load', () => resolve(iframe.contentWindow));
document.body.appendChild(iframe);
});
}
// Returns a promise which will resolve with the next error event fired at any
// of `windows`, after the invocation of this function. Once one does, this
// function removes its listeners and produces that error event so that it can
// be examined (most notably for which global proxy it was targeted at).
async function nextErrorEvent(windows) {
let listener;
let p = new Promise((resolve, reject) => {
listener = (event) => { resolve(event); event.preventDefault(); };
});
for (let w of windows) {
w.addEventListener('error', listener);
}
try {
return await p;
} finally {
for (let w of windows) {
w.removeEventListener('error', listener);
}
}
}
promise_test(async t => {
let w = await createIframe(t, `<script>function listener() { throw new Error(); }<`+`/script>`);
let w2 = await createIframe(t);
let target = new w2.EventTarget();
target.addEventListener('party', w.listener);
let nextErrorPromise = nextErrorEvent([self, w, w2]);
target.dispatchEvent(new Event('party'));
let errorEvent = await nextErrorPromise;
if (errorEvent.error) {
assert_true(errorEvent.error instanceof w.Error, 'error should be an instance created inside the listener function');
}
assert_equals(errorEvent.target, w, `error event should target listener's global but instead targets ${event.currentTarget === w2 ? 'target\'s global' : 'test harness global'}`);
}, 'exception thrown in event listener function should result in error event on listener\'s global');
promise_test(async t => {
let w = await createIframe(t, `<script>listener = {};<`+`/script>`);
let w2 = await createIframe(t, `<script>handleEvent = () => { throw new Error; };<`+`/script>`);
let w3 = await createIframe(t);
w.listener.handleEvent = w2.handleEvent;
let target = new w3.EventTarget();
target.addEventListener('party', w.listener);
let nextErrorPromise = nextErrorEvent([self, w, w2, w3]);
target.dispatchEvent(new Event('party'));
let errorEvent = await nextErrorPromise;
if (errorEvent.error) {
assert_true(errorEvent.error instanceof w2.Error, 'error should be an instance created inside the listener function');
}
assert_equals(errorEvent.target, w, `error event should target listener's global but instead targets ${event.currentTarget === w2 ? 'target\'s global' : event.currentTarget === w3 ? 'function\'s global' : 'test harness global'}`);
}, 'exception thrown in event listener interface object should result in error event on listener\'s global');
</script>
</body>

View File

@ -0,0 +1,51 @@
<!DOCTYPE html>
<meta charset="UTF-8">
<title>Throwing in event listeners</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<div id="log"></div>
<script>
setup({allow_uncaught_exception:true})
test(function() {
var errorEvents = 0;
window.onerror = this.step_func(function(e) {
assert_equals(typeof e, 'string');
++errorEvents;
});
var element = document.createElement('div');
element.addEventListener('click', function() {
throw new Error('Error from only listener');
});
element.dispatchEvent(new Event('click'));
assert_equals(errorEvents, 1);
}, "Throwing in event listener with a single listeners");
test(function() {
var errorEvents = 0;
window.onerror = this.step_func(function(e) {
assert_equals(typeof e, 'string');
++errorEvents;
});
var element = document.createElement('div');
var secondCalled = false;
element.addEventListener('click', function() {
throw new Error('Error from first listener');
});
element.addEventListener('click', this.step_func(function() {
secondCalled = true;
}), false);
element.dispatchEvent(new Event('click'));
assert_equals(errorEvents, 1);
assert_true(secondCalled);
}, "Throwing in event listener with multiple listeners");
</script>

View File

@ -0,0 +1,83 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>Re-initializing events while dispatching them</title>
<link rel="author" title="Josh Matthews" href="mailto:josh@joshmatthews.net">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<div id="log"></div>
<script>
var events = {
'KeyboardEvent': {
'constructor': function() { return new KeyboardEvent("type", {key: "A"}); },
'init': function(ev) { ev.initKeyboardEvent("type2", true, true, null, "a", 1, "", true, "") },
'check': function(ev) {
assert_equals(ev.key, "A", "initKeyboardEvent key setter should short-circuit");
assert_false(ev.repeat, "initKeyboardEvent repeat setter should short-circuit");
assert_equals(ev.location, 0, "initKeyboardEvent location setter should short-circuit");
}
},
'MouseEvent': {
'constructor': function() { return new MouseEvent("type"); },
'init': function(ev) { ev.initMouseEvent("type2", true, true, null, 0, 1, 1, 1, 1, true, true, true, true, 1, null) },
'check': function(ev) {
assert_equals(ev.screenX, 0, "initMouseEvent screenX setter should short-circuit");
assert_equals(ev.screenY, 0, "initMouseEvent screenY setter should short-circuit");
assert_equals(ev.clientX, 0, "initMouseEvent clientX setter should short-circuit");
assert_equals(ev.clientY, 0, "initMouseEvent clientY setter should short-circuit");
assert_false(ev.ctrlKey, "initMouseEvent ctrlKey setter should short-circuit");
assert_false(ev.altKey, "initMouseEvent altKey setter should short-circuit");
assert_false(ev.shiftKey, "initMouseEvent shiftKey setter should short-circuit");
assert_false(ev.metaKey, "initMouseEvent metaKey setter should short-circuit");
assert_equals(ev.button, 0, "initMouseEvent button setter should short-circuit");
}
},
'CustomEvent': {
'constructor': function() { return new CustomEvent("type") },
'init': function(ev) { ev.initCustomEvent("type2", true, true, 1) },
'check': function(ev) {
assert_equals(ev.detail, null, "initCustomEvent detail setter should short-circuit");
}
},
'UIEvent': {
'constructor': function() { return new UIEvent("type") },
'init': function(ev) { ev.initUIEvent("type2", true, true, window, 1) },
'check': function(ev) {
assert_equals(ev.view, null, "initUIEvent view setter should short-circuit");
assert_equals(ev.detail, 0, "initUIEvent detail setter should short-circuit");
}
},
'Event': {
'constructor': function() { return new Event("type") },
'init': function(ev) { ev.initEvent("type2", true, true) },
'check': function(ev) {
assert_equals(ev.bubbles, false, "initEvent bubbles setter should short-circuit");
assert_equals(ev.cancelable, false, "initEvent cancelable setter should short-circuit");
assert_equals(ev.type, "type", "initEvent type setter should short-circuit");
}
}
};
var names = Object.keys(events);
for (var i = 0; i < names.length; i++) {
var t = async_test("Calling init" + names[i] + " while dispatching.");
t.step(function() {
var e = events[names[i]].constructor();
var target = document.createElement("div")
target.addEventListener("type", t.step_func(function() {
events[names[i]].init(e);
var o = e;
while ((o = Object.getPrototypeOf(o))) {
if (!(o.constructor.name in events)) {
break;
}
events[o.constructor.name].check(e);
}
}), false);
assert_equals(target.dispatchEvent(e), true, "dispatchEvent must return true")
});
t.done();
}
</script>

View File

@ -0,0 +1,136 @@
<!DOCTYPE html>
<title>Event.initEvent</title>
<link rel="author" title="Ms2ger" href="mailto:Ms2ger@gmail.com">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<div id="log"></div>
<script>
var booleans = [true, false];
booleans.forEach(function(bubbles) {
booleans.forEach(function(cancelable) {
test(function() {
var e = document.createEvent("Event")
e.initEvent("type", bubbles, cancelable)
// Step 2.
// Stop (immediate) propagation flag is tested later
assert_equals(e.defaultPrevented, false, "defaultPrevented")
assert_equals(e.returnValue, true, "returnValue")
// Step 3.
assert_equals(e.isTrusted, false, "isTrusted")
// Step 4.
assert_equals(e.target, null, "target")
assert_equals(e.srcElement, null, "srcElement")
// Step 5.
assert_equals(e.type, "type", "type")
// Step 6.
assert_equals(e.bubbles, bubbles, "bubbles")
// Step 7.
assert_equals(e.cancelable, cancelable, "cancelable")
}, "Properties of initEvent(type, " + bubbles + ", " + cancelable + ")")
})
})
test(function() {
var e = document.createEvent("Event")
e.initEvent("type 1", true, false)
assert_equals(e.type, "type 1", "type (first init)")
assert_equals(e.bubbles, true, "bubbles (first init)")
assert_equals(e.cancelable, false, "cancelable (first init)")
e.initEvent("type 2", false, true)
assert_equals(e.type, "type 2", "type (second init)")
assert_equals(e.bubbles, false, "bubbles (second init)")
assert_equals(e.cancelable, true, "cancelable (second init)")
}, "Calling initEvent multiple times (getting type).")
test(function() {
// https://bugzilla.mozilla.org/show_bug.cgi?id=998809
var e = document.createEvent("Event")
e.initEvent("type 1", true, false)
assert_equals(e.bubbles, true, "bubbles (first init)")
assert_equals(e.cancelable, false, "cancelable (first init)")
e.initEvent("type 2", false, true)
assert_equals(e.type, "type 2", "type (second init)")
assert_equals(e.bubbles, false, "bubbles (second init)")
assert_equals(e.cancelable, true, "cancelable (second init)")
}, "Calling initEvent multiple times (not getting type).")
// Step 2.
async_test(function() {
// https://www.w3.org/Bugs/Public/show_bug.cgi?id=17715
var e = document.createEvent("Event")
e.initEvent("type", false, false)
assert_equals(e.type, "type", "type (first init)")
assert_equals(e.bubbles, false, "bubbles (first init)")
assert_equals(e.cancelable, false, "cancelable (first init)")
var target = document.createElement("div")
target.addEventListener("type", this.step_func(function() {
e.initEvent("fail", true, true)
assert_equals(e.type, "type", "type (second init)")
assert_equals(e.bubbles, false, "bubbles (second init)")
assert_equals(e.cancelable, false, "cancelable (second init)")
}), false)
assert_equals(target.dispatchEvent(e), true, "dispatchEvent must return true")
this.done()
}, "Calling initEvent must not have an effect during dispatching.")
test(function() {
var e = document.createEvent("Event")
e.stopPropagation()
e.initEvent("type", false, false)
var target = document.createElement("div")
var called = false
target.addEventListener("type", function() { called = true }, false)
assert_false(e.cancelBubble, "cancelBubble must be false")
assert_true(target.dispatchEvent(e), "dispatchEvent must return true")
assert_true(called, "Listener must be called")
}, "Calling initEvent must unset the stop propagation flag.")
test(function() {
var e = document.createEvent("Event")
e.stopImmediatePropagation()
e.initEvent("type", false, false)
var target = document.createElement("div")
var called = false
target.addEventListener("type", function() { called = true }, false)
assert_true(target.dispatchEvent(e), "dispatchEvent must return true")
assert_true(called, "Listener must be called")
}, "Calling initEvent must unset the stop immediate propagation flag.")
async_test(function() {
var e = document.createEvent("Event")
e.initEvent("type", false, false)
var target = document.createElement("div")
target.addEventListener("type", this.step_func(function() {
e.initEvent("type2", true, true);
assert_equals(e.type, "type", "initEvent type setter should short-circuit");
assert_false(e.bubbles, "initEvent bubbles setter should short-circuit");
assert_false(e.cancelable, "initEvent cancelable setter should short-circuit");
}), false)
assert_equals(target.dispatchEvent(e), true, "dispatchEvent must return true")
this.done()
}, "Calling initEvent during propagation.")
test(function() {
var e = document.createEvent("Event")
assert_throws_js(TypeError, function() {
e.initEvent()
})
}, "First parameter to initEvent should be mandatory.")
test(function() {
var e = document.createEvent("Event")
e.initEvent("type")
assert_equals(e.type, "type", "type")
assert_false(e.bubbles, "bubbles")
assert_false(e.cancelable, "cancelable")
}, "Tests initEvent's default parameter values.")
</script>

View File

@ -0,0 +1,11 @@
test(function() {
var desc1 = Object.getOwnPropertyDescriptor(new Event("x"), "isTrusted");
assert_not_equals(desc1, undefined);
assert_equals(typeof desc1.get, "function");
var desc2 = Object.getOwnPropertyDescriptor(new Event("x"), "isTrusted");
assert_not_equals(desc2, undefined);
assert_equals(typeof desc2.get, "function");
assert_equals(desc1.get, desc2.get);
});

View File

@ -0,0 +1,48 @@
<!doctype html>
<title>Event propagation tests</title>
<link rel=author title="Aryeh Gregor" href=ayg@aryeh.name>
<div id=log></div>
<script src=/resources/testharness.js></script>
<script src=/resources/testharnessreport.js></script>
<script>
"use strict";
function testPropagationFlag(ev, expected, desc) {
test(function() {
var called = false;
var callback = function() { called = true };
this.add_cleanup(function() {
document.head.removeEventListener("foo", callback)
});
document.head.addEventListener("foo", callback);
document.head.dispatchEvent(ev);
assert_equals(called, expected, "Propagation flag");
// dispatchEvent resets the propagation flags so it will happily dispatch
// the event the second time around.
document.head.dispatchEvent(ev);
assert_equals(called, true, "Propagation flag after first dispatch");
}, desc);
}
var ev = document.createEvent("Event");
ev.initEvent("foo", true, false);
testPropagationFlag(ev, true, "Newly-created Event");
ev.stopPropagation();
testPropagationFlag(ev, false, "After stopPropagation()");
ev.initEvent("foo", true, false);
testPropagationFlag(ev, true, "Reinitialized after stopPropagation()");
var ev = document.createEvent("Event");
ev.initEvent("foo", true, false);
ev.stopImmediatePropagation();
testPropagationFlag(ev, false, "After stopImmediatePropagation()");
ev.initEvent("foo", true, false);
testPropagationFlag(ev, true, "Reinitialized after stopImmediatePropagation()");
var ev = document.createEvent("Event");
ev.initEvent("foo", true, false);
ev.cancelBubble = true;
testPropagationFlag(ev, false, "After cancelBubble=true");
ev.initEvent("foo", true, false);
testPropagationFlag(ev, true, "Reinitialized after cancelBubble=true");
</script>

View File

@ -0,0 +1,64 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Event.returnValue</title>
<link rel="author" title="Chris Rebert" href="http://chrisrebert.com">
<link rel="help" href="https://dom.spec.whatwg.org/#dom-event-returnvalue">
<meta name="flags" content="dom">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
</head>
<body>
<div id="log"></div>
<script>
test(function() {
var ev = new Event("foo");
assert_true(ev.returnValue, "returnValue");
}, "When an event is created, returnValue should be initialized to true.");
test(function() {
var ev = new Event("foo", {"cancelable": false});
assert_false(ev.cancelable, "cancelable (before)");
ev.preventDefault();
assert_false(ev.cancelable, "cancelable (after)");
assert_true(ev.returnValue, "returnValue");
}, "preventDefault() should not change returnValue if cancelable is false.");
test(function() {
var ev = new Event("foo", {"cancelable": false});
assert_false(ev.cancelable, "cancelable (before)");
ev.returnValue = false;
assert_false(ev.cancelable, "cancelable (after)");
assert_true(ev.returnValue, "returnValue");
}, "returnValue=false should have no effect if cancelable is false.");
test(function() {
var ev = new Event("foo", {"cancelable": true});
assert_true(ev.cancelable, "cancelable (before)");
ev.preventDefault();
assert_true(ev.cancelable, "cancelable (after)");
assert_false(ev.returnValue, "returnValue");
}, "preventDefault() should change returnValue if cancelable is true.");
test(function() {
var ev = new Event("foo", {"cancelable": true});
assert_true(ev.cancelable, "cancelable (before)");
ev.returnValue = false;
assert_true(ev.cancelable, "cancelable (after)");
assert_false(ev.returnValue, "returnValue");
}, "returnValue should change returnValue if cancelable is true.");
test(function() {
var ev = document.createEvent("Event");
ev.returnValue = false;
ev.initEvent("foo", true, true);
assert_true(ev.bubbles, "bubbles");
assert_true(ev.cancelable, "cancelable");
assert_true(ev.returnValue, "returnValue");
}, "initEvent should unset returnValue.");
test(function() {
var ev = new Event("foo", {"cancelable": true});
ev.preventDefault();
ev.returnValue = true;// no-op
assert_true(ev.defaultPrevented);
assert_false(ev.returnValue);
}, "returnValue=true should have no effect once the canceled flag was set.");
</script>
</body>
</html>

View File

@ -0,0 +1,34 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>Event's stopImmediatePropagation</title>
<link rel="help" href="https://dom.spec.whatwg.org/#dom-event-stopimmediatepropagation">
<link rel="author" href="mailto:d@domenic.me" title="Domenic Denicola">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<div id="target"></div>
<script>
"use strict";
setup({ single_test: true });
const target = document.querySelector("#target");
let timesCalled = 0;
target.addEventListener("test", e => {
++timesCalled;
e.stopImmediatePropagation();
assert_equals(e.cancelBubble, true, "The stop propagation flag must have been set");
});
target.addEventListener("test", () => {
++timesCalled;
});
const e = new Event("test");
target.dispatchEvent(e);
assert_equals(timesCalled, 1, "The second listener must not have been called");
done();
</script>

View File

@ -0,0 +1,20 @@
<!DOCTYPE html>
<meta charset="utf-8">
<link rel="author" title="Joey Arhar" href="mailto:jarhar@chromium.org">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<body>
<script>
test(t => {
const element = document.createElement('div');
element.addEventListener('click', () => {
event.stopPropagation();
}, { capture: true });
element.addEventListener('click',
t.unreached_func('stopPropagation in the capture handler should have canceled this bubble handler.'));
element.dispatchEvent(new MouseEvent('click', { bubbles: true, cancelable: true }));
});
</script>

View File

@ -0,0 +1,179 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>Event constructors</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<div id="log"></div>
<script>
function assert_props(iface, event, defaults) {
assert_true(event instanceof self[iface]);
expected[iface].properties.forEach(function(p) {
var property = p[0], value = p[defaults ? 1 : 2];
assert_true(property in event,
"Event " + format_value(event) + " should have a " +
property + " property");
assert_equals(event[property], value,
"The value of the " + property + " property should be " +
format_value(value));
});
if ("parent" in expected[iface]) {
assert_props(expected[iface].parent, event, defaults);
}
}
// Class declarations don't go on the global by default, so put it there ourselves:
self.SubclassedEvent = class SubclassedEvent extends Event {
constructor(name, props) {
super(name, props);
if (props && typeof(props) == "object" && "customProp" in props) {
this.customProp = props.customProp;
} else {
this.customProp = 5;
}
}
get fixedProp() {
return 17;
}
}
var EventModifierInit = [
["ctrlKey", false, true],
["shiftKey", false, true],
["altKey", false, true],
["metaKey", false, true],
];
var expected = {
"Event": {
"properties": [
["bubbles", false, true],
["cancelable", false, true],
["isTrusted", false, false],
],
},
"UIEvent": {
"parent": "Event",
"properties": [
["view", null, window],
["detail", 0, 7],
],
},
"FocusEvent": {
"parent": "UIEvent",
"properties": [
["relatedTarget", null, document],
],
},
"MouseEvent": {
"parent": "UIEvent",
"properties": EventModifierInit.concat([
["screenX", 0, 40],
["screenY", 0, 40],
["clientX", 0, 40],
["clientY", 0, 40],
["button", 0, 40],
["buttons", 0, 40],
["relatedTarget", null, document],
]),
},
"WheelEvent": {
"parent": "MouseEvent",
"properties": [
["deltaX", 0.0, 3.1],
["deltaY", 0.0, 3.1],
["deltaZ", 0.0, 3.1],
["deltaMode", 0, 40],
],
},
"KeyboardEvent": {
"parent": "UIEvent",
"properties": EventModifierInit.concat([
["key", "", "string"],
["code", "", "string"],
["location", 0, 7],
["repeat", false, true],
["isComposing", false, true],
["charCode", 0, 7],
["keyCode", 0, 7],
["which", 0, 7],
]),
},
"CompositionEvent": {
"parent": "UIEvent",
"properties": [
["data", "", "string"],
],
},
"SubclassedEvent": {
"parent": "Event",
"properties": [
["customProp", 5, 8],
["fixedProp", 17, 17],
],
},
};
Object.keys(expected).forEach(function(iface) {
test(function() {
var event = new self[iface]("type");
assert_props(iface, event, true);
}, iface + " constructor (no argument)");
test(function() {
var event = new self[iface]("type", undefined);
assert_props(iface, event, true);
}, iface + " constructor (undefined argument)");
test(function() {
var event = new self[iface]("type", null);
assert_props(iface, event, true);
}, iface + " constructor (null argument)");
test(function() {
var event = new self[iface]("type", {});
assert_props(iface, event, true);
}, iface + " constructor (empty argument)");
test(function() {
var dictionary = {};
expected[iface].properties.forEach(function(p) {
var property = p[0], value = p[1];
dictionary[property] = value;
});
var event = new self[iface]("type", dictionary);
assert_props(iface, event, true);
}, iface + " constructor (argument with default values)");
test(function() {
function fill_in(iface, dictionary) {
if ("parent" in expected[iface]) {
fill_in(expected[iface].parent, dictionary)
}
expected[iface].properties.forEach(function(p) {
var property = p[0], value = p[2];
dictionary[property] = value;
});
}
var dictionary = {};
fill_in(iface, dictionary);
var event = new self[iface]("type", dictionary);
assert_props(iface, event, false);
}, iface + " constructor (argument with non-default values)");
});
test(function () {
assert_throws_js(TypeError, function() {
new UIEvent("x", { view: 7 })
});
}, "UIEvent constructor (view argument with wrong type)")
</script>

View File

@ -0,0 +1,27 @@
<!doctype html>
<meta charset="utf-8">
<title>event.timeStamp is initialized using event's relevant global object</title>
<link rel="help" href="https://dom.spec.whatwg.org/#ref-for-dom-event-timestamp%E2%91%A1">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<body>
<script>
const t = async_test();
t.step_timeout(() => {
const iframeDelayed = document.createElement("iframe");
iframeDelayed.onload = t.step_func_done(() => {
// Use eval() to eliminate false-positive test result for WebKit builds before r280256,
// which invoked WebIDL accessors in context of lexical (caller) global object.
const timeStampExpected = iframeDelayed.contentWindow.eval(`new Event("foo").timeStamp`);
const eventDelayed = new iframeDelayed.contentWindow.Event("foo");
const {get} = Object.getOwnPropertyDescriptor(Event.prototype, "timeStamp");
assert_approx_equals(get.call(eventDelayed), timeStampExpected, 5, "via Object.getOwnPropertyDescriptor");
Object.setPrototypeOf(eventDelayed, Event.prototype);
assert_approx_equals(eventDelayed.timeStamp, timeStampExpected, 5, "via Object.setPrototypeOf");
});
document.body.append(iframeDelayed);
}, 1000);
</script>

View File

@ -0,0 +1,16 @@
<!DOCTYPE html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script type="text/javascript">
'use strict';
for (let eventType of ["MouseEvent", "KeyboardEvent", "WheelEvent", "FocusEvent"]) {
test(function() {
let before = performance.now();
let e = new window[eventType]('test');
let after = performance.now();
assert_greater_than_equal(e.timeStamp, before, "Event timestamp should be greater than performance.now() timestamp taken before its creation");
assert_less_than_equal(e.timeStamp, after, "Event timestamp should be less than performance.now() timestamp taken after its creation");
}, `Constructed ${eventType} timestamp should be high resolution and have the same time origin as performance.now()`);
}
</script>

View File

@ -0,0 +1,16 @@
<!DOCTYPE html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script type="text/javascript">
'use strict';
for (let eventType of ["GamepadEvent"]) {
test(function() {
let before = performance.now();
let e = new window[eventType]('test');
let after = performance.now();
assert_greater_than_equal(e.timeStamp, before, "Event timestamp should be greater than performance.now() timestamp taken before its creation");
assert_less_than_equal(e.timeStamp, after, "Event timestamp should be less than performance.now() timestamp taken after its creation");
}, `Constructed ${eventType} timestamp should be high resolution and have the same time origin as performance.now()`);
}
</script>

View File

@ -0,0 +1,49 @@
<!DOCTYPE html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script type="text/javascript">
'use strict';
// Computes greatest common divisor of a and b using Euclid's algorithm
function computeGCD(a, b) {
if (!Number.isInteger(a) || !Number.isInteger(b)) {
throw new Error('Parameters must be integer numbers');
}
var r;
while (b != 0) {
r = a % b;
a = b;
b = r;
}
return (a < 0) ? -a : a;
}
// Finds minimum resolution Δ given a set of samples which are known to be in the form of N*Δ.
// We use GCD of all samples as a simple estimator.
function estimateMinimumResolution(samples) {
var gcd;
for (const sample of samples) {
gcd = gcd ? computeGCD(gcd, sample) : sample;
}
return gcd;
}
test(function() {
const samples = [];
for (var i = 0; i < 1e3; i++) {
var deltaInMicroSeconds = 0;
const e1 = new MouseEvent('test1');
do {
const e2 = new MouseEvent('test2');
deltaInMicroSeconds = Math.round((e2.timeStamp - e1.timeStamp) * 1000);
} while (deltaInMicroSeconds == 0) // only collect non-zero samples
samples.push(deltaInMicroSeconds);
}
const minResolution = estimateMinimumResolution(samples);
assert_greater_than_equal(minResolution, 5);
}, 'Event timestamp should not have a resolution better than 5 microseconds');
</script>

View File

@ -0,0 +1,35 @@
<!DOCTYPE html>
<title>Event.type set to the empty string</title>
<link rel="author" title="Ms2ger" href="mailto:Ms2ger@gmail.com">
<link rel="help" href="https://dom.spec.whatwg.org/#dom-event-type">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<div id="log"></div>
<script>
function do_test(t, e) {
assert_equals(e.type, "", "type");
assert_equals(e.bubbles, false, "bubbles");
assert_equals(e.cancelable, false, "cancelable");
var target = document.createElement("div");
var handled = false;
target.addEventListener("", t.step_func(function(e) {
handled = true;
}));
assert_true(target.dispatchEvent(e));
assert_true(handled);
}
async_test(function() {
var e = document.createEvent("Event");
e.initEvent("", false, false);
do_test(this, e);
this.done();
}, "initEvent");
async_test(function() {
var e = new Event("");
do_test(this, e);
this.done();
}, "Constructor");
</script>

View File

@ -0,0 +1,22 @@
<!DOCTYPE html>
<title>Event.type</title>
<link rel="author" title="Ms2ger" href="mailto:Ms2ger@gmail.com">
<link rel="help" href="https://dom.spec.whatwg.org/#dom-event-type">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<div id="log"></div>
<script>
test(function() {
var e = document.createEvent("Event")
assert_equals(e.type, "");
}, "Event.type should initially be the empty string");
test(function() {
var e = document.createEvent("Event")
e.initEvent("foo", false, false)
assert_equals(e.type, "foo")
}, "Event.type should be initialized by initEvent");
test(function() {
var e = new Event("bar")
assert_equals(e.type, "bar")
}, "Event.type should be initialized by the constructor");
</script>

View File

@ -0,0 +1,9 @@
async_test(function(t) {
let crossOriginFrame = document.createElement('iframe');
crossOriginFrame.src = 'https://{{hosts[alt][]}}:{{ports[https][0]}}/common/blank.html';
document.body.appendChild(crossOriginFrame);
crossOriginFrame.addEventListener('load', t.step_func_done(function() {
let crossOriginWindow = crossOriginFrame.contentWindow;
window.addEventListener('click', crossOriginWindow);
}));
}, "EventListener.addEventListener doesn't throw when a cross origin object is passed in.");

View File

@ -0,0 +1,75 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>Cross-realm EventListener throws TypeError of its associated Realm</title>
<link rel="help" href="https://webidl.spec.whatwg.org/#ref-for-prepare-to-run-script">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<iframe name="eventListenerGlobalObject" src="resources/empty-document.html"></iframe>
<script>
setup({ allow_uncaught_exception: true });
test_onload(() => {
const eventTarget = new EventTarget;
const eventListener = new eventListenerGlobalObject.Object;
eventTarget.addEventListener("foo", eventListener);
assert_reports_exception(eventListenerGlobalObject.TypeError, () => { eventTarget.dispatchEvent(new Event("foo")); });
}, "EventListener is cross-realm plain object without 'handleEvent' property");
test_onload(() => {
const eventTarget = new EventTarget;
const eventListener = new eventListenerGlobalObject.Object;
eventListener.handleEvent = {};
eventTarget.addEventListener("foo", eventListener);
assert_reports_exception(eventListenerGlobalObject.TypeError, () => { eventTarget.dispatchEvent(new Event("foo")); });
}, "EventListener is cross-realm plain object with non-callable 'handleEvent' property");
test_onload(() => {
const eventTarget = new EventTarget;
const { proxy, revoke } = Proxy.revocable(() => {}, {});
revoke();
const eventListener = new eventListenerGlobalObject.Object;
eventListener.handleEvent = proxy;
eventTarget.addEventListener("foo", eventListener);
assert_reports_exception(eventListenerGlobalObject.TypeError, () => { eventTarget.dispatchEvent(new Event("foo")); });
}, "EventListener is cross-realm plain object with revoked Proxy as 'handleEvent' property");
test_onload(() => {
const eventTarget = new EventTarget;
const { proxy, revoke } = eventListenerGlobalObject.Proxy.revocable({}, {});
revoke();
eventTarget.addEventListener("foo", proxy);
assert_reports_exception(eventListenerGlobalObject.TypeError, () => { eventTarget.dispatchEvent(new Event("foo")); });
}, "EventListener is cross-realm non-callable revoked Proxy");
test_onload(() => {
const eventTarget = new EventTarget;
const { proxy, revoke } = eventListenerGlobalObject.Proxy.revocable(() => {}, {});
revoke();
eventTarget.addEventListener("foo", proxy);
assert_reports_exception(eventListenerGlobalObject.TypeError, () => { eventTarget.dispatchEvent(new Event("foo")); });
}, "EventListener is cross-realm callable revoked Proxy");
function test_onload(fn, desc) {
async_test(t => { window.addEventListener("load", t.step_func_done(fn)); }, desc);
}
function assert_reports_exception(expectedConstructor, fn) {
let error;
const onErrorHandler = event => { error = event.error; };
eventListenerGlobalObject.addEventListener("error", onErrorHandler);
fn();
eventListenerGlobalObject.removeEventListener("error", onErrorHandler);
assert_equals(typeof error, "object");
assert_equals(error.constructor, expectedConstructor);
}
</script>

View File

@ -0,0 +1,102 @@
<!DOCTYPE html>
<meta charset=utf-8>
<title>EventListener::handleEvent()</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<link rel="help" href="https://dom.spec.whatwg.org/#callbackdef-eventlistener">
<div id=log></div>
<script>
setup({ allow_uncaught_exception: true });
test(function(t) {
var type = "foo";
var target = document.createElement("div");
var eventListener = {
handleEvent: function(evt) {
var that = this;
t.step(function() {
assert_equals(evt.type, type);
assert_equals(evt.target, target);
assert_equals(evt.srcElement, target);
assert_equals(that, eventListener);
});
},
};
target.addEventListener(type, eventListener);
target.dispatchEvent(new Event(type));
}, "calls `handleEvent` method of `EventListener`");
test(function(t) {
var type = "foo";
var target = document.createElement("div");
var calls = 0;
target.addEventListener(type, {
get handleEvent() {
calls++;
return function() {};
},
});
assert_equals(calls, 0);
target.dispatchEvent(new Event(type));
target.dispatchEvent(new Event(type));
assert_equals(calls, 2);
}, "performs `Get` every time event is dispatched");
test(function(t) {
var type = "foo";
var target = document.createElement("div");
var calls = 0;
var eventListener = function() { calls++; };
eventListener.handleEvent = t.unreached_func("`handleEvent` method should not be called on functions");
target.addEventListener(type, eventListener);
target.dispatchEvent(new Event(type));
assert_equals(calls, 1);
}, "doesn't call `handleEvent` method on callable `EventListener`");
const uncaught_error_test = async (t, getHandleEvent) => {
const type = "foo";
const target = document.createElement("div");
let calls = 0;
target.addEventListener(type, {
get handleEvent() {
calls++;
return getHandleEvent();
},
});
const timeout = () => {
return new Promise(resolve => {
t.step_timeout(resolve, 0);
});
};
const eventWatcher = new EventWatcher(t, window, "error", timeout);
const errorPromise = eventWatcher.wait_for("error");
target.dispatchEvent(new Event(type));
const event = await errorPromise;
assert_equals(calls, 1, "handleEvent property was not looked up");
throw event.error;
};
promise_test(t => {
const error = { name: "test" };
return promise_rejects_exactly(t, error,
uncaught_error_test(t, () => { throw error; }));
}, "rethrows errors when getting `handleEvent`");
promise_test(t => {
return promise_rejects_js(t, TypeError, uncaught_error_test(t, () => null));
}, "throws if `handleEvent` is falsy and not callable");
promise_test(t => {
return promise_rejects_js(t, TypeError, uncaught_error_test(t, () => 42));
}, "throws if `handleEvent` is thruthy and not callable");
</script>

View File

@ -0,0 +1,20 @@
<!doctype html>
<meta charset=utf-8>
<title></title>
<script src=/resources/testharness.js></script>
<script src=/resources/testharnessreport.js></script>
<iframe src="{{location[scheme]}}://{{domains[www1]}}:{{ports[http][0]}}{{location[path]}}/../EventListener-incumbent-global-subframe-1.sub.html"></iframe>
<script>
var t = async_test("Check the incumbent global EventListeners are called with");
onload = t.step_func(function() {
onmessage = t.step_func_done(function(e) {
var d = e.data;
assert_equals(d.actual, d.expected, d.reason);
});
frames[0].postMessage("start", "*");
});
</script>

View File

@ -0,0 +1,20 @@
<!doctype html>
<meta charset=utf-8>
<title></title>
<script src=/resources/testharness.js></script>
<script src=/resources/testharnessreport.js></script>
<iframe src="{{location[scheme]}}://{{domains[www1]}}:{{ports[http][0]}}{{location[path]}}/../EventListener-incumbent-global-subframe-2.sub.html"></iframe>
<script>
var t = async_test("Check the incumbent global EventListeners are called with");
onload = t.step_func(function() {
onmessage = t.step_func_done(function(e) {
var d = e.data;
assert_equals(d.actual, d.expected, d.reason);
});
frames[0].postMessage("start", "*");
});
</script>

View File

@ -0,0 +1,13 @@
<!DOCTYPE html>
<iframe src="{{location[scheme]}}://{{domains[www2]}}:{{ports[http][0]}}{{location[path]}}/../EventListener-incumbent-global-subsubframe.sub.html"></iframe>
<script>
document.domain = "{{host}}";
onmessage = function(e) {
if (e.data == "start") {
frames[0].document.body.addEventListener("click", frames[0].postMessage.bind(frames[0], "respond", "*", undefined));
frames[0].postMessage("sendclick", "*");
} else {
parent.postMessage(e.data, "*");
}
}
</script>

View File

@ -0,0 +1,13 @@
<!DOCTYPE html>
<iframe src="{{location[scheme]}}://{{domains[www2]}}:{{ports[http][0]}}{{location[path]}}/../EventListener-incumbent-global-subsubframe.sub.html"></iframe>
<script>
document.domain = "{{host}}";
onmessage = function(e) {
if (e.data == "start") {
frames[0].document.body.addEventListener("click", frames[0].getTheListener());
frames[0].postMessage("sendclick", "*");
} else {
parent.postMessage(e.data, "*");
}
}
</script>

View File

@ -0,0 +1,20 @@
<!DOCTYPE html>
<script>
function getTheListener() {
return postMessage.bind(this, "respond", "*", undefined)
}
document.domain = "{{host}}";
onmessage = function (e) {
if (e.data == "sendclick") {
document.body.click();
} else {
parent.postMessage(
{
actual: e.origin,
expected: parent.location.origin,
reason: "Incumbent should have been the caller of addEventListener()"
},
"*")
};
}
</script>

View File

@ -0,0 +1,66 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>Invoke legacy event listener</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<style>
@keyframes test {
0% { color: red; }
100% { color: green; }
}
</style>
<div id="log"></div>
<script>
function runLegacyEventTest(type, legacyType, ctor, setup) {
function createTestElem(t) {
var elem = document.createElement('div');
document.body.appendChild(elem);
t.add_cleanup(function() {
document.body.removeChild(elem);
});
return elem;
}
async_test(function(t) {
var elem = createTestElem(t);
var gotEvent = false;
elem.addEventListener(legacyType,
t.unreached_func("listener of " + legacyType + " should not be invoked"));
elem.addEventListener(type, t.step_func(function() {
assert_false(gotEvent, "unexpected " + type + " event");
gotEvent = true;
t.step_timeout(function() { t.done(); }, 100);
}));
setup(elem);
}, "Listener of " + type);
async_test(function(t) {
var elem = createTestElem(t);
var count = 0;
elem.addEventListener(legacyType, t.step_func(function() {
++count;
if (count > 1) {
assert_unreached("listener of " + legacyType + " should not be invoked again");
return;
}
elem.dispatchEvent(new window[ctor](type));
t.done();
}));
setup(elem);
}, "Legacy listener of " + type);
}
function setupTransition(elem) {
getComputedStyle(elem).color;
elem.style.color = 'green';
elem.style.transition = 'color 30ms';
}
function setupAnimation(elem) {
elem.style.animation = 'test 30ms';
}
runLegacyEventTest('transitionend', 'webkitTransitionEnd', "TransitionEvent", setupTransition);
runLegacyEventTest('animationend', 'webkitAnimationEnd', "AnimationEvent", setupAnimation);
runLegacyEventTest('animationstart', 'webkitAnimationStart', "AnimationEvent", setupAnimation);
</script>

View File

@ -0,0 +1,98 @@
<!DOCTYPE HTML>
<meta charset="utf-8">
<title>EventListenerOptions.capture</title>
<link rel="author" title="Rick Byers" href="mailto:rbyers@chromium.org">
<link rel="help" href="https://dom.spec.whatwg.org/#dom-eventlisteneroptions-capture">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<div id="log"></div>
<script>
function testCaptureValue(captureValue, expectedValue) {
var handlerPhase = undefined;
var handler = function handler(e) {
assert_equals(handlerPhase, undefined, "Handler invoked after remove");
handlerPhase = e.eventPhase;
}
document.addEventListener('test', handler, captureValue);
document.body.dispatchEvent(new Event('test', {bubbles: true}));
document.removeEventListener('test', handler, captureValue);
document.body.dispatchEvent(new Event('test', {bubbles: true}));
assert_equals(handlerPhase, expectedValue, "Incorrect event phase for value: " + JSON.stringify(captureValue));
}
test(function() {
testCaptureValue(true, Event.CAPTURING_PHASE);
testCaptureValue(false, Event.BUBBLING_PHASE);
testCaptureValue(null, Event.BUBBLING_PHASE);
testCaptureValue(undefined, Event.BUBBLING_PHASE);
testCaptureValue(2.3, Event.CAPTURING_PHASE);
testCaptureValue(-1000.3, Event.CAPTURING_PHASE);
testCaptureValue(NaN, Event.BUBBLING_PHASE);
testCaptureValue(+0.0, Event.BUBBLING_PHASE);
testCaptureValue(-0.0, Event.BUBBLING_PHASE);
testCaptureValue("", Event.BUBBLING_PHASE);
testCaptureValue("AAAA", Event.CAPTURING_PHASE);
}, "Capture boolean should be honored correctly");
test(function() {
testCaptureValue({}, Event.BUBBLING_PHASE);
testCaptureValue({capture:true}, Event.CAPTURING_PHASE);
testCaptureValue({capture:false}, Event.BUBBLING_PHASE);
testCaptureValue({capture:2}, Event.CAPTURING_PHASE);
testCaptureValue({capture:0}, Event.BUBBLING_PHASE);
}, "Capture option should be honored correctly");
test(function() {
var supportsCapture = false;
var query_options = {
get capture() {
supportsCapture = true;
return false;
},
get dummy() {
assert_unreached("dummy value getter invoked");
return false;
}
};
document.addEventListener('test_event', null, query_options);
assert_true(supportsCapture, "addEventListener doesn't support the capture option");
supportsCapture = false;
document.removeEventListener('test_event', null, query_options);
assert_true(supportsCapture, "removeEventListener doesn't support the capture option");
}, "Supports capture option");
function testOptionEquality(addOptionValue, removeOptionValue, expectedEquality) {
var handlerInvoked = false;
var handler = function handler(e) {
assert_equals(handlerInvoked, false, "Handler invoked multiple times");
handlerInvoked = true;
}
document.addEventListener('test', handler, addOptionValue);
document.removeEventListener('test', handler, removeOptionValue);
document.body.dispatchEvent(new Event('test', {bubbles: true}));
assert_equals(!handlerInvoked, expectedEquality, "equivalence of options " +
JSON.stringify(addOptionValue) + " and " + JSON.stringify(removeOptionValue));
if (handlerInvoked)
document.removeEventListener('test', handler, addOptionValue);
}
test(function() {
// Option values that should be treated as equivalent
testOptionEquality({}, false, true);
testOptionEquality({capture: false}, false, true);
testOptionEquality(true, {capture: true}, true);
testOptionEquality({capture: null}, undefined, true);
testOptionEquality({capture: true}, {dummy: false, capture: 1}, true);
testOptionEquality({dummy: true}, false, true);
// Option values that should be treated as distinct
testOptionEquality(true, false, false);
testOptionEquality(true, {capture:false}, false);
testOptionEquality({}, true, false);
}, "Equivalence of option values");
</script>

View File

@ -0,0 +1,32 @@
<!DOCTYPE html>
<meta charset=utf-8>
<title>addEventListener with a platform object</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script>
</script>
<my-custom-click id=click>Click me!</my-custom-click>
<script>
"use strict";
setup({ single_test: true });
class MyCustomClick extends HTMLElement {
connectedCallback() {
this.addEventListener("click", this);
}
handleEvent(event) {
if (event.target === this) {
this.dataset.yay = "It worked!";
}
}
}
window.customElements.define("my-custom-click", MyCustomClick);
const customElement = document.getElementById("click");
customElement.click();
assert_equals(customElement.dataset.yay, "It worked!");
done();
</script>

View File

@ -0,0 +1,21 @@
// META: title=EventTarget's addEventListener + removeEventListener
"use strict";
function listener(evt) {
evt.preventDefault();
return false;
}
test(() => {
const et = new EventTarget();
et.addEventListener("x", listener, false);
let event = new Event("x", { cancelable: true });
let ret = et.dispatchEvent(event);
assert_false(ret);
et.removeEventListener("x", listener);
event = new Event("x", { cancelable: true });
ret = et.dispatchEvent(event);
assert_true(ret);
}, "Removing an event listener without explicit capture arg should succeed");

View File

@ -0,0 +1,9 @@
// META: title=EventTarget.addEventListener
// Step 1.
test(function() {
const et = new EventTarget();
assert_equals(et.addEventListener("x", null, false), undefined);
assert_equals(et.addEventListener("x", null, true), undefined);
assert_equals(et.addEventListener("x", null), undefined);
}, "Adding a null event listener should succeed");

View File

@ -0,0 +1,79 @@
"use strict";
test(() => {
const target = new EventTarget();
const event = new Event("foo", { bubbles: true, cancelable: false });
let callCount = 0;
function listener(e) {
assert_equals(e, event);
++callCount;
}
target.addEventListener("foo", listener);
target.dispatchEvent(event);
assert_equals(callCount, 1);
target.dispatchEvent(event);
assert_equals(callCount, 2);
target.removeEventListener("foo", listener);
target.dispatchEvent(event);
assert_equals(callCount, 2);
}, "A constructed EventTarget can be used as expected");
test(() => {
const target = new EventTarget();
const event = new Event("foo");
function listener(e) {
assert_equals(e, event);
assert_equals(e.target, target);
assert_equals(e.currentTarget, target);
assert_array_equals(e.composedPath(), [target]);
}
target.addEventListener("foo", listener, { once: true });
target.dispatchEvent(event);
assert_equals(event.target, target);
assert_equals(event.currentTarget, null);
assert_array_equals(event.composedPath(), []);
}, "A constructed EventTarget implements dispatch correctly");
test(() => {
class NicerEventTarget extends EventTarget {
on(...args) {
this.addEventListener(...args);
}
off(...args) {
this.removeEventListener(...args);
}
dispatch(type, detail) {
this.dispatchEvent(new CustomEvent(type, { detail }));
}
}
const target = new NicerEventTarget();
const event = new Event("foo", { bubbles: true, cancelable: false });
const detail = "some data";
let callCount = 0;
function listener(e) {
assert_equals(e.detail, detail);
++callCount;
}
target.on("foo", listener);
target.dispatch("foo", detail);
assert_equals(callCount, 1);
target.dispatch("foo", detail);
assert_equals(callCount, 2);
target.off("foo", listener);
target.dispatch("foo", detail);
assert_equals(callCount, 2);
}, "EventTarget can be subclassed");

View File

@ -0,0 +1,71 @@
<!DOCTYPE html>
<meta charset=utf-8>
<title>EventTarget.dispatchEvent: return value</title>
<link rel="help" href="https://dom.spec.whatwg.org/#concept-event-dispatch">
<link rel="help" href="https://dom.spec.whatwg.org/#dom-event-preventdefault">
<link rel="help" href="https://dom.spec.whatwg.org/#dom-event-returnvalue">
<link rel="help" href="https://dom.spec.whatwg.org/#dom-event-defaultprevented">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<div id=log></div>
<table id="table" border="1" style="display: none">
<tbody id="table-body">
<tr id="table-row">
<td id="table-cell">Shady Grove</td>
<td>Aeolian</td>
</tr>
<tr id="parent">
<td id="target">Over the river, Charlie</td>
<td>Dorian</td>
</tr>
</tbody>
</table>
<script>
test(function() {
var event_type = "foo";
var target = document.getElementById("target");
var parent = document.getElementById("parent");
var default_prevented;
var return_value;
parent.addEventListener(event_type, function(e) {}, true);
target.addEventListener(event_type, function(e) {
evt.preventDefault();
default_prevented = evt.defaultPrevented;
return_value = evt.returnValue;
}, true);
target.addEventListener(event_type, function(e) {}, true);
var evt = document.createEvent("Event");
evt.initEvent(event_type, true, true);
assert_true(parent.dispatchEvent(evt));
assert_false(target.dispatchEvent(evt));
assert_true(default_prevented);
assert_false(return_value);
}, "Return value of EventTarget.dispatchEvent() affected by preventDefault().");
test(function() {
var event_type = "foo";
var target = document.getElementById("target");
var parent = document.getElementById("parent");
var default_prevented;
var return_value;
parent.addEventListener(event_type, function(e) {}, true);
target.addEventListener(event_type, function(e) {
evt.returnValue = false;
default_prevented = evt.defaultPrevented;
return_value = evt.returnValue;
}, true);
target.addEventListener(event_type, function(e) {}, true);
var evt = document.createEvent("Event");
evt.initEvent(event_type, true, true);
assert_true(parent.dispatchEvent(evt));
assert_false(target.dispatchEvent(evt));
assert_true(default_prevented);
assert_false(return_value);
}, "Return value of EventTarget.dispatchEvent() affected by returnValue.");
</script>

View File

@ -0,0 +1,104 @@
<!DOCTYPE html>
<meta charset=utf-8>
<title>EventTarget.dispatchEvent</title>
<link rel="author" title="Olli Pettay" href="mailto:Olli.Pettay@gmail.com">
<link rel="author" title="Ms2ger" href="mailto:Ms2ger@gmail.com">
<link rel="help" href="https://dom.spec.whatwg.org/#dom-eventtarget-dispatchevent">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/dom/nodes/Document-createEvent.js"></script>
<div id="log"></div>
<script>
setup({
"allow_uncaught_exception": true,
})
test(function() {
assert_throws_js(TypeError, function() { document.dispatchEvent(null) })
}, "Calling dispatchEvent(null).")
for (var alias in aliases) {
test(function() {
var e = document.createEvent(alias)
assert_equals(e.type, "", "Event type should be empty string before initialization")
assert_throws_dom("InvalidStateError", function() { document.dispatchEvent(e) })
}, "If the event's initialized flag is not set, an InvalidStateError must be thrown (" + alias + ").")
}
var dispatch_dispatch = async_test("If the event's dispatch flag is set, an InvalidStateError must be thrown.")
dispatch_dispatch.step(function() {
var e = document.createEvent("Event")
e.initEvent("type", false, false)
var target = document.createElement("div")
target.addEventListener("type", dispatch_dispatch.step_func(function() {
assert_throws_dom("InvalidStateError", function() {
target.dispatchEvent(e)
})
assert_throws_dom("InvalidStateError", function() {
document.dispatchEvent(e)
})
}), false)
assert_equals(target.dispatchEvent(e), true, "dispatchEvent must return true")
dispatch_dispatch.done()
})
test(function() {
// https://www.w3.org/Bugs/Public/show_bug.cgi?id=17713
// https://www.w3.org/Bugs/Public/show_bug.cgi?id=17714
var e = document.createEvent("Event")
e.initEvent("type", false, false)
var called = []
var target = document.createElement("div")
target.addEventListener("type", function() {
called.push("First")
throw new Error()
}, false)
target.addEventListener("type", function() {
called.push("Second")
}, false)
assert_equals(target.dispatchEvent(e), true, "dispatchEvent must return true")
assert_array_equals(called, ["First", "Second"],
"Should have continued to call other event listeners")
}, "Exceptions from event listeners must not be propagated.")
async_test(function() {
var results = []
var outerb = document.createElement("b")
var middleb = outerb.appendChild(document.createElement("b"))
var innerb = middleb.appendChild(document.createElement("b"))
outerb.addEventListener("x", this.step_func(function() {
middleb.addEventListener("x", this.step_func(function() {
results.push("middle")
}), true)
results.push("outer")
}), true)
innerb.dispatchEvent(new Event("x"))
assert_array_equals(results, ["outer", "middle"])
this.done()
}, "Event listeners added during dispatch should be called");
async_test(function() {
var results = []
var b = document.createElement("b")
b.addEventListener("x", this.step_func(function() {
results.push(1)
}), true)
b.addEventListener("x", this.step_func(function() {
results.push(2)
}), false)
b.addEventListener("x", this.step_func(function() {
results.push(3)
}), true)
b.dispatchEvent(new Event("x"))
assert_array_equals(results, [1, 3, 2])
this.done()
}, "Capturing event listeners should be called before non-capturing ones")
</script>

View File

@ -0,0 +1,8 @@
// META: title=EventTarget.removeEventListener
// Step 1.
test(function() {
assert_equals(globalThis.removeEventListener("x", null, false), undefined);
assert_equals(globalThis.removeEventListener("x", null, true), undefined);
assert_equals(globalThis.removeEventListener("x", null), undefined);
}, "removing a null event listener should succeed");

View File

@ -0,0 +1,182 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>EventTarget listeners this value</title>
<link rel="author" title="Domenic Denicola" href="mailto:d@domenic.me">
<link rel="help" href="https://dom.spec.whatwg.org/#concept-event-listener-invoke">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script>
"use strict";
test(() => {
const nodes = [
document.createElement("p"),
document.createTextNode("some text"),
document.createDocumentFragment(),
document.createComment("a comment"),
document.createProcessingInstruction("target", "data")
];
let callCount = 0;
for (const node of nodes) {
node.addEventListener("someevent", function () {
++callCount;
assert_equals(this, node);
});
node.dispatchEvent(new CustomEvent("someevent"));
}
assert_equals(callCount, nodes.length);
}, "the this value inside the event listener callback should be the node");
test(() => {
const nodes = [
document.createElement("p"),
document.createTextNode("some text"),
document.createDocumentFragment(),
document.createComment("a comment"),
document.createProcessingInstruction("target", "data")
];
let callCount = 0;
for (const node of nodes) {
const handler = {
handleEvent() {
++callCount;
assert_equals(this, handler);
}
};
node.addEventListener("someevent", handler);
node.dispatchEvent(new CustomEvent("someevent"));
}
assert_equals(callCount, nodes.length);
}, "the this value inside the event listener object handleEvent should be the object");
test(() => {
const nodes = [
document.createElement("p"),
document.createTextNode("some text"),
document.createDocumentFragment(),
document.createComment("a comment"),
document.createProcessingInstruction("target", "data")
];
let callCount = 0;
for (const node of nodes) {
const handler = {
handleEvent() {
assert_unreached("should not call the old handleEvent method");
}
};
node.addEventListener("someevent", handler);
handler.handleEvent = function () {
++callCount;
assert_equals(this, handler);
};
node.dispatchEvent(new CustomEvent("someevent"));
}
assert_equals(callCount, nodes.length);
}, "dispatchEvent should invoke the current handleEvent method of the object");
test(() => {
const nodes = [
document.createElement("p"),
document.createTextNode("some text"),
document.createDocumentFragment(),
document.createComment("a comment"),
document.createProcessingInstruction("target", "data")
];
let callCount = 0;
for (const node of nodes) {
const handler = {};
node.addEventListener("someevent", handler);
handler.handleEvent = function () {
++callCount;
assert_equals(this, handler);
};
node.dispatchEvent(new CustomEvent("someevent"));
}
assert_equals(callCount, nodes.length);
}, "addEventListener should not require handleEvent to be defined on object listeners");
test(() => {
const nodes = [
document.createElement("p"),
document.createTextNode("some text"),
document.createDocumentFragment(),
document.createComment("a comment"),
document.createProcessingInstruction("target", "data")
];
let callCount = 0;
for (const node of nodes) {
function handler() {
++callCount;
assert_equals(this, node);
}
handler.handleEvent = () => {
assert_unreached("should not call the handleEvent method on a function");
};
node.addEventListener("someevent", handler);
node.dispatchEvent(new CustomEvent("someevent"));
}
assert_equals(callCount, nodes.length);
}, "handleEvent properties added to a function before addEventListener are not reached");
test(() => {
const nodes = [
document.createElement("p"),
document.createTextNode("some text"),
document.createDocumentFragment(),
document.createComment("a comment"),
document.createProcessingInstruction("target", "data")
];
let callCount = 0;
for (const node of nodes) {
function handler() {
++callCount;
assert_equals(this, node);
}
node.addEventListener("someevent", handler);
handler.handleEvent = () => {
assert_unreached("should not call the handleEvent method on a function");
};
node.dispatchEvent(new CustomEvent("someevent"));
}
assert_equals(callCount, nodes.length);
}, "handleEvent properties added to a function after addEventListener are not reached");
</script>

View File

@ -0,0 +1,23 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>KeyEvent.initKeyEvent</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<div id="log"></div>
<script>
// The legacy KeyEvent.initKeyEvent shouldn't be defined in the wild anymore.
// https://www.w3.org/TR/1999/WD-DOM-Level-2-19990923/events.html#Events-Event-initKeyEvent
test(function() {
const event = document.createEvent("KeyboardEvent");
assert_true(event?.initKeyEvent === undefined);
}, "KeyboardEvent.initKeyEvent shouldn't be defined (created by createEvent(\"KeyboardEvent\")");
test(function() {
const event = new KeyboardEvent("keypress");
assert_true(event?.initKeyEvent === undefined);
}, "KeyboardEvent.initKeyEvent shouldn't be defined (created by constructor)");
test(function() {
assert_true(KeyboardEvent.prototype.initKeyEvent === undefined);
}, "KeyboardEvent.prototype.initKeyEvent shouldn't be defined");
</script>

View File

@ -0,0 +1,21 @@
<!doctype html>
<meta charset=utf-8>
<title>Test that disabled is honored immediately in presence of dynamic changes</title>
<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
<link rel="author" title="Andreas Farre" href="mailto:afarre@mozilla.com">
<link rel="help" href="https://html.spec.whatwg.org/multipage/#enabling-and-disabling-form-controls:-the-disabled-attribute">
<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1405087">
<script src=/resources/testharness.js></script>
<script src=/resources/testharnessreport.js></script>
<input type="button" value="Click" disabled>
<script>
async_test(t => {
// NOTE: This test will timeout if it fails.
window.addEventListener('load', t.step_func(() => {
let e = document.querySelector('input');
e.disabled = false;
e.onclick = t.step_func_done(() => {});
e.click();
}));
}, "disabled is honored properly in presence of dynamic changes");
</script>

View File

@ -0,0 +1,90 @@
const otherWindow = document.body.appendChild(document.createElement("iframe")).contentWindow;
["EventTarget", "XMLHttpRequest"].forEach(constructorName => {
async_test(t => {
const eventTarget = new otherWindow[constructorName]();
eventTarget.addEventListener("hi", t.step_func_done(e => {
assert_equals(otherWindow.event, undefined);
assert_equals(e, window.event);
}));
eventTarget.dispatchEvent(new Event("hi"));
}, "window.event for constructors from another global: " + constructorName);
});
// XXX: It would be good to test a subclass of EventTarget once we sort out
// https://github.com/heycam/webidl/issues/540
async_test(t => {
const element = document.body.appendChild(otherWindow.document.createElement("meh"));
element.addEventListener("yo", t.step_func_done(e => {
assert_equals(e, window.event);
}));
element.dispatchEvent(new Event("yo"));
}, "window.event and element from another document");
async_test(t => {
const doc = otherWindow.document,
element = doc.body.appendChild(doc.createElement("meh")),
child = element.appendChild(doc.createElement("bleh"));
element.addEventListener("yoyo", t.step_func(e => {
document.body.appendChild(element);
assert_equals(element.ownerDocument, document);
assert_equals(window.event, e);
assert_equals(otherWindow.event, undefined);
}), true);
element.addEventListener("yoyo", t.step_func(e => {
assert_equals(element.ownerDocument, document);
assert_equals(window.event, e);
assert_equals(otherWindow.event, undefined);
}), true);
child.addEventListener("yoyo", t.step_func_done(e => {
assert_equals(child.ownerDocument, document);
assert_equals(window.event, e);
assert_equals(otherWindow.event, undefined);
}));
child.dispatchEvent(new Event("yoyo"));
}, "window.event and moving an element post-dispatch");
test(t => {
const host = document.createElement("div"),
shadow = host.attachShadow({ mode: "open" }),
child = shadow.appendChild(document.createElement("trala")),
furtherChild = child.appendChild(document.createElement("waddup"));
let counter = 0;
host.addEventListener("hi", t.step_func(e => {
assert_equals(window.event, e);
assert_equals(counter++, 3);
}));
child.addEventListener("hi", t.step_func(e => {
assert_equals(window.event, undefined);
assert_equals(counter++, 2);
}));
furtherChild.addEventListener("hi", t.step_func(e => {
host.appendChild(child);
assert_equals(window.event, undefined);
assert_equals(counter++, 0);
}));
furtherChild.addEventListener("hi", t.step_func(e => {
assert_equals(window.event, undefined);
assert_equals(counter++, 1);
}));
furtherChild.dispatchEvent(new Event("hi", { composed: true, bubbles: true }));
assert_equals(counter, 4);
}, "window.event should not be affected by nodes moving post-dispatch");
async_test(t => {
const frame = document.body.appendChild(document.createElement("iframe"));
frame.src = "resources/event-global-extra-frame.html";
frame.onload = t.step_func_done((load_event) => {
const event = new Event("hi");
document.addEventListener("hi", frame.contentWindow.listener); // listener intentionally not wrapped in t.step_func
document.addEventListener("hi", t.step_func(e => {
assert_equals(event, e);
assert_equals(window.event, e);
}));
document.dispatchEvent(event);
assert_equals(frameState.event, event);
assert_equals(frameState.windowEvent, event);
assert_equals(frameState.parentEvent, load_event);
});
}, "Listener from a different global");

View File

@ -0,0 +1,23 @@
<!doctype html>
<meta charset="utf-8">
<title>window.event is still set when 'beforeunload' result is coerced to string</title>
<link rel="help" href="https://dom.spec.whatwg.org/#ref-for-window-current-event%E2%91%A1">
<link rel="help" href="https://webidl.spec.whatwg.org/#call-a-user-objects-operation">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<iframe id="iframe" src="resources/event-global-is-still-set-when-coercing-beforeunload-result-frame.html"></iframe>
<body>
<script>
window.onload = () => {
async_test(t => {
iframe.onload = t.step_func_done(() => {
assert_equals(typeof window.currentEventInToString, "object");
assert_equals(window.currentEventInToString.type, "beforeunload");
});
iframe.contentWindow.location.href = "about:blank";
});
};
</script>

View File

@ -0,0 +1,43 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>window.onerror handler restores window.event after it reports an exception</title>
<link rel="help" href="https://dom.spec.whatwg.org/#concept-event-listener-inner-invoke">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<body>
<iframe src="resources/empty-document.html"></iframe>
<iframe src="resources/empty-document.html"></iframe>
<script>
setup({ allow_uncaught_exception: true });
async_test(t => {
window.onload = t.step_func_done(onLoadEvent => {
frames[0].onerror = new frames[1].Function(`
top.eventDuringSecondOnError = top.window.event;
top.frames[0].eventDuringSecondOnError = top.frames[0].event;
top.frames[1].eventDuringSecondOnError = top.frames[1].event;
`);
window.onerror = new frames[0].Function(`
top.eventDuringFirstOnError = top.window.event;
top.frames[0].eventDuringFirstOnError = top.frames[0].event;
top.frames[1].eventDuringFirstOnError = top.frames[1].event;
foo; // cause second onerror
`);
const myEvent = new ErrorEvent("error", { error: new Error("myError") });
window.dispatchEvent(myEvent);
assert_equals(top.eventDuringFirstOnError, onLoadEvent);
assert_equals(frames[0].eventDuringFirstOnError, myEvent);
assert_equals(frames[1].eventDuringFirstOnError, undefined);
assert_equals(top.eventDuringSecondOnError, onLoadEvent);
assert_equals(frames[0].eventDuringSecondOnError, myEvent);
assert_equals(frames[1].eventDuringSecondOnError.error.name, "ReferenceError");
});
});
</script>

View File

@ -0,0 +1,19 @@
// https://dom.spec.whatwg.org/#concept-event-listener-inner-invoke (steps 8.2 - 12)
// https://webidl.spec.whatwg.org/#call-a-user-objects-operation (step 10.1)
test(() => {
const eventTarget = new EventTarget;
let currentEvent;
eventTarget.addEventListener("foo", {
get handleEvent() {
currentEvent = window.event;
return () => {};
}
});
const event = new Event("foo");
eventTarget.dispatchEvent(event);
assert_equals(currentEvent, event);
}, "window.event is set before 'handleEvent' lookup");

View File

@ -0,0 +1,127 @@
<!DOCTYPE html>
<title>window.event tests</title>
<link rel="author" title="Mike Taylor" href="mailto:miketaylr@gmail.com">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<div id=log></div>
<script>
setup({allow_uncaught_exception: true});
test(t => {
assert_own_property(window, "event");
assert_equals(window.event, undefined);
}, "event exists on window, which is initially set to undefined");
async_test(t => {
let target = document.createElement("div");
assert_equals(window.event, undefined, "undefined before dispatch");
let clickEvent = new Event("click");
target.addEventListener("click", t.step_func_done(e => {
assert_equals(window.event, clickEvent, "window.event set to current event during dispatch");
}));
target.dispatchEvent(clickEvent);
assert_equals(window.event, undefined, "undefined after dispatch");
}, "window.event is only defined during dispatch");
async_test(t => {
let parent = document.createElement("div");
let root = parent.attachShadow({mode: "closed"});
let span = document.createElement("span");
root.appendChild(span);
span.addEventListener("test", t.step_func(e => {
assert_equals(window.event, undefined);
assert_not_equals(window.event, e);
}));
parent.addEventListener("test", t.step_func_done(e => {
assert_equals(window.event, e);
assert_not_equals(window.event, undefined);
}));
parent.dispatchEvent(new Event("test", {composed: true}));
}, "window.event is undefined if the target is in a shadow tree (event dispatched outside shadow tree)");
async_test(t => {
let parent = document.createElement("div");
let root = parent.attachShadow({mode: "closed"});
let span = document.createElement("span");
root.appendChild(span);
let shadowNode = root.firstElementChild;
shadowNode.addEventListener("test", t.step_func((e) => {
assert_not_equals(window.event, e);
assert_equals(window.event, undefined);
}));
parent.addEventListener("test", t.step_func_done(e => {
assert_equals(window.event, e);
assert_not_equals(window.event, undefined);
}));
shadowNode.dispatchEvent(new Event("test", {composed: true, bubbles: true}));
}, "window.event is undefined if the target is in a shadow tree (event dispatched inside shadow tree)");
async_test(t => {
let parent = document.createElement("div");
let root = parent.attachShadow({mode: "open"});
document.body.append(parent)
let span = document.createElement("span");
root.append(span);
let shadowNode = root.firstElementChild;
shadowNode.addEventListener("error", t.step_func(e => {
assert_not_equals(window.event, e);
assert_equals(window.event, undefined);
}));
let windowOnErrorCalled = false;
window.onerror = t.step_func_done(() => {
windowOnErrorCalled = true;
assert_equals(typeof window.event, "object");
assert_equals(window.event.type, "error");
});
shadowNode.dispatchEvent(new ErrorEvent("error", {composed: true, bubbles: true}));
assert_true(windowOnErrorCalled);
}, "window.event is undefined inside window.onerror if the target is in a shadow tree (ErrorEvent dispatched inside shadow tree)");
async_test(t => {
let target1 = document.createElement("div");
let target2 = document.createElement("div");
target2.addEventListener("dude", t.step_func(() => {
assert_equals(window.event.type, "dude");
}));
target1.addEventListener("cool", t.step_func_done(() => {
assert_equals(window.event.type, "cool", "got expected event from global event during dispatch");
target2.dispatchEvent(new Event("dude"));
assert_equals(window.event.type, "cool", "got expected event from global event after handling a different event handler callback");
}));
target1.dispatchEvent(new Event("cool"));
}, "window.event is set to the current event during dispatch");
async_test(t => {
let target = document.createElement("div");
target.addEventListener("click", t.step_func_done(e => {
assert_equals(e, window.event);
}));
target.dispatchEvent(new Event("click"));
}, "window.event is set to the current event, which is the event passed to dispatch");
async_test(t => {
let target = new XMLHttpRequest();
target.onload = t.step_func_done(e => {
assert_equals(e, window.event);
});
target.dispatchEvent(new Event("load"));
}, "window.event is set to the current event, which is the event passed to dispatch (2)");
</script>

View File

@ -0,0 +1,14 @@
importScripts("/resources/testharness.js");
test(t => {
let seen = false;
const event = new Event("hi");
assert_equals(self.event, undefined);
self.addEventListener("hi", t.step_func(e => {
seen = true;
assert_equals(self.event, undefined);
assert_equals(e, event);
}));
self.dispatchEvent(event);
assert_true(seen);
}, "There's no self.event (that's why we call it window.event) in workers");
done();

View File

@ -0,0 +1,33 @@
<!DOCTYPE html>
<link rel="author" href="mailto:masonf@chromium.org">
<link rel="help" href="https://crbug.com/747207">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-actions.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
<script>
function handleDown(node) {
var d2 = new Document();
d2.appendChild(node);
}
</script>
<!-- No crash should occur if a node is moved during mousedown. -->
<div id='click' onmousedown='handleDown(this)'>Click me</div>
<script>
const target = document.getElementById('click');
async_test(t => {
let actions = new test_driver.Actions()
.pointerMove(0, 0, {origin: target})
.pointerDown()
.pointerUp()
.send()
.then(t.step_func_done(() => {
assert_equals(null,document.getElementById('click'));
}))
.catch(e => t.step_func(() => assert_unreached('Error')));
},'Moving a node during mousedown should not crash');
</script>

View File

@ -0,0 +1,15 @@
<!DOCTYPE html>
<link rel="author" title="Robert Flack" href="mailto:flackr@chromium.org">
<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1209098">
<!-- No crash should occur if a keypress is dispatched to a constructed document. -->
<script>
var newDoc = document.implementation.createDocument( "", null);
var testNode = newDoc.createElement('div');
newDoc.append(testNode);
var syntheticEvent = document.createEvent('KeyboardEvents');
syntheticEvent.initKeyboardEvent("keypress");
testNode.dispatchEvent(syntheticEvent)
</script>

View File

@ -0,0 +1,10 @@
test(t => {
const input = document.body.appendChild(document.createElement('input'));
input.type = "radio";
t.add_cleanup(() => input.remove());
const clickEvent = new MouseEvent('click', { button: 0, which: 1 });
input.addEventListener('change', t.step_func(() => {
assert_equals(clickEvent.eventPhase, Event.NONE);
}));
input.dispatchEvent(clickEvent);
}, "Use NONE phase during legacy-pre-activation behavior");

View File

@ -0,0 +1,26 @@
<!DOCTYPE html>
<html>
<title>Script created MouseEvent properly retargets and adjusts offsetX</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<style>
body {
margin: 8px;
padding: 0;
}
</style>
<div id="target">Hello</div>
<script>
async_test(t => {
target.addEventListener('click', ev => {
t.step(() => assert_equals(ev.offsetX, 42));
t.done();
});
const ev = new MouseEvent('click', { clientX: 50 });
target.dispatchEvent(ev);
}, "offsetX is correctly adjusted");
</script>

View File

@ -0,0 +1,80 @@
<!doctype html>
<html>
<head>
<meta chareset="utf-8">
<title>Clicking editable content in link shouldn't cause redundant focus related events</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-actions.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
</head>
<body>
<a href="#"><span contenteditable>Hello</span></a>
<a href="#" contenteditable><span>Hello</span></a>
<script>
function promiseTicks() {
return new Promise(resolve => {
requestAnimationFrame(() => {
requestAnimationFrame(resolve);
});
});
}
async function clickElementAndCollectFocusEvents(x, y, options) {
await promiseTicks();
let events = [];
for (const eventType of ["focus", "blur", "focusin", "focusout"]) {
document.addEventListener(eventType, event => {
events.push(`type: ${event.type}, target: ${event.target.nodeName}`);
}, {capture: true});
}
const waitForClickEvent = new Promise(resolve => {
addEventListener("click", resolve, {capture: true, once: true});
});
await new test_driver
.Actions()
.pointerMove(x, y, options)
.pointerDown()
.pointerUp()
.send();
await waitForClickEvent;
await promiseTicks();
return events;
}
promise_test(async t => {
document.activeElement?.blur();
const editingHost = document.querySelector("span[contenteditable]");
editingHost.blur();
const focusEvents =
await clickElementAndCollectFocusEvents(5, 5, {origin: editingHost});
assert_array_equals(
focusEvents,
[
"type: focus, target: SPAN",
"type: focusin, target: SPAN",
],
"Click event shouldn't cause redundant focus events");
}, "Click editable element in link");
promise_test(async t => {
document.activeElement?.blur();
const editingHost = document.querySelector("a[contenteditable]");
editingHost.blur();
const focusEvents =
await clickElementAndCollectFocusEvents(5, 5, {origin: editingHost});
assert_array_equals(
focusEvents,
[
"type: focus, target: A",
"type: focusin, target: A",
],
"Click event shouldn't cause redundant focus events");
}, "Click editable link");
</script>
</body>
</html>

View File

@ -0,0 +1,19 @@
<!DOCTYPE html>
<title>non-passive mousewheel event listener on body</title>
<link rel="help" href="https://w3c.github.io/uievents/#cancelability-of-wheel-events">
<link rel="help" href="https://github.com/w3c/uievents/issues/331">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-actions.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
<script src="resources/scrolling.js"></script>
<div class=remove-on-cleanup style="height: 200vh"></div>
<script>
document.body.onload = () => runTest({
target: document.body,
eventName: 'mousewheel',
passive: false,
expectCancelable: true,
});
</script>

View File

@ -0,0 +1,35 @@
<!DOCTYPE html>
<title>non-passive mousewheel event listener on div</title>
<link rel="help" href="https://w3c.github.io/uievents/#cancelability-of-wheel-events">
<link rel="help" href="https://github.com/w3c/uievents/issues/331">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-actions.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
<script src="resources/scrolling.js"></script>
<style>
html, body {
overflow: hidden;
margin: 0;
}
#div {
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
overflow: scroll;
}
</style>
<div class=remove-on-cleanup id=div>
<div style="height: 200vh"></div>
</div>
<script>
document.body.onload = () => runTest({
target: document.getElementById('div'),
eventName: 'mousewheel',
passive: false,
expectCancelable: true,
});
</script>

View File

@ -0,0 +1,19 @@
<!DOCTYPE html>
<title>non-passive mousewheel event listener on document</title>
<link rel="help" href="https://w3c.github.io/uievents/#cancelability-of-wheel-events">
<link rel="help" href="https://github.com/w3c/uievents/issues/331">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-actions.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
<script src="resources/scrolling.js"></script>
<div class=remove-on-cleanup style="height: 200vh"></div>
<script>
document.body.onload = () => runTest({
target: document,
eventName: 'mousewheel',
passive: false,
expectCancelable: true,
});
</script>

View File

@ -0,0 +1,19 @@
<!DOCTYPE html>
<title>non-passive mousewheel event listener on root</title>
<link rel="help" href="https://w3c.github.io/uievents/#cancelability-of-wheel-events">
<link rel="help" href="https://github.com/w3c/uievents/issues/331">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-actions.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
<script src="resources/scrolling.js"></script>
<div class=remove-on-cleanup style="height: 200vh"></div>
<script>
document.body.onload = () => runTest({
target: document.documentElement,
eventName: 'mousewheel',
passive: false,
expectCancelable: true,
});
</script>

View File

@ -0,0 +1,19 @@
<!DOCTYPE html>
<title>non-passive mousewheel event listener on window</title>
<link rel="help" href="https://w3c.github.io/uievents/#cancelability-of-wheel-events">
<link rel="help" href="https://github.com/w3c/uievents/issues/331">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-actions.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
<script src="resources/scrolling.js"></script>
<div class=remove-on-cleanup style="height: 200vh"></div>
<script>
document.body.onload = () => runTest({
target: window,
eventName: 'mousewheel',
passive: false,
expectCancelable: true,
});
</script>

View File

@ -0,0 +1,25 @@
<!DOCTYPE html>
<title>non-passive touchmove event listener on body</title>
<link rel="help" href="https://w3c.github.io/touch-events/#cancelability">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-actions.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
<script src="resources/wait-for.js"></script>
<script src="resources/touching.js"></script>
<style>
#touchDiv {
width: 100px;
height: 100px;
}
</style>
<div id="touchDiv"></div>
<script>
document.body.onload = () => runTest({
target: document.body,
eventName: 'touchmove',
passive: false,
expectCancelable: true,
});
</script>

View File

@ -0,0 +1,25 @@
<!DOCTYPE html>
<title>non-passive touchmove event listener on div</title>
<link rel="help" href="https://w3c.github.io/touch-events/#cancelability">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-actions.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
<script src="resources/wait-for.js"></script>
<script src="resources/touching.js"></script>
<style>
#touchDiv {
width: 100px;
height: 100px;
}
</style>
<div id="touchDiv"></div>
<script>
document.body.onload = () => runTest({
target: document.getElementById('touchDiv'),
eventName: 'touchmove',
passive: false,
expectCancelable: true,
});
</script>

View File

@ -0,0 +1,25 @@
<!DOCTYPE html>
<title>non-passive touchmove event listener on document</title>
<link rel="help" href="https://w3c.github.io/touch-events/#cancelability">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-actions.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
<script src="resources/wait-for.js"></script>
<script src="resources/touching.js"></script>
<style>
#touchDiv {
width: 100px;
height: 100px;
}
</style>
<div id="touchDiv"></div>
<script>
document.body.onload = () => runTest({
target: document,
eventName: 'touchmove',
passive: false,
expectCancelable: true,
});
</script>

View File

@ -0,0 +1,25 @@
<!DOCTYPE html>
<title>non-passive touchmove event listener on root</title>
<link rel="help" href="https://w3c.github.io/touch-events/#cancelability">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-actions.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
<script src="resources/wait-for.js"></script>
<script src="resources/touching.js"></script>
<style>
#touchDiv {
width: 100px;
height: 100px;
}
</style>
<div id="touchDiv"></div>
<script>
document.body.onload = () => runTest({
target: document.documentElement,
eventName: 'touchmove',
passive: false,
expectCancelable: true,
});
</script>

View File

@ -0,0 +1,25 @@
<!DOCTYPE html>
<link rel="help" href="https://w3c.github.io/touch-events/#cancelability">
<link rel="help" href="https://github.com/WICG/interventions/issues/35">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-actions.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
<script src="resources/wait-for.js"></script>
<script src="resources/touching.js"></script>
<style>
#touchDiv {
width: 100px;
height: 100px;
}
</style>
<div id="touchDiv"></div>
<script>
document.body.onload = () => runTest({
target: window,
eventName: 'touchstart',
passive: false,
expectCancelable: true,
});
</script>

View File

@ -0,0 +1,25 @@
<!DOCTYPE html>
<title>non-passive touchstart event listener on body</title>
<link rel="help" href="https://w3c.github.io/touch-events/#cancelability">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-actions.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
<script src="resources/wait-for.js"></script>
<script src="resources/touching.js"></script>
<style>
#touchDiv {
width: 100px;
height: 100px;
}
</style>
<div id="touchDiv"></div>
<script>
document.body.onload = () => runTest({
target: document.body,
eventName: 'touchstart',
passive: false,
expectCancelable: true,
});
</script>

View File

@ -0,0 +1,25 @@
<!DOCTYPE html>
<title>non-passive touchstart event listener on div</title>
<link rel="help" href="https://w3c.github.io/touch-events/#cancelability">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-actions.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
<script src="resources/wait-for.js"></script>
<script src="resources/touching.js"></script>
<style>
#touchDiv {
width: 100px;
height: 100px;
}
</style>
<div id="touchDiv"></div>
<script>
document.body.onload = () => runTest({
target: document.getElementById('touchDiv'),
eventName: 'touchstart',
passive: false,
expectCancelable: true,
});
</script>

View File

@ -0,0 +1,25 @@
<!DOCTYPE html>
<title>non-passive touchstart event listener on document</title>
<link rel="help" href="https://w3c.github.io/touch-events/#cancelability">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-actions.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
<script src="resources/wait-for.js"></script>
<script src="resources/touching.js"></script>
<style>
#touchDiv {
width: 100px;
height: 100px;
}
</style>
<div id="touchDiv"></div>
<script>
document.body.onload = () => runTest({
target: document,
eventName: 'touchstart',
passive: false,
expectCancelable: true,
});
</script>

View File

@ -0,0 +1,25 @@
<!DOCTYPE html>
<title>non-passive touchstart event listener on root</title>
<link rel="help" href="https://w3c.github.io/touch-events/#cancelability">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-actions.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
<script src="resources/wait-for.js"></script>
<script src="resources/touching.js"></script>
<style>
#touchDiv {
width: 100px;
height: 100px;
}
</style>
<div id="touchDiv"></div>
<script>
document.body.onload = () => runTest({
target: document.documentElement,
eventName: 'touchstart',
passive: false,
expectCancelable: true,
});
</script>

View File

@ -0,0 +1,25 @@
<!DOCTYPE html>
<title>non-passive touchstart event listener on window</title>
<link rel="help" href="https://w3c.github.io/touch-events/#cancelability">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-actions.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
<script src="resources/wait-for.js"></script>
<script src="resources/touching.js"></script>
<style>
#touchDiv {
width: 100px;
height: 100px;
}
</style>
<div id="touchDiv"></div>
<script>
document.body.onload = () => runTest({
target: window,
eventName: 'touchstart',
passive: false,
expectCancelable: true,
});
</script>

View File

@ -0,0 +1,18 @@
<!DOCTYPE html>
<title>non-passive wheel event listener on body</title>
<link rel="help" href="https://w3c.github.io/uievents/#cancelability-of-wheel-events">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-actions.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
<script src="resources/scrolling.js"></script>
<div class=remove-on-cleanup style="height: 200vh"></div>
<script>
document.body.onload = () => runTest({
target: document.body,
eventName: 'wheel',
passive: false,
expectCancelable: true,
});
</script>

View File

@ -0,0 +1,34 @@
<!DOCTYPE html>
<title>non-passive wheel event listener on div</title>
<link rel="help" href="https://w3c.github.io/uievents/#cancelability-of-wheel-events">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-actions.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
<script src="resources/scrolling.js"></script>
<style>
html, body {
overflow: hidden;
margin: 0;
}
#div {
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
overflow: scroll;
}
</style>
<div class=remove-on-cleanup id=div>
<div style="height: 200vh"></div>
</div>
<script>
document.body.onload = () => runTest({
target: document.getElementById('div'),
eventName: 'wheel',
passive: false,
expectCancelable: true,
});
</script>

View File

@ -0,0 +1,18 @@
<!DOCTYPE html>
<title>non-passive wheel event listener on document</title>
<link rel="help" href="https://w3c.github.io/uievents/#cancelability-of-wheel-events">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-actions.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
<script src="resources/scrolling.js"></script>
<div class=remove-on-cleanup style="height: 200vh"></div>
<script>
document.body.onload = () => runTest({
target: document,
eventName: 'wheel',
passive: false,
expectCancelable: true,
});
</script>

View File

@ -0,0 +1,18 @@
<!DOCTYPE html>
<title>non-passive wheel event listener on root</title>
<link rel="help" href="https://w3c.github.io/uievents/#cancelability-of-wheel-events">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-actions.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
<script src="resources/scrolling.js"></script>
<div class=remove-on-cleanup style="height: 200vh"></div>
<script>
document.body.onload = () => runTest({
target: document.documentElement,
eventName: 'wheel',
passive: false,
expectCancelable: true,
});
</script>

View File

@ -0,0 +1,18 @@
<!DOCTYPE html>
<title>non-passive wheel event listener on window</title>
<link rel="help" href="https://w3c.github.io/uievents/#cancelability-of-wheel-events">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-actions.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
<script src="resources/scrolling.js"></script>
<div class=remove-on-cleanup style="height: 200vh"></div>
<script>
document.body.onload = () => runTest({
target: window,
eventName: 'wheel',
passive: false,
expectCancelable: true,
});
</script>

View File

@ -0,0 +1,19 @@
<!DOCTYPE html>
<title>passive mousewheel event listener on body</title>
<link rel="help" href="https://w3c.github.io/uievents/#cancelability-of-wheel-events">
<link rel="help" href="https://github.com/w3c/uievents/issues/331">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-actions.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
<script src="resources/scrolling.js"></script>
<div class=remove-on-cleanup style="height: 200vh"></div>
<script>
document.body.onload = () => runTest({
target: document.body,
eventName: 'mousewheel',
passive: true,
expectCancelable: false,
});
</script>

Some files were not shown because too many files have changed in this diff Show More