summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/html/semantics/popovers/popover-top-layer-combinations.html
diff options
context:
space:
mode:
Diffstat (limited to 'testing/web-platform/tests/html/semantics/popovers/popover-top-layer-combinations.html')
-rw-r--r--testing/web-platform/tests/html/semantics/popovers/popover-top-layer-combinations.html149
1 files changed, 149 insertions, 0 deletions
diff --git a/testing/web-platform/tests/html/semantics/popovers/popover-top-layer-combinations.html b/testing/web-platform/tests/html/semantics/popovers/popover-top-layer-combinations.html
new file mode 100644
index 0000000000..8db327d7d1
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/popovers/popover-top-layer-combinations.html
@@ -0,0 +1,149 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Popover combined with dialog/fullscreen behavior</title>
+<link rel=author href="mailto:masonf@chromium.org">
+<link rel=help href="https://open-ui.org/components/popover.research.explainer">
+<link rel=help href="https://html.spec.whatwg.org/multipage/popover.html">
+<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/popover-utils.js"></script>
+
+<button id=visible>Visible button</button>
+<div id=examples>
+ <dialog popover>Popover Dialog</dialog>
+ <dialog popover open style="top:50px;">Open Non-modal Popover Dialog</dialog>
+ <div popover class=fullscreen>Fullscreen Popover</div>
+ <dialog popover class=fullscreen>Fullscreen Popover Dialog</dialog>
+ <dialog popover open class=fullscreen style="top:200px;">Fullscreen Open Non-modal Popover Dialog</dialog>
+</div>
+
+<style>
+ [popover] {
+ inset:auto;
+ top:0;
+ left:0;
+ }
+ [popover].fullscreen.visible {
+ display:block;
+ }
+</style>
+
+<script>
+const isDialog = (ex) => ex instanceof HTMLDialogElement;
+const isFullscreen = (ex) => ex.classList.contains('fullscreen');
+function ensureIsOpenPopover(ex,message) {
+ // Because :popover-open will eventually support <dialog>, this does extra work to
+ // verify we're dealing with an :popover-open Popover. Note that this will also throw
+ // if this is an element with the `popover` attribute that has been made
+ // visible via an explicit `display:block` style rule.
+ message = message || 'Error';
+ assert_true(ex.matches(':popover-open'),`${message}: Popover doesn\'t match :popover-open`);
+ ex.hidePopover(); // Shouldn't throw if this is a showing popover
+ ex.showPopover(); // Show it again to avoid state change
+ assert_true(ex.matches(':popover-open'),`${message}: Sanity`);
+}
+window.onload = () => requestAnimationFrame(() => requestAnimationFrame(() => {
+ const examples = Array.from(document.querySelectorAll('#examples>*'));
+ examples.forEach(ex => {
+ promise_test(async (t) => {
+ t.add_cleanup(() => ex.remove());
+ // Test initial conditions
+ if (ex.hasAttribute('open')) {
+ assert_true(isDialog(ex));
+ assert_true(isElementVisible(ex),'Open dialog should be visible by default');
+ assert_throws_dom("InvalidStateError",() => ex.showPopover(),'Calling showPopover on an already-showing element should throw InvalidStateError');
+ ex.removeAttribute('open');
+ assert_false(isElementVisible(ex),'Removing the open attribute should hide the dialog');
+ } else {
+ ex.showPopover(); // Should not throw
+ ensureIsOpenPopover(ex,'showPopover should work');
+ ex.hidePopover(); // Should not throw
+ assert_false(ex.matches(':popover-open'),'hidePopover should work');
+ }
+ assert_false(isElementVisible(ex));
+
+ // Start with popover, try the other API
+ ex.showPopover();
+ ensureIsOpenPopover(ex);
+ let tested_something=false;
+ if (isDialog(ex)) {
+ tested_something=true;
+ assert_throws_dom("InvalidStateError",() => ex.showModal(),'Calling showModal() on an already-showing Popover should throw InvalidStateError');
+ assert_throws_dom("InvalidStateError",() => ex.show(),'Calling show() on an already-showing Popover should throw InvalidStateError');
+ }
+ if (isFullscreen(ex)) {
+ tested_something=true;
+ let requestSucceeded = false;
+ await blessTopLayer(ex);
+ await ex.requestFullscreen()
+ .then(() => {requestSucceeded = true;}) // We should not hit this.
+ .catch((exception) => {
+ // This exception is expected.
+ assert_equals(exception.name,'TypeError',`Invalid exception from requestFullscreen() (${exception.message})`);
+ });
+ assert_false(requestSucceeded,'requestFullscreen() should not succeed when the element is an already-showing Popover');
+ }
+ assert_true(tested_something);
+ ensureIsOpenPopover(ex);
+ ex.hidePopover();
+
+ // Start with the other API, then try popover
+ if (isDialog(ex)) {
+ ex.show();
+ assert_true(ex.hasAttribute('open'));
+ assert_throws_dom("InvalidStateError",() => ex.showPopover(),'Calling showPopover() on an already-showing non-modal dialog should throw InvalidStateError');
+ ex.close();
+ assert_false(ex.hasAttribute('open'));
+ ex.showModal();
+ assert_true(ex.hasAttribute('open'));
+ assert_throws_dom("InvalidStateError",() => ex.showPopover(),'Calling showPopover() on an already-showing modal dialog should throw InvalidStateError');
+ ex.close();
+ assert_false(ex.hasAttribute('open'));
+ } else if (isFullscreen(ex)) {
+ let requestSucceeded = false;
+ await blessTopLayer(visible);
+ await ex.requestFullscreen()
+ .then(() => {
+ assert_throws_dom("InvalidStateError",() => ex.showPopover(),'Calling showPopover() on an already-fullscreen element should throw InvalidStateError');
+ });
+ await document.exitFullscreen()
+ .then(() => assert_true(true));
+ }
+
+ // Finally, try invoking these combined popovers via a declarative invoker
+ const button = document.createElement('button');
+ t.add_cleanup(() => button.remove());
+ document.body.appendChild(button);
+ button.popoverTargetElement = ex;
+ button.popoverTargetAction = "toggle";
+ assert_false(ex.matches(':popover-open'));
+ await clickOn(button);
+ ensureIsOpenPopover(ex,'Invoking element should be able to invoke all popovers');
+ ex.hidePopover();
+ if (isDialog(ex)) {
+ ex.showModal();
+ assert_true(ex.hasAttribute('open'));
+ } else if (isFullscreen(ex)) {
+ // Popover fullscreen isn't visible by default, so explicitly add
+ // display:block, so that calls to "clickOn" can succeed.
+ ex.classList.add('visible');
+ await blessTopLayer(visible);
+ await ex.requestFullscreen();
+ } else {
+ assert_unreached('Not a dialog or fullscreen');
+ }
+ ex.appendChild(button); // Add button to the element, so it's visible to click
+ await clickOn(button);
+ assert_false(ex.matches(':popover-open'),'The invoker click should have failed on the already-open dialog/fullscreen');
+ if (isDialog(ex)) {
+ ex.close();
+ } else {
+ await document.exitFullscreen()
+ }
+ }, `Popover combination: ${ex.textContent}`);
+ });
+}));
+</script>