Source code
Revision control
Copy as Markdown
Other Tools
Test Info: Warnings
- This test has a WPT meta file that expects 2 subtest issues.
- This WPT test may be referenced by the following Test IDs:
- /pointerevents/pointerevent_pointercapture_in_frame.html?mouse - WPT Dashboard Interop Dashboard
- /pointerevents/pointerevent_pointercapture_in_frame.html?pen - WPT Dashboard Interop Dashboard
- /pointerevents/pointerevent_pointercapture_in_frame.html?touch - WPT Dashboard Interop Dashboard
<meta name="variant" content="?mouse">
<meta name="variant" content="?touch">
<meta name="variant" content="?pen">
<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>
<script src="/resources/testdriver-actions.js"></script>
<script type="text/javascript" src="pointerevent_support.js"></script>
<style>
iframe {
width: 300px;
height: 300px;
top: 100px;
left: 100px;
border: 0;
position: absolute;
background: green;
}
#outerFrame {
width: 500px;
height: 500px;
background: blue;
}
body {
touch-action:none;
}
</style>
<body id="outerFrame body" onload="run()">
<div id='outerFrame'>
<iframe id='innerFrameElement' src="resources/pointerevent_pointercapture-iframe.html"></iframe>
</div>
</body>
<script>
var receivedEventList = [];
// |start_logging| is set to true in the pointerdown event handler, and as such
// also tracks if pointerdown happened already in the test.
var start_logging = false;
var first_pointermove_happened = false;
// Add a timeout promise when waiting for lostpointercapture and pointerup.
// We add this to make it easy to know which event wasn't fired on the right
// element.
var eventTimeout = ()=>(()=>new Promise((resolve, reject)=>{
const msToWait = 4000;
let start;
function wait(timestamp){
if(start === undefined)
start = timestamp;
if(timestamp - start < msToWait)
requestAnimationFrame(wait);
else
resolve();
}
requestAnimationFrame(wait);
}));
function handleEvent(event) {
if (event.type == 'pointerdown') {
start_logging = true;
const target = document.captureTargetOverride || event.target;
target.setPointerCapture(event.pointerId);
}
// Only log the first pointermove event after pointerdown. We need to account
// for coalesced pointermove events and for the pointermove events that
// happen after lostpointercapture.
if (start_logging && (event.type !== "pointermove" || !first_pointermove_happened))
receivedEventList.push(event.target.id + ' received ' + event.type);
if (event.type == "pointermove"){
if (document.releasePointerCaptureOnFirstMove && event.target.hasPointerCapture(event.pointerId))
event.target.releasePointerCapture(event.pointerId);
if(start_logging)
first_pointermove_happened = true;
}
};
document.testEventList = ['pointerup', 'pointerdown', 'pointermove', 'gotpointercapture', 'lostpointercapture'];
document.testEventList.forEach(function(eventName) {
document.getElementById('outerFrame').addEventListener(eventName, handleEvent);
});
function Reset() {
document.captureTargetOverride = null;
document.releasePointerCaptureOnFirstMove = false;
receivedEventList = [];
start_logging = false;
first_pointermove_happened = false;
}
function run() {
Reset();
var pointerType = location.search.substring(1);
promise_test (async(t) => {
t.add_cleanup(Reset);
expectedEventList = ["innerFrame received pointerdown",
"innerFrame received gotpointercapture",
"innerFrame received pointermove",
"innerFrame received pointerup",
"innerFrame received lostpointercapture"];
var pointerId = pointerType + "Pointer1";
var innerFrame = document.getElementById('innerFrameElement');
var innerFrameDocument = innerFrame.contentDocument;
// We are interested in tracking events only after pointerdown
var pointerdown_happened = new Promise((resolve, reject)=>{innerFrameDocument.addEventListener("pointerdown",resolve);});
var watcher_promise = pointerdown_happened.then(()=>{
var watch_inner_frame = new EventWatcher(t, innerFrameDocument, ["lostpointercapture"], eventTimeout());
return watch_inner_frame.wait_for(["lostpointercapture"]);
});
await new test_driver.Actions()
.addPointer(pointerId, pointerType)
.pointerMove(200, 200)
.pointerDown()
.pointerMove(150, 150)
.pointerMove(50, 50)
.pointerUp()
.pointerMove(75, 75)
.send();
// Wait for lostpointercapture to fire.
await watcher_promise;
assert_array_equals(receivedEventList, expectedEventList, "Received events: " + receivedEventList);
}, "Test " + pointerType + "pointer capture in same-origin frame: Pointer down at inner frame and set pointer capture.");
promise_test (async(t) => {
t.add_cleanup(Reset);
document.captureTargetOverride = document.getElementById('outerFrame');
expectedEventList = ["innerFrame received pointerdown",
"innerFrame received pointermove",
"innerFrameDocument received pointerup"];
var pointerId = pointerType + "Pointer1";
var innerFrame = document.getElementById('innerFrameElement');
var innerFrameDocument = innerFrame.contentDocument;
// We are interested in tracking events only after pointerdown
var pointerdown_happened = new Promise((resolve, reject)=>{innerFrameDocument.addEventListener("pointerdown",resolve);});
var watcher_promise = pointerdown_happened.then(()=>{
var watch_inner_frame = new EventWatcher(t, innerFrameDocument, ["pointerup"], eventTimeout());
return watch_inner_frame.wait_for(["pointerup"]);
});
await new test_driver.Actions()
.addPointer(pointerId, pointerType)
.pointerMove(200, 200)
.pointerDown()
.pointerMove(150, 150)
.pointerMove(50, 50)
.pointerUp()
.pointerMove(75, 75)
.send();
// Wait for pointerup to fire.
await watcher_promise;
assert_array_equals(receivedEventList, expectedEventList, "Received events: " + receivedEventList);
}, "Test " + pointerType + "pointer capture in same-origin frame: Pointer down at inner frame and set pointer capture to outer frame should not capture.");
promise_test (async(t) => {
t.add_cleanup(Reset);
expectedEventList = ["outerFrame received pointerdown",
"outerFrame received gotpointercapture",
"outerFrame received pointermove",
"outerFrame received pointerup",
"outerFrame received lostpointercapture"];
var pointerId = pointerType + "Pointer1";
// We are interested in tracking events only after pointerdown
var pointerdown_happened = new Promise((resolve, reject)=>{document.getElementById('outerFrame').addEventListener("pointerdown",resolve);});
var watcher_promise = pointerdown_happened.then(()=>{
// For this test we're going to wait for both pointerup and lostpointercapture,
// as pointerup fires on innerFrame on Windows (see crbug.com/1186788)
var watch_outer_frame_for_pointerup_and_lostpointercapture =
new EventWatcher(t, document.getElementById('outerFrame'), ["pointerup", "lostpointercapture"], eventTimeout());
return watch_outer_frame_for_pointerup_and_lostpointercapture.wait_for(["pointerup", "lostpointercapture"]);
});
await new test_driver.Actions()
.addPointer(pointerId, pointerType)
.pointerMove(25, 25)
.pointerDown()
.pointerMove(200, 200)
.pointerUp()
.pointerMove(25, 25)
.send();
// Wait for lostpointercapture to fire.
await watcher_promise;
assert_array_equals(receivedEventList, expectedEventList, "Received events: " + receivedEventList);
}, "Test " + pointerType + "pointer capture in same-origin frame: Pointer down at outer frame body and set pointer capture.");
promise_test (async(t) => {
t.add_cleanup(Reset);
document.captureTargetOverride = document.getElementById('innerFrameElement');
expectedEventList = ["outerFrame received pointerdown",
"outerFrame received pointermove",
"outerFrame received pointerup"];
var pointerId = pointerType + "Pointer1";
// We are interested in tracking events only after pointerdown
var pointerdown_happened = new Promise((resolve, reject)=>{document.getElementById('outerFrame').addEventListener("pointerdown",resolve);});
var watcher_promise = pointerdown_happened.then(()=>{
var watch_outer_frame = new EventWatcher(t, document.getElementById('outerFrame'), ["pointerup"], eventTimeout());
return watch_outer_frame.wait_for("pointerup");
});
await new test_driver.Actions()
.addPointer(pointerId, pointerType)
.pointerMove(25, 25)
.pointerDown()
.pointerMove(200, 200)
.pointerUp()
.pointerMove(25, 25)
.send();
// Wait for lostpointercapture to fire.
await watcher_promise;
assert_array_equals(receivedEventList, expectedEventList, "Received events: " + receivedEventList);
}, "Test " + pointerType + "pointer capture in same-origin frame: Pointer down at outer frame body and set pointer capture in inner frame should not capture.");
promise_test (async(t) => {
t.add_cleanup(Reset);
document.releasePointerCaptureOnFirstMove = true;
// Mouse event has the frame capture, so after pointer capture released, events are
// dispatched to innerFrameDocument.
expectedEventList = ["innerFrame received pointerdown",
"innerFrame received gotpointercapture",
"innerFrame received pointermove",
"innerFrame received lostpointercapture",
(pointerType == "touch" ? "outerFrame": "innerFrameDocument") + " received pointerup",];
var pointerId = pointerType + "Pointer1";
var innerFrame = document.getElementById('innerFrameElement');
var innerFrameDocument = innerFrame.contentDocument;
// We are interested in tracking events only after pointerdown
var pointerdown_happened = new Promise((resolve, reject)=>{innerFrameDocument.addEventListener("pointerdown",resolve);});
var watcher_promise = pointerdown_happened.then(()=>{
if(pointerType === "touch"){
var watch_outer_frame = new EventWatcher(t, document.getElementById('outerFrame'), ["pointerup"], eventTimeout());
return watch_outer_frame.wait_for("pointerup");
}else{
var watch_inner_frame = new EventWatcher(t, innerFrameDocument, ["pointerup"], eventTimeout());
return watch_inner_frame.wait_for("pointerup");
}
});
await new test_driver.Actions()
.addPointer(pointerId, pointerType)
.pointerMove(200, 200)
.pointerDown()
.pointerMove(150, 150)
.pointerMove(50, 50)
.pointerUp()
.pointerMove(150, 150)
.send();
// Wait for pointerup to fire.
await watcher_promise;
assert_array_equals(receivedEventList, expectedEventList, "Received events: " + receivedEventList);
document.releasePointerCaptureOnFirstMove = false;
}, "Test " + pointerType + "pointer capture in same-origin frame: Pointerdown with set capture at inner frame, then release on next pointermove.");
promise_test (async(t) => {
t.add_cleanup(Reset);
document.releasePointerCaptureOnFirstMove = true;
expectedEventList = ["outerFrame received pointerdown",
"outerFrame received gotpointercapture",
"outerFrame received pointermove",
"outerFrame received lostpointercapture",
"innerFrame received pointerup"];
var pointerId = pointerType + "Pointer1";
var innerFrame = document.getElementById('innerFrameElement');
var innerFrameDocument = innerFrame.contentDocument;
// We are interested in tracking events only after pointerdown
var pointerdown_happened = new Promise((resolve, reject)=>{document.getElementById('outerFrame').addEventListener("pointerdown",resolve);});
var watcher_promise = pointerdown_happened.then(()=>{
var watch_inner_frame = new EventWatcher(t, innerFrameDocument, ["pointerup"], eventTimeout());
return watch_inner_frame.wait_for(["pointerup"]);
});
await new test_driver.Actions()
.addPointer(pointerId, pointerType)
.pointerMove(50, 50)
.pointerDown()
.pointerMove(200, 200)
// Pause here to make sure that the previous and following pointer moves
// are not coalesced. If they are coalesced, we will not see the second
// move event which is when the pending lostpointercapture should be fired
// (Since the pointerup event is targeted at a different frame, it won't dispatch
// the pending lostpointercapture event).
.pause(300)
.pointerMove(250, 250)
.pointerUp()
.send();
// Wait for pointerup to fire.
await watcher_promise;
assert_array_equals(receivedEventList, expectedEventList, "Received events: " + receivedEventList);
document.releasePointerCaptureOnFirstMove = false;
}, "Test " + pointerType + "pointer capture in same-origin frame: Pointerdown with set capture at outer frame, then release on next pointermove.");
}
</script>
</body>