Skip to content

Commit 62f2147

Browse files
KhafraDevmarco-ippolito
authored andcommitted
test: update DOM events web platform tests
PR-URL: #54642 Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Mattias Buelens <mattias@buelens.com> Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com> Reviewed-By: Ethan Arrowood <ethan@arrowood.dev> Reviewed-By: Chemi Atlow <chemi@atlow.co.il> Reviewed-By: James M Snell <jasnell@gmail.com>
1 parent 453df77 commit 62f2147

39 files changed

Lines changed: 2693 additions & 565 deletions

File tree

‎test/fixtures/wpt/README.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ Last update:
1313
- common: https://github.com/web-platform-tests/wpt/tree/dbd648158d/common
1414
- console: https://github.com/web-platform-tests/wpt/tree/767ae35464/console
1515
- dom/abort: https://github.com/web-platform-tests/wpt/tree/d1f1ecbd52/dom/abort
16-
- dom/events: https://github.com/web-platform-tests/wpt/tree/ab8999891c/dom/events
16+
- dom/events: https://github.com/web-platform-tests/wpt/tree/0a811c5161/dom/events
1717
- encoding: https://github.com/web-platform-tests/wpt/tree/5aa50dd415/encoding
1818
- fetch/data-urls/resources: https://github.com/web-platform-tests/wpt/tree/7c79d998ff/fetch/data-urls/resources
1919
- FileAPI: https://github.com/web-platform-tests/wpt/tree/cceaf3628d/FileAPI

‎test/fixtures/wpt/dom/events/Event-dispatch-click.html‎

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,22 @@
8787
child.dispatchEvent(newMouseEvent("click",{bubbles:true}))
8888
},"pick the first with activation behavior <a href>")
8989

90+
async_test(function(t){
91+
varinput=document.createElement("input")
92+
input.type="radio"
93+
dump.appendChild(input)
94+
input.onclick=t.step_func(function(){
95+
assert_false(input.checked,"input pre-click must not be triggered")
96+
})
97+
varchild=input.appendChild(document.createElement("input"))
98+
child.type="radio"
99+
child.onclick=t.step_func(function(){
100+
assert_true(child.checked,"child pre-click must be triggered")
101+
})
102+
child.dispatchEvent(newMouseEvent("click",{bubbles:true}))
103+
t.done()
104+
},"pick the first with activation behavior <input type=radio>")
105+
90106
async_test(function(t){
91107
varinput=document.createElement("input")
92108
input.type="checkbox"
@@ -173,6 +189,46 @@
173189
t.done()
174190
},"disabled checkbox still has activation behavior, part 2")
175191

192+
async_test(function(t){
193+
varstate="start"
194+
195+
varform=document.createElement("form")
196+
form.onsubmit=t.step_func(()=>{
197+
if(state=="start"||state=="radio"){
198+
state="failure"
199+
}elseif(state=="form"){
200+
state="done"
201+
}
202+
returnfalse
203+
})
204+
dump.appendChild(form)
205+
varbutton=form.appendChild(document.createElement("button"))
206+
button.type="submit"
207+
varradio=button.appendChild(document.createElement("input"))
208+
radio.type="radio"
209+
radio.onclick=t.step_func(()=>{
210+
if(state=="start"){
211+
assert_unreached()
212+
}elseif(state=="radio"){
213+
assert_true(radio.checked)
214+
}
215+
})
216+
radio.disabled=true
217+
radio.click()
218+
assert_equals(state,"start")
219+
220+
state="radio"
221+
radio.disabled=false
222+
radio.click()
223+
assert_equals(state,"radio")
224+
225+
state="form"
226+
button.click()
227+
assert_equals(state,"done")
228+
229+
t.done()
230+
},"disabled radio still has activation behavior")
231+
176232
async_test(function(t){
177233
varinput=document.createElement("input")
178234
input.type="checkbox"

‎test/fixtures/wpt/dom/events/Event-dispatch-on-disabled-elements.html‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
<body>
2020
<script>
2121
// HTML elements that can be disabled
22-
constformElements=["button","fieldset","input","select","textarea"];
22+
constformElements=["button","input","select","textarea"];
2323

2424
test(()=>{
2525
for(constlocalNameofformElements){
Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
<!DOCTYPE html>
2+
<metacharset=utf-8>
3+
<title> Only one activation behavior is executed during dispatch</title>
4+
<linkrel="author" title="Vincent Hilla" href="mailto:vhilla@mozilla.com">
5+
<linkrel="help" href="https://dom.spec.whatwg.org/#eventtarget-activation-behavior">
6+
<linkrel="help" href="https://dom.spec.whatwg.org/#concept-event-dispatch">
7+
<scriptsrc="/resources/testharness.js"></script>
8+
<scriptsrc="/resources/testharnessreport.js"></script>
9+
<divid=log></div>
10+
11+
<divid=test_container></div>
12+
13+
<!--
14+
Three classes:
15+
click
16+
Element to be clicked to cause activation behavior
17+
activates
18+
Element that registers the activation behavior
19+
container
20+
Element in which other elements with activation behavior are placed.
21+
We test that those won't be activated too.
22+
-->
23+
<template>
24+
<!--input, change event bubble, so have to check if checked is true-->
25+
<inputclass="click activates container" type="checkbox" oninput="this.checked ? activated(this) : null">
26+
<inputclass="click activates container" type="radio" oninput="this.checked ? activated(this) : null">
27+
<formonsubmit="activated(this); return false" class="activates">
28+
<inputclass="click container" type="submit">
29+
</form>
30+
<formonsubmit="activated(this); return false" class="activates">
31+
<inputclass="click container" type="image">
32+
</form>
33+
<formonreset="activated(this)" class="activates">
34+
<inputclass="click container" type="reset">
35+
</form>
36+
<formonsubmit="activated(this); return false" class="activates">
37+
<buttonclass="click container" type="submit"></button>
38+
</form>
39+
<formonreset="activated(this)" class="activates">
40+
<buttonclass="click container" type="reset"></button>
41+
</form>
42+
<ahref="#link" class="click container activates"></a>
43+
<areahref="#link" class="click container activates">
44+
<detailsontoggle="activated(this)" class="activates">
45+
<summaryclass="click container"></summary>
46+
</details>
47+
<label>
48+
<inputtype=checkboxonclick="this.checked ? activated(this) : null" class="activates">
49+
<spanclass="click container">label</span>
50+
</label>
51+
<!--activation behavior of label for event targeted at interactive content descendant is to do nothing-->
52+
<labelclass="container">
53+
<buttonclass="click" type="button"></button>
54+
</label>
55+
</template>
56+
57+
<script>
58+
letactivations=[];
59+
functionactivated(e){
60+
activations.push(e);
61+
}
62+
63+
functiongetActivations(testidx){
64+
returnactivations.filter(a=>
65+
(a.endsWith&&a.endsWith("test"+testidx+"_link"))
66+
||(a.classList&&a.classList.contains("test"+testidx))
67+
);
68+
}
69+
70+
// for a and area elements
71+
window.onhashchange=function(e){
72+
if(e.newURL.endsWith("link")){
73+
activated(e.newURL);
74+
}
75+
window.location.hash="";
76+
};
77+
78+
functiongetElementsByClassNameInclusive(e,clsname){
79+
letls=Array.from(e.getElementsByClassName(clsname));
80+
if(e.classList.contains(clsname))ls.push(e);
81+
returnls;
82+
}
83+
84+
functiongetClickTarget(e){
85+
returngetElementsByClassNameInclusive(e,"click")[0];
86+
}
87+
88+
functiongetContainer(e){
89+
returngetElementsByClassNameInclusive(e,"container")[0];
90+
}
91+
92+
functiongetExpectedActivations(e){
93+
letls=getElementsByClassNameInclusive(e,"activates");
94+
95+
// special case, for a and area the window registers the activation
96+
// have to use string, as testrunner cannot stringify the window object
97+
ls=ls.map(e=>e.tagName==="A"||e.tagName==="AREA" ? e.href : e);
98+
99+
returnls;
100+
}
101+
102+
functiontoString(e){
103+
constchildren=Array.from(e.children);
104+
constchildstr=(children.map(toString)).join("");
105+
consttag=e.tagName;
106+
consttypestr=e.type ? " type="+e.type : "";
107+
return`<${tag}${typestr}>${childstr}</${tag}>`;
108+
}
109+
110+
// generate O(n^2) test combinations
111+
consttemplate=document.querySelector("template");
112+
constelements=Array.from(template.content.children);
113+
consttests=[]
114+
for(consttargetofelements){
115+
for(constparentofelements){
116+
if(target===parent)continue;
117+
tests.push([target.cloneNode(true),parent.cloneNode(true)])
118+
}
119+
}
120+
121+
consttest_container=document.getElementById("test_container");
122+
123+
/**
124+
* Test that if two elements in an event target chain have activation behavior,
125+
* only one of them will be activated.
126+
*
127+
* Each child of <template> represents one case of activation behavior.
128+
* The behavior should be triggered by clicking the element of class click
129+
* and will manifest as a call to activated().
130+
*
131+
* For each [target, parent] in tests, we make target a descendant of parent
132+
* and test that only target gets activated when dispatching a click.
133+
*/
134+
for(leti=0;i<tests.length;i++){
135+
let[target,parent]=tests[i];
136+
async_test(function(t){
137+
lettest=document.createElement("div");
138+
test_container.appendChild(test);
139+
test.appendChild(parent);
140+
getContainer(parent).appendChild(target);
141+
142+
// for later filtering out the activations belonging to this test
143+
for(leteoftest.getElementsByClassName("activates")){
144+
e.classList.add("test"+i);
145+
}
146+
for(leteoftest.querySelectorAll("a, area")){
147+
e.href="#test"+i+"_link";
148+
}
149+
150+
getClickTarget(target).click();
151+
152+
// Need to spin event loop twice, as some clicks might dispatch another task
153+
t.step_timeout(()=>{
154+
t.step_timeout(t.step_func_done(()=>{
155+
assert_array_equals(getActivations(i),getExpectedActivations(target));
156+
}),0);
157+
},0);
158+
159+
t.add_cleanup(function(){
160+
test_container.removeChild(test);
161+
});
162+
},`When clicking child ${toString(target)} of parent ${toString(parent)}, only child should be activated.`);
163+
}
164+
</script>
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
<!DOCTYPE html>
2+
<scriptsrc="/resources/testharness.js"></script>
3+
<scriptsrc="/resources/testharnessreport.js"></script>
4+
<body>
5+
<script>
6+
functioncreateIframe(t,srcdoc=''){
7+
letiframe=document.createElement('iframe');
8+
iframe.srcdoc=srcdoc;
9+
t.add_cleanup(()=>iframe.remove());
10+
returnnewPromise((resolve,reject)=>{
11+
iframe.addEventListener('load',()=>resolve(iframe.contentWindow));
12+
document.body.appendChild(iframe);
13+
});
14+
}
15+
16+
// Returns a promise which will resolve with the next error event fired at any
17+
// of `windows`, after the invocation of this function. Once one does, this
18+
// function removes its listeners and produces that error event so that it can
19+
// be examined (most notably for which global proxy it was targeted at).
20+
asyncfunctionnextErrorEvent(windows){
21+
letlistener;
22+
letp=newPromise((resolve,reject)=>{
23+
listener=(event)=>{resolve(event);event.preventDefault();};
24+
});
25+
for(letwofwindows){
26+
w.addEventListener('error',listener);
27+
}
28+
try{
29+
returnawaitp;
30+
}finally{
31+
for(letwofwindows){
32+
w.removeEventListener('error',listener);
33+
}
34+
}
35+
}
36+
37+
promise_test(asynct=>{
38+
letw=awaitcreateIframe(t,`<script>function listener() { throw new Error(); }<`+`/script>`);
39+
letw2=awaitcreateIframe(t);
40+
41+
lettarget=neww2.EventTarget();
42+
target.addEventListener('party',w.listener);
43+
letnextErrorPromise=nextErrorEvent([self,w,w2]);
44+
target.dispatchEvent(newEvent('party'));
45+
leterrorEvent=awaitnextErrorPromise;
46+
if(errorEvent.error){
47+
assert_true(errorEvent.errorinstanceofw.Error,'error should be an instance created inside the listener function');
48+
}
49+
assert_equals(errorEvent.target,w,`error event should target listener's global but instead targets ${event.currentTarget===w2 ? 'target\'s global' : 'test harness global'}`);
50+
},'exception thrown in event listener function should result in error event on listener\'s global');
51+
52+
promise_test(asynct=>{
53+
letw=awaitcreateIframe(t,`<script>listener = {};<`+`/script>`);
54+
letw2=awaitcreateIframe(t,`<script>handleEvent = () => { throw new Error; };<`+`/script>`);
55+
letw3=awaitcreateIframe(t);
56+
w.listener.handleEvent=w2.handleEvent;
57+
58+
lettarget=neww3.EventTarget();
59+
target.addEventListener('party',w.listener);
60+
letnextErrorPromise=nextErrorEvent([self,w,w2,w3]);
61+
target.dispatchEvent(newEvent('party'));
62+
leterrorEvent=awaitnextErrorPromise;
63+
if(errorEvent.error){
64+
assert_true(errorEvent.errorinstanceofw2.Error,'error should be an instance created inside the listener function');
65+
}
66+
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'}`);
67+
},'exception thrown in event listener interface object should result in error event on listener\'s global');
68+
</script>
69+
</body>

‎test/fixtures/wpt/dom/events/EventTarget-constructible.any.js‎

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,23 @@ test(() => {
2323
assert_equals(callCount,2);
2424
},"A constructed EventTarget can be used as expected");
2525

26+
test(()=>{
27+
consttarget=newEventTarget();
28+
constevent=newEvent("foo");
29+
30+
functionlistener(e){
31+
assert_equals(e,event);
32+
assert_equals(e.target,target);
33+
assert_equals(e.currentTarget,target);
34+
assert_array_equals(e.composedPath(),[target]);
35+
}
36+
target.addEventListener("foo",listener,{once: true});
37+
target.dispatchEvent(event);
38+
assert_equals(event.target,target);
39+
assert_equals(event.currentTarget,null);
40+
assert_array_equals(event.composedPath(),[]);
41+
},"A constructed EventTarget implements dispatch correctly");
42+
2643
test(()=>{
2744
classNicerEventTargetextendsEventTarget{
2845
on(...args){

‎test/fixtures/wpt/dom/events/event-global.html‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,4 +114,14 @@
114114

115115
target.dispatchEvent(newEvent("click"));
116116
},"window.event is set to the current event, which is the event passed to dispatch");
117+
118+
async_test(t=>{
119+
lettarget=newXMLHttpRequest();
120+
121+
target.onload=t.step_func_done(e=>{
122+
assert_equals(e,window.event);
123+
});
124+
125+
target.dispatchEvent(newEvent("load"));
126+
},"window.event is set to the current event, which is the event passed to dispatch (2)");
117127
</script>
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<!DOCTYPE html>
2+
<linkrel="help" href="https://crbug.com/341104769">
3+
<scriptsrc="/resources/testharness.js"></script>
4+
<scriptsrc="/resources/testharnessreport.js"></script>
5+
<scriptsrc="/resources/testdriver.js"></script>
6+
<scriptsrc="/resources/testdriver-actions.js"></script>
7+
<scriptsrc="/resources/testdriver-vendor.js"></script>
8+
9+
<template>
10+
<p>TEST</p>
11+
</template>
12+
13+
<body>
14+
<script>
15+
constclone=document.querySelector("template").content.cloneNode(true);
16+
constp=clone.querySelector("p");
17+
18+
letgotEvent=false;
19+
p.addEventListener("pointerup",()=>{
20+
gotEvent=true;
21+
});
22+
23+
document.body.append(clone);
24+
25+
promise_test(async()=>{
26+
awaittest_driver.click(document.querySelector("p"));
27+
assert_true(gotEvent);
28+
},"Moving a node to new document should move the registered event listeners together");
29+
</script>

0 commit comments

Comments
 (0)