Commit d40b0ff5 authored by Andrew Comminos's avatar Andrew Comminos Committed by Commit Bot

Add isInputPending pointer event tests

Adds basic tests for continuous and discrete pointer events being
detected by isInputPending with same-origin and cross-origin frames.
Note that these do not currently work with content_shell (see
crbug.com/893480).

Bug: 910421
Change-Id: I93a0b2f7c47d7444069b157dcc55f9f04856eba0
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2236693Reviewed-by: default avatarStefan Zager <szager@chromium.org>
Commit-Queue: Andrew Comminos <acomminos@fb.com>
Cr-Commit-Position: refs/heads/master@{#802332}
parent 7a9374ff
...@@ -2204,6 +2204,7 @@ crbug.com/893480 external/wpt/infrastructure/testdriver/actions/multiDevice.html ...@@ -2204,6 +2204,7 @@ crbug.com/893480 external/wpt/infrastructure/testdriver/actions/multiDevice.html
crbug.com/893480 external/wpt/pointerevents/pointerevent_touch-action-keyboard.html [ Failure Timeout ] crbug.com/893480 external/wpt/pointerevents/pointerevent_touch-action-keyboard.html [ Failure Timeout ]
crbug.com/893480 external/wpt/infrastructure/testdriver/actions/actionsWithKeyPressed.html [ Failure Timeout ] crbug.com/893480 external/wpt/infrastructure/testdriver/actions/actionsWithKeyPressed.html [ Failure Timeout ]
crbug.com/893480 external/wpt/css/css-scroll-snap/input/keyboard.html [ Failure Timeout ] crbug.com/893480 external/wpt/css/css-scroll-snap/input/keyboard.html [ Failure Timeout ]
crbug.com/893480 external/wpt/is-input-pending/tentative/* [ Failure Timeout ]
# Need to support 'direction: rtl' for scroll snap # Need to support 'direction: rtl' for scroll snap
crbug.com/1012173 external/wpt/css/css-scroll-snap/snap-after-initial-layout/direction-rtl.html [ Failure ] crbug.com/1012173 external/wpt/css/css-scroll-snap/snap-after-initial-layout/direction-rtl.html [ Failure ]
......
- `security/` contains tests intended to ensure that input is not detectable cross-origin.
- `tentative/` contains tests to detect common cases where it may be beneficial to pending input.
- All positive tests are marked as tentative, as the spec permits UAs to omit reporting pending input.
<!DOCTYPE html>
<script src="input-onmessage.js"></script>
// Responds to onmessage events from other frames to check for pending input.
onmessage = async e => {
if (e.data !== 'check-input') return;
const discreteOptions = new IsInputPendingOptions({ includeContinuous: false });
const continuousOptions = new IsInputPendingOptions({ includeContinuous: true });
// Use a reasonable time to wait after dispatching events, since we want to be
// able to test for cases where isInputPending returns false.
const DISPATCH_WAIT_TIME_MS = 200;
// Wait a reasonable amount of time for the event to be enqueued.
const end = performance.now() + DISPATCH_WAIT_TIME_MS;
let hasDiscrete;
let hasContinuous;
do {
hasDiscrete = navigator.scheduling.isInputPending(discreteOptions);
hasContinuous = navigator.scheduling.isInputPending(continuousOptions);
} while (performance.now() < end && !(hasDiscrete && hasContinuous));
e.source.postMessage({
discrete: hasDiscrete,
continuous: hasContinuous,
}, '*');
}
// Dispatches the given sequence of actions and verifies isInputPending state
// after dispatch according to expectations. Returns when all dispatched input
// has been handled.
const pendingActionTest = async (label, target, actionCallback, expectations) => {
promise_test(async () => {
// Give focus to the page first, before running the test.
await new test_driver.Actions()
.pointerMove(0, 0)
.pointerDown()
.pointerUp()
.send();
// Register a handler to fetch the result of isInputPending from the target
// window.
const resultPromise = new Promise(res => {
window.addEventListener('message', function handler(e) {
if (e.data === 'check-input') return;
res(e.data);
window.removeEventListener('message', handler);
});
});
// Signal to the target window to monitor isInputPending.
target.postMessage('check-input', '*');
const actions = actionCallback();
const actionsPromise = actions.send();
const {discrete, continuous} = await resultPromise;
assert_equals(discrete, expectations.discrete, 'detected discrete input');
assert_equals(continuous, expectations.continuous, 'detected continuous input');
await actionsPromise;
}, label);
}
const PendingInputUtils = {
testDetectNoPendingInput(target, actionCallback, label) {
pendingActionTest(label, target, actionCallback, {
discrete: false,
continuous: false,
});
},
testDetectDiscretePendingInput(target, actionCallback, label) {
pendingActionTest(label, target, actionCallback, {
discrete: true,
continuous: true,
});
},
testDetectContinuousPendingInput(target, actionCallback, label) {
pendingActionTest(label, target, actionCallback, {
discrete: false,
continuous: true,
});
},
// Simulates a pointer event at the given coordinates, and tests that the
// given target window cannot access it. Intended for cross-origin compliance
// tests.
testCannotAccessPendingInputAt(target, x, y, label) {
PendingInputUtils.testDetectNoPendingInput(target, () => {
return new test_driver.Actions().pointerMove(x, y).pointerDown().pointerUp();
}, label);
},
}
<!doctype html>
<html>
<head>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-actions.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="../resources/input-onmessage.js"></script>
<script src="../resources/pending-input-utils.js"></script>
<style>
iframe {
clip-path: ellipse(160px 90px);
}
</style>
</head>
<body>
<div class="obscurer"></div>
<iframe src="http://{{hosts[][www1]}}:{{ports[http][0]}}/is-input-pending/resources/blank.html"></iframe>
<p>Ensure that a parent frame cannot detect events on a cross-origin subframe with a complex clip.</p>
<script>
window.addEventListener('load', () => {
PendingInputUtils.testCannotAccessPendingInputAt(window, 160, 90, 'parent cannot detect cross-origin events');
});
</script>
</body>
</html>
<!doctype html>
<html>
<head>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-actions.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="../resources/input-onmessage.js"></script>
<script src="../resources/pending-input-utils.js"></script>
<style>
.obscurer {
position: fixed;
top: 0px;
left: 0px;
width: 320px;
height: 180px;
background-color: rgba(0, 0, 255, 0.25);
clip-path: ellipse(160px 90px);
}
</style>
</head>
<body>
<iframe src="http://{{hosts[][www1]}}:{{ports[http][0]}}/is-input-pending/resources/blank.html"></iframe>
<div class="obscurer"></div>
<p>Ensure that a parent frame cannot detect events on a cross-origin subframe masked by a div with a complex clip.</p>
<script>
window.addEventListener('load', () => {
PendingInputUtils.testCannotAccessPendingInputAt(window, 10, 10, 'parent cannot detect cross-origin events outside of clip');
PendingInputUtils.testCannotAccessPendingInputAt(frames[0], 50, 50, 'subframe cannot detect events inside of clip');
});
</script>
</body>
</html>
<!doctype html>
<html>
<head>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-actions.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="../resources/input-onmessage.js"></script>
<script src="../resources/pending-input-utils.js"></script>
<style>
.obscurer {
position: fixed;
top: 0px;
left: 0px;
width: 160px;
height: 180px;
background-color: rgba(0, 0, 255, 0.25);
}
.obscurer > * {
position: absolute;
left: 160px;
width: 160px;
height: 90px;
pointer-events: none;
background-color: rgba(255, 0, 0, 0.25);
}
</style>
</head>
<body>
<iframe src="http://{{hosts[][www1]}}:{{ports[http][0]}}/is-input-pending/resources/blank.html"></iframe>
<div class="obscurer">
<div></div>
</div>
<p>Ensure that a parent frame cannot detect events on top of a cross-origin subframe masked by a div with a `pointer-events: none` child.</p>
<script>
window.addEventListener('load', () => {
PendingInputUtils.testCannotAccessPendingInputAt(window, 180, 120, 'parent cannot detect cross-origin events in `pointer-events: none` region');
PendingInputUtils.testCannotAccessPendingInputAt(frames[0], 10, 10, 'subframe cannot detect events in `pointer-events: initial` region');
});
</script>
</body>
</html>
<!doctype html>
<html>
<head>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-actions.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="../resources/input-onmessage.js"></script>
<script src="../resources/pending-input-utils.js"></script>
<style>
.obscurer {
position: fixed;
top: 0px;
left: 0px;
width: 320px;
height: 180px;
pointer-events: none;
background-color: rgba(0, 0, 255, 0.25);
}
.obscurer > * {
width: 160px;
height: 180px;
pointer-events: initial;
background-color: rgba(255, 0, 0, 0.25);
}
</style>
</head>
<body>
<div class="obscurer">
<div></div>
</div>
<iframe src="http://{{hosts[][www1]}}:{{ports[http][0]}}/is-input-pending/resources/blank.html"></iframe>
<p>Ensure that a parent frame cannot can events on top of a cross-origin subframe masked by a div with `pointer-events: none` and a `pointer-events: initial` child.</p>
<script>
window.addEventListener('load', () => {
PendingInputUtils.testCannotAccessPendingInputAt(window, 180, 10, 'cannot detect cross-origin events in `pointer-events: none` region');
});
</script>
</body>
</html>
<!doctype html>
<html>
<head>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-actions.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="../resources/input-onmessage.js"></script>
<script src="../resources/pending-input-utils.js"></script>
<style>
.obscurer {
position: fixed;
top: 0px;
left: 0px;
width: 320px;
height: 180px;
pointer-events: none;
background-color: rgba(0, 0, 255, 0.25);
}
</style>
</head>
<body>
<div class="obscurer"></div>
<iframe src="http://{{hosts[][www1]}}:{{ports[http][0]}}/is-input-pending/resources/blank.html"></iframe>
<p>Ensure that a parent frame cannot detect events on a cross-origin subframe masked by a div with `pointer-events: none`.</p>
<script>
window.addEventListener('load', () => {
PendingInputUtils.testCannotAccessPendingInputAt(window, 10, 10, 'parent cannot detect events');
});
</script>
</body>
</html>
<!doctype html>
<html>
<head>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-actions.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="../resources/input-onmessage.js"></script>
<script src="../resources/pending-input-utils.js"></script>
<style>
.occluding {
margin-left: -100px;
}
</style>
</head>
<body>
<iframe src="http://{{hosts[][www1]}}:{{ports[http][0]}}/is-input-pending/resources/blank.html"></iframe>
<iframe class="occluding" src="http://{{hosts[][www2]}}:{{ports[http][0]}}/is-input-pending/resources/blank.html"></iframe>
<p>Ensure that two overlapping subframes cannot detect events from each other.</p>
<script>
window.addEventListener('load', () => {
PendingInputUtils.testCannotAccessPendingInputAt(window, 280, 10, 'parent cannot detect input on occluding iframe');
PendingInputUtils.testCannotAccessPendingInputAt(frames[0], 280, 10, 'occluded iframe cannot detect input on occluding iframe');
});
</script>
</body>
</html>
<!doctype html>
<html>
<head>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-actions.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="../resources/input-onmessage.js"></script>
<script src="../resources/pending-input-utils.js"></script>
<style>
iframe {
pointer-events: none;
}
</style>
</head>
<body>
<iframe src="http://{{hosts[][www1]}}:{{ports[http][0]}}/is-input-pending/resources/blank.html"></iframe>
<p>Ensure that a subframe cannot detect events if it has `pointer-events: none`.</p>
<script>
window.addEventListener('load', () => {
PendingInputUtils.testCannotAccessPendingInputAt(frames[0], 10, 10, 'iframe cannot detect events with pointer-events: none');
});
</script>
</body>
</html>
<!doctype html>
<html>
<head>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-actions.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="../resources/input-onmessage.js"></script>
<script src="../resources/pending-input-utils.js"></script>
<style>
iframe {
transform: rotateZ(-45deg);
}
</style>
</head>
<body>
<iframe src="http://{{hosts[][www1]}}:{{ports[http][0]}}/is-input-pending/resources/blank.html"></iframe>
<p>Ensure that a parent frame cannot detect events on a cross-origin subframe when the subframe does not intersect and is not an axis-aligned rect.</p>
<script>
window.addEventListener('load', () => {
PendingInputUtils.testCannotAccessPendingInputAt(window, 100, 50, 'parent cannot detect input inside of iframe bounds');
PendingInputUtils.testCannotAccessPendingInputAt(frames[0], 10, 10, 'subframe cannot detect input outside of iframe bounds');
});
</script>
</body>
</html>
<!doctype html>
<html>
<head>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-actions.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="../resources/input-onmessage.js"></script>
<script src="../resources/pending-input-utils.js"></script>
</head>
<body>
<iframe src="http://{{hosts[][www1]}}:{{ports[http][0]}}/is-input-pending/resources/blank.html"></iframe>
<p>Ensure that a parent frame cannot detect events on a cross-origin subframe.</p>
<script>
window.addEventListener('load', () => {
PendingInputUtils.testCannotAccessPendingInputAt(window, 10, 10, 'cannot detect cross-origin events on subframe');
});
</script>
</body>
</html>
<!doctype html>
<html>
<head>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-actions.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="../resources/input-onmessage.js"></script>
<script src="../resources/pending-input-utils.js"></script>
</head>
<body>
<iframe src="../resources/blank.html"></iframe>
<p>Ensure that a parent frame can detect events on one of its same-origin subframes.</p>
<script>
window.addEventListener('load', () => {
PendingInputUtils.testDetectDiscretePendingInput(window, () => {
return new test_driver.Actions()
.pointerMove(10, 10)
.pointerDown()
.pointerUp();
}, 'can detect same-origin iframe events in parent');
PendingInputUtils.testDetectDiscretePendingInput(frames[0], () => {
return new test_driver.Actions()
.pointerMove(10, 10)
.pointerDown()
.pointerUp();
}, 'can detect same-origin iframe events in subframe');
});
</script>
</body>
</html>
<!doctype html>
<html>
<head>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-actions.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="../resources/input-onmessage.js"></script>
<script src="../resources/pending-input-utils.js"></script>
</head>
<body>
<p>Ensure that pointer events dispatched the to the toplevel document are detectable by isInputPending.</p>
<script>
window.addEventListener('load', () => {
PendingInputUtils.testDetectDiscretePendingInput(window, () => {
return new test_driver.Actions()
.addPointer('p', 'mouse')
.pointerMove(10, 10)
.pointerDown()
.pointerUp();
}, 'toplevel mouse events detected');
});
</script>
</body>
</html>
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment