Bug 1774491 [wpt PR 34454] - Fix popup animation bug, and add more testing of animations, a=testonly

Automatic update from web-platform-tests
Fix popup animation bug, and add more testing of animations

Primarily, this CL adds a test of popup animations for these two cases:
 1. descendant elements have an animation: make sure "hide" waits for it
 2. there are already-running animations: make sure "hide" doesn't wait

These were follow-up action items from [1].

While writing this test, I found and fixed a corner case bug: if there
are *only* pre-existing animations, a popup would never be hidden.

[1] https://chromium-review.googlesource.com/c/chromium/src/+/3688871

Bug: 1307772
Change-Id: I133f4d682bb8081b137fb23675137b06e6a15565
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3708115
Reviewed-by: Robert Flack <flackr@chromium.org>
Auto-Submit: Mason Freed <masonf@chromium.org>
Commit-Queue: Robert Flack <flackr@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1015056}

--

wpt-commits: 93a98d6ac4785d3c78b57845d91c78e2bf12c6eb
wpt-pr: 34454
This commit is contained in:
Mason Freed 2022-06-21 09:58:11 +00:00 коммит произвёл moz-wptsync-bot
Родитель d1939b2c9d
Коммит a36765a3a4
4 изменённых файлов: 106 добавлений и 14 удалений

Просмотреть файл

@ -0,0 +1,90 @@
<!DOCTYPE html>
<meta charset="utf-8">
<link rel=author href="mailto:masonf@chromium.org">
<link rel=help href="https://open-ui.org/components/popup.research.explainer">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="resources/popup-utils.js"></script>
<body>
<style>
.animation { opacity: 0; }
.animation:top-layer { opacity: 1; }
.animation:not(:top-layer) { animation: fade-out 1000s; }
@keyframes fade-out {
from { opacity: 1; }
to { opacity: 0; }
}
.animation>div>div { left: 0; }
.animation:not(:top-layer)>div>div { animation: rotate 1000s; color:red;}
@keyframes rotate {
from { transform: rotate(0); }
to { transform: rotate(360deg); }
}
[popup] { top: 200px; }
[popup]::backdrop { background-color: rgba(255,0,0,0.2); }
</style>
<script>
function createPopup(t,type) {
const popup = document.createElement('div');
popup.popup = 'auto';
popup.classList = type;
const div = document.createElement('div');
const descendent = div.appendChild(document.createElement('div'));
descendent.appendChild(document.createTextNode("Descendent element"));
popup.append("This is a popup",div);
document.body.appendChild(popup);
t.add_cleanup(() => popup.remove());
return {popup, descendent};
}
promise_test(async (t) => {
const {popup, descendent} = createPopup(t,'animation');
assert_false(isElementVisible(popup));
assert_equals(descendent.parentElement.parentElement,popup);
popup.showPopup();
assert_true(popup.matches(':top-layer'));
assert_true(isElementVisible(popup));
assert_equals(popup.getAnimations({subtree: true}).length,0);
popup.hidePopup();
const animations = popup.getAnimations({subtree: true});
assert_equals(animations.length,2,'There should be two animations running');
assert_false(popup.matches(':top-layer'),'popup should not match :top-layer as soon as hidden');
assert_true(isElementVisible(popup),'but animations should keep the popup visible');
assert_true(isElementVisible(descendent),'The descendent should also be visible');
await waitForRender();
await waitForRender();
assert_equals(popup.getAnimations({subtree: true}).length,2,'The animations should still be running');
assert_true(isElementVisible(popup),'Popup should still be visible due to animation');
animations.forEach(animation => animation.finish()); // Force the animations to finish
await waitForRender(); // Wait one frame
assert_false(popup.matches(':top-layer'),'The popup still shouldn\'t match :top-layer');
assert_false(isElementVisible(popup),'The popup should now be invisible');
assert_false(isElementVisible(descendent),'The descendent should also be invisible');
assert_equals(popup.getAnimations({subtree: true}).length,0);
},'Descendent animations should keep the popup visible until the animation ends');
promise_test(async (t) => {
const {popup, descendent} = createPopup(t,'');
assert_equals(popup.classList.length, 0);
assert_false(isElementVisible(popup));
popup.showPopup();
assert_true(popup.matches(':top-layer'));
assert_true(isElementVisible(popup));
assert_equals(popup.getAnimations({subtree: true}).length,0);
// Start an animation on the popup and its descendent.
popup.animate([{opacity: 1},{opacity: 0}],{duration: 1000000,iterations: 1});
descendent.animate([{transform: 'rotate(0)'},{transform: 'rotate(360deg)'}],{duration: 1000000,iterations: 1});
assert_equals(popup.getAnimations({subtree: true}).length,2);
// Then hide the popup.
popup.hidePopup();
assert_false(popup.matches(':top-layer'),'popup should not match :top-layer as soon as hidden');
assert_equals(popup.getAnimations({subtree: true}).length,2,'animations should still be running');
await waitForRender();
assert_equals(popup.getAnimations({subtree: true}).length,2,'animations should still be running');
assert_false(isElementVisible(popup),'Pre-existing animations should not keep the popup visible');
},'Pre-existing animations should *not* keep the popup visible until the animation ends');
</script>

Просмотреть файл

@ -4,6 +4,7 @@
<link rel=help href="https://open-ui.org/components/popup.research.explainer">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="resources/popup-utils.js"></script>
<div id=popups>
<div popup id=boolean>Popup</div>
@ -21,7 +22,7 @@
<script>
function popupVisible(popup, isPopup) {
const isVisible = !!(popup.offsetWidth || popup.offsetHeight || popup.getClientRects().length);
const isVisible = isElementVisible(popup);
if (isVisible) {
assert_not_equals(window.getComputedStyle(popup).display,'none');
assert_equals(isPopup,popup.matches(':top-layer'));

Просмотреть файл

@ -4,6 +4,7 @@
<link rel=help href="https://open-ui.org/components/popup.research.explainer">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="resources/popup-utils.js"></script>
<script>
function ensureShadowDom(host) {
@ -35,9 +36,6 @@
ensureShadowDom(testRoot);
return findPopups(testRoot);
}
function popupVisible(popup) {
return !!(popup.offsetWidth || popup.offsetHeight || popup.getClientRects().length);
}
function showPopup(testId,popupNum) {
getPopupReferences(testId)[popupNum].showPopup();
}
@ -59,7 +57,7 @@
const popup = getPopupReferences('test1')[0];
popup.showPopup();
assert_true(popup.matches(':top-layer'));
assert_true(popupVisible(popup));
assert_true(isElementVisible(popup));
}, "Popups located inside shadow DOM can still be shown");
</script>
@ -85,12 +83,12 @@
const [popup1,popup2] = getPopupReferences('test2');
popup1.showPopup();
assert_true(popup1.matches(':top-layer'));
assert_true(popupVisible(popup1));
assert_true(isElementVisible(popup1));
popup2.showPopup();
assert_false(popup1.matches(':top-layer'), 'popup1 open'); // P1 was closed by P2
assert_false(popupVisible(popup1), 'popup1 visible');
assert_false(isElementVisible(popup1), 'popup1 visible');
assert_true(popup2.matches(':top-layer'), 'popup2 open'); // P2 is open
assert_true(popupVisible(popup2), 'popup2 visible');
assert_true(isElementVisible(popup2), 'popup2 visible');
}, "anchor references do not cross shadow boundaries");
</script>
@ -114,14 +112,14 @@
const [popup1,popup2] = getPopupReferences('test3');
popup1.showPopup();
assert_true(popup1.matches(':top-layer'));
assert_true(popupVisible(popup1));
assert_true(isElementVisible(popup1));
// Showing popup2 should not close popup1, since it is a flat
// tree ancestor of popup2's anchor button.
popup2.showPopup();
assert_true(popup2.matches(':top-layer'));
assert_true(popupVisible(popup2));
assert_true(isElementVisible(popup2));
assert_true(popup1.matches(':top-layer'));
assert_true(popupVisible(popup1));
assert_true(isElementVisible(popup1));
popup1.hidePopup();
assert_false(popup2.matches(':top-layer'));
assert_false(popup1.matches(':top-layer'));
@ -151,12 +149,12 @@
popup2.showPopup();
// Both 1 and 2 should be open at this point.
assert_true(popup1.matches(':top-layer'), 'popup1 not open');
assert_true(popupVisible(popup1));
assert_true(isElementVisible(popup1));
assert_true(popup2.matches(':top-layer'), 'popup2 not open');
assert_true(popupVisible(popup2));
assert_true(isElementVisible(popup2));
// This should hide both of them.
popup1.hidePopup();
assert_false(popup2.matches(':top-layer'));
assert_false(popupVisible(popup2));
assert_false(isElementVisible(popup2));
}, "The popup stack is preserved across shadow-inclusive ancestors");
</script>

Просмотреть файл

@ -20,3 +20,6 @@ async function sendEscape() {
await new test_driver.send_keys(document.body,'\uE00C'); // Escape
await waitForRender();
}
function isElementVisible(el) {
return !!(el.offsetWidth || el.offsetHeight || el.getClientRects().length);
}