diff --git a/html/semantics/popups/popup-animation-corner-cases.tentative.html b/html/semantics/popups/popup-animation-corner-cases.tentative.html
index 917f0d900d1502..c463139b3c64ec 100644
--- a/html/semantics/popups/popup-animation-corner-cases.tentative.html
+++ b/html/semantics/popups/popup-animation-corner-cases.tentative.html
@@ -45,7 +45,10 @@
const {popUp, descendent} = createPopUp(t,'animation');
assert_false(isElementVisible(popUp));
assert_equals(descendent.parentElement.parentElement,popUp);
+ assert_true(popUp.matches(':closed'));
+ assert_false(popUp.matches(':open'));
popUp.showPopUp();
+ assert_false(popUp.matches(':closed'));
assert_true(popUp.matches(':open'));
assert_true(isElementVisible(popUp));
assert_equals(popUp.getAnimations({subtree: true}).length,0);
@@ -53,6 +56,7 @@
const animations = popUp.getAnimations({subtree: true});
assert_equals(animations.length,2,'There should be two animations running');
assert_false(popUp.matches(':open'),'popUp should not match :open as soon as hidden');
+ assert_false(popUp.matches(':closed'),'popUp should not match :closed until animations complete');
assert_true(isElementVisible(popUp),'but animations should keep the popUp visible');
assert_true(isElementVisible(descendent),'The descendent should also be visible');
await waitForRender();
@@ -61,6 +65,7 @@
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_true(popUp.matches(':closed'),'The pop up should now match :closed');
assert_false(popUp.matches(':open'),'The pop up still shouldn\'t match :open');
assert_false(isElementVisible(popUp),'The pop up should now be invisible');
assert_false(isElementVisible(descendent),'The descendent should also be invisible');
@@ -82,6 +87,7 @@
// Then hide the popUp.
popUp.hidePopUp();
assert_false(popUp.matches(':open'),'pop up should not match :open as soon as hidden');
+ assert_true(popUp.matches(':closed'),'pop up should match :closed immediately');
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');
@@ -137,6 +143,27 @@
assert_false(isElementVisible(popUp),'Even if hide event is cancelled, the popup still closes');
},'hide event cannot be cancelled');
+promise_test(async (t) => {
+ const {popUp, descendent} = createPopUp(t,'animation');
+ assert_false(isElementVisible(popUp));
+ popUp.showPopUp();
+ assert_false(popUp.matches(':closed'));
+ assert_true(popUp.matches(':open'));
+ assert_true(isElementVisible(popUp));
+ assert_equals(popUp.getAnimations({subtree: true}).length,0);
+ popUp.popUp = 'manual';
+ const animations = popUp.getAnimations({subtree: true});
+ assert_equals(animations.length,2,'There should be two animations running');
+ assert_false(popUp.matches(':open'),'popUp should not match :open as soon as hidden');
+ assert_false(popUp.matches(':closed'),'popUp should not match :closed until animations complete');
+ assert_true(isElementVisible(popUp),'but animations should keep the popUp visible');
+ animations.forEach(animation => animation.finish()); // Force the animations to finish
+ await waitForRender(); // Wait one frame
+ assert_true(popUp.matches(':closed'),'The pop up should now match :closed');
+ assert_false(popUp.matches(':open'),'The pop up still shouldn\'t match :open');
+ assert_false(isElementVisible(popUp),'The pop up should now be invisible');
+},'Closing animations are triggered by changing the pop-up type');
+
promise_test(async (t) => {
const {popUp, descendent} = createPopUp(t,'');
popUp.showPopUp();
diff --git a/html/semantics/popups/popup-attribute-basic.tentative.html b/html/semantics/popups/popup-attribute-basic.tentative.html
index de8d4d5f897003..e5b49ec9b19430 100644
--- a/html/semantics/popups/popup-attribute-basic.tentative.html
+++ b/html/semantics/popups/popup-attribute-basic.tentative.html
@@ -47,9 +47,11 @@
if (isVisible) {
assert_not_equals(window.getComputedStyle(popUp).display,'none');
assert_equals(popUp.matches(':open'),isPopUp,`${message}: Visible pop-ups should match :open`);
+ assert_false(popUp.matches(':closed'),`${message}: Visible pop-ups and *all* non-pop-ups should *not* match :closed`);
} else {
assert_equals(window.getComputedStyle(popUp).display,'none',`${message}: Non-showing pop-ups should have display:none`);
assert_false(popUp.matches(':open'),`${message}: Non-showing pop-ups should *not* match :open`);
+ assert_true(popUp.matches(':closed'),`${message}: Non-showing pop-ups should match :closed`);
}
}
function assertIsFunctionalPopUp(popUp) {
@@ -89,7 +91,7 @@
});
// Then loop through all HTML5 elements that render a box by default:
- let elementsThatDontRender = ['audio','base','br','datalist','dialog','embed','head','link','meta','noscript','param','rp','script','style','template','title','wbr'];
+ let elementsThatDontRender = ['audio','base','br','datalist','dialog','embed','head','link','meta','noscript','param','rp','script','slot','style','template','title','wbr'];
const elements = HTML5_ELEMENTS.filter(el => !elementsThatDontRender.includes(el));
elements.forEach(tag => {
test((t) => {
@@ -98,7 +100,13 @@
document.body.appendChild(element);
t.add_cleanup(() => element.remove());
assertIsFunctionalPopUp(element);
- }, `A <${tag}> element should behave as a pop-up.`);
+ }, `A <${tag} popup> element should behave as a pop-up.`);
+ test((t) => {
+ const element = document.createElement(tag);
+ document.body.appendChild(element);
+ t.add_cleanup(() => element.remove());
+ assertNotAPopUp(element);
+ }, `A <${tag}> element should *not* behave as a pop-up.`);
});
function createPopUp(t) {
@@ -318,6 +326,7 @@
assert_false(isElementVisible(popUp));
popUp.showPopUp();
assert_true(popUp.matches(':open'));
+ assert_false(popUp.matches(':closed'));
assert_true(getComputedStyle(popUp).opacity < 0.1,'Animations should start on show');
assert_throws_dom("InvalidStateError",() => popUp.showPopUp(),'Calling showPopUp on a popup that is in the process of animating show should throw InvalidStateError');
await finishAnimations(popUp);
@@ -325,10 +334,12 @@
assert_true(isElementVisible(popUp));
popUp.hidePopUp();
assert_false(popUp.matches(':open'));
+ assert_false(popUp.matches(':closed'),'Not :closed until animations finish');
assert_true(getComputedStyle(popUp).opacity > 0.9,'Animations should start on hide');
assert_throws_dom("InvalidStateError",() => popUp.hidePopUp(),'Calling hidePopUp on a popup that is in the process of animating hide should throw InvalidStateError');
popUp.showPopUp(); // But showPopUp should still be ok.
popUp.hidePopUp(); // Clean up
await finishAnimations(popUp);
+ assert_true(popUp.matches(':closed'),':closed should match once animations finish');
},'Exceptions are thrown even when show/hide are animated')