blob: 16acd687aae657a7b24a5fda8150b926c337fb93 [file] [log] [blame]
<!DOCTYPE html>
<meta charset="utf-8" />
<title>The pop-up-hide-delay CSS property</title>
<link rel="author" href="mailto:masonf@chromium.org">
<link rel=help href="https://open-ui.org/components/popup.research.explainer">
<meta name="timeout" content="long">
<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/popup-utils.js"></script>
<style>
[popup] {
top:100px;
pop-up-hide-delay: 100ms;
}
[popuphovertarget] {
top:200px;
pop-up-show-delay: 100ms;
}
#unrelated {top: 300px;}
div {
/* Fixed position everything to ensure nothing overlaps */
position: fixed;
}
</style>
<div id=unrelated>Unrelated element</div>
<div popup id=example1>Pop-up</div>
<div popuphovertarget=example1 id=invoker1>Hover me</div>
<script>
const hoverDelays = 100; // This needs to match the style block above.
const hoverWaitTime = 200; // How long to wait to cover the delay for sure.
// NOTE about testing methodology:
// This test checks whether pop-ups are hidden *after* the appropriate de-hover
// delay. The delay used for testing is kept low, to avoid this test taking too
// long, but that means that sometimes on a slow bot/client, the delay can
// elapse before we are able to check the pop-up status. And that can make this
// test flaky. To avoid that, the msSinceMouseOver() function is used to check
// that not-too-much time has passed, and if it has, the test is simply skipped.
const unrelated = document.getElementById('unrelated');
function getComputedStyleTimeMs(element,property) {
// Times are in seconds, so just strip off the 's'.
return Number(getComputedStyle(element)[property].slice(0,-1))*1000;
}
promise_test(async (t) => {
await mouseOver(unrelated);
const popUp = document.getElementById('example1');
assert_false(popUp.matches(':top-layer'));
popUp.showPopUp();
assert_true(popUp.matches(':top-layer'));
await waitForHoverTime(hoverWaitTime);
assert_false(popUp.matches(':top-layer'));
assert_true(msSinceMouseOver() >= hoverWaitTime,'waitForHoverTime should wait the specified time');
assert_true(hoverWaitTime > hoverDelays,'hoverDelays is the value from CSS, hoverWaitTime should be longer than that');
assert_equals(getComputedStyleTimeMs(invoker1,'popUpShowDelay'),hoverDelays,'pop-up-show-delay is incorrect');
assert_equals(getComputedStyleTimeMs(popUp,'popUpHideDelay'),hoverDelays,'pop-up-hide-delay is incorrect');
},`The pop-up-hide-delay causes a pop-up to be hidden after a delay`);
promise_test(async (t) => {
await mouseOver(unrelated);
const popUp = document.getElementById('example1');
assert_false(popUp.matches(':top-layer'));
popUp.showPopUp();
await mouseOver(popUp);
await waitForHoverTime(hoverWaitTime);
assert_true(popUp.matches(':top-layer'),'hovering the pop-up should keep it showing');
await mouseOver(unrelated);
let showing = popUp.matches(':top-layer');
if (msSinceMouseOver() >= hoverDelays)
return; // The WPT runner was too slow.
assert_true(showing,'hovering unrelated element shouldn\'t immediately hide the pop-up');
await waitForHoverTime(hoverWaitTime);
assert_false(popUp.matches(':top-layer'),'hovering unrelated element should hide pop-up after delay');
},`hovering the pop-up keeps it from being hidden`);
promise_test(async (t) => {
await mouseOver(unrelated);
const popUp = document.getElementById('example1');
const invoker = document.getElementById('invoker1');
assert_false(popUp.matches(':top-layer'));
await mouseOver(invoker);
await waitForHoverTime(hoverWaitTime);
assert_true(popUp.matches(':top-layer'));
await waitForHoverTime(hoverWaitTime);
assert_true(popUp.matches(':top-layer'),'While still hovering the invoker, pop-up should not be hidden');
await mouseOver(popUp);
await waitForHoverTime(hoverWaitTime);
await mouseOver(invoker);
await waitForHoverTime(hoverWaitTime);
assert_true(popUp.matches(':top-layer'),'Moving hover between invoker and pop-up should keep pop-up from being hidden');
await mouseOver(unrelated);
await waitForHoverTime(hoverWaitTime);
assert_false(popUp.matches(':top-layer'),'Moving hover to unrelated should finally hide the pop-up');
},`hovering a popuphovertarget invoking element keeps the pop-up from being hidden`);
</script>
<div popup id=example2>Pop-up</div>
<button popuptoggletarget=example2><span><span data-note=nested_element id=invoker2>Click me</span></span></button>
<script>
promise_test(async (t) => {
await mouseOver(unrelated);
const popUp = document.getElementById('example2');
const invoker = document.getElementById('invoker2');
assert_equals(getComputedStyleTimeMs(popUp,'popUpHideDelay'),hoverDelays,'pop-up-hide-delay is incorrect');
assert_false(popUp.matches(':top-layer'));
await mouseOver(invoker);
popUp.showPopUp();
await waitForHoverTime(hoverWaitTime);
assert_true(popUp.matches(':top-layer'),'While hovering an invoker element, pop-up should not be hidden');
await mouseOver(popUp);
await waitForHoverTime(hoverWaitTime);
await mouseOver(invoker);
await waitForHoverTime(hoverWaitTime);
assert_true(popUp.matches(':top-layer'),'Moving hover between invoker and pop-up should keep pop-up from being hidden');
await mouseOver(unrelated);
await waitForHoverTime(hoverWaitTime);
assert_false(popUp.matches(':top-layer'),'Moving hover to unrelated should finally hide the pop-up');
},`hovering a popuptoggletarget invoking element keeps the pop-up from being hidden`);
</script>