summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/window-placement
diff options
context:
space:
mode:
Diffstat (limited to 'testing/web-platform/tests/window-placement')
-rw-r--r--testing/web-platform/tests/window-placement/META.yml4
-rw-r--r--testing/web-platform/tests/window-placement/README.md5
-rw-r--r--testing/web-platform/tests/window-placement/fullscreen-companion-window-manual.tentative.https.html76
-rw-r--r--testing/web-platform/tests/window-placement/multi-screen-fullscreen-manual.tentative.https.html116
-rw-r--r--testing/web-platform/tests/window-placement/multi-screen-window-open.tentative.https.html99
-rw-r--r--testing/web-platform/tests/window-placement/resources/helpers.js68
6 files changed, 368 insertions, 0 deletions
diff --git a/testing/web-platform/tests/window-placement/META.yml b/testing/web-platform/tests/window-placement/META.yml
new file mode 100644
index 0000000000..2c6d60f4e7
--- /dev/null
+++ b/testing/web-platform/tests/window-placement/META.yml
@@ -0,0 +1,4 @@
+spec: https://w3c.github.io/window-placement/
+suggested_reviewers:
+ - michaelwasserman
+ - bradtriebwasser
diff --git a/testing/web-platform/tests/window-placement/README.md b/testing/web-platform/tests/window-placement/README.md
new file mode 100644
index 0000000000..d9e324c911
--- /dev/null
+++ b/testing/web-platform/tests/window-placement/README.md
@@ -0,0 +1,5 @@
+# Window Management Testing
+
+[Window Management Specification](https://w3c.github.io/window-placement/)
+
+The tests in this directory require at least 2 displays on the host machine to yield meaningful results. A well-supported configuration is 2 displays at 1920x1080 resolution arranged horizonally (primary on the left, secondary on the right).
diff --git a/testing/web-platform/tests/window-placement/fullscreen-companion-window-manual.tentative.https.html b/testing/web-platform/tests/window-placement/fullscreen-companion-window-manual.tentative.https.html
new file mode 100644
index 0000000000..10f30a1906
--- /dev/null
+++ b/testing/web-platform/tests/window-placement/fullscreen-companion-window-manual.tentative.https.html
@@ -0,0 +1,76 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<meta name="timeout" content="long">
+<!-- user agents are not required to support open features other than `noopener`
+ and on some platforms position and size features don't make sense -->
+<meta name="flags" content="may">
+<title>Multi-Screen Window Management test: Fullscreen Companion Window</title>
+<link rel="help" href="https://w3c.github.io/window-placement/">
+This test uses multi-screen details to request fullscreen and open a pop-up<br>
+(companion window) in the same user activation.<br>
+It runs manually with `wpt serve` and a compatible browser.<br><br>
+<button id="setUpButton">Request screen details</button>
+<ul id="popupButtons"></ul>
+<button id="cleanUpButton">Close any open popups</button><br>
+<input id="autoCleanUp" type="checkbox" checked=true>Auto-close popups</input>
+<ul id="logger"></ul>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<script src="resources/helpers.js"></script>
+
+<script>
+'use strict';
+let popups = [];
+
+cleanUpButton.addEventListener('click', async () => {
+ popups.forEach(p => p.close());
+});
+
+// expectPopup should be true if the test should expect the pop-up to be
+// created, or false if the popup is not expected to be created (blocked).
+async function testPopupOnScreen(popupTest, screen, expectPopup) {
+ // Show a popup child window on the associated screen.
+ const left = screen.availLeft + Math.floor(screen.availWidth / 2) - 150;
+ const top = screen.availTop + Math.floor(screen.availHeight / 2) - 50;
+ log(`Opening a popup on '${screen.label}' at (${left}, ${top})`);
+ let popup = window.open(
+ '/resources/blank.html', '',
+ `left=${left},top=${top},width=300,height=100`);
+ assert_equals(!!popup, expectPopup, 'Popup reference');
+ if (popup === null)
+ return;
+ assert_equals(!popup.closed, expectPopup, 'Popup open');
+ popups.push(popup);
+ if (autoCleanUp.checked) {
+ // TODO(crbug.com/1338645): Remove this workaround (delay) after browser code is
+ // fixed.
+ popupTest.add_cleanup(()=>{
+ setTimeout(popup.close, 1000);
+ });
+ }
+}
+
+promise_test(async setUpTest => {
+ await setUpWindowManagement(setUpTest, setUpButton);
+ const screenDetails = await getScreenDetails();
+ assert_true(!!screenDetails, 'Error getting screen details');
+ for (const [i, fullscreenScreen] of screenDetails.screens.entries()) {
+ const popupScreen =
+ screenDetails.screens[(i + 1) % screenDetails.screens.length];
+ let testName =
+ `Fullscreen on '${fullscreenScreen.label}' and open popup on '${popupScreen.label}'`;
+ promise_test(async popupTest => {
+ await addTestTriggerButtonAndAwaitClick(popupButtons,
+ testName,
+ popupTest);
+ await document.documentElement.requestFullscreen(
+ { screen: fullscreenScreen }
+ );
+ await testPopupOnScreen(popupTest, popupScreen,
+ /*expectPopup=*/screenDetails.screens.length > 1);
+ }, testName);
+ }
+}, 'Use multi-screen details to request fullscreen and open a pop-up in the same user activation.');
+</script>
diff --git a/testing/web-platform/tests/window-placement/multi-screen-fullscreen-manual.tentative.https.html b/testing/web-platform/tests/window-placement/multi-screen-fullscreen-manual.tentative.https.html
new file mode 100644
index 0000000000..620cd6e507
--- /dev/null
+++ b/testing/web-platform/tests/window-placement/multi-screen-fullscreen-manual.tentative.https.html
@@ -0,0 +1,116 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<meta name="timeout" content="long">
+<title>Multi-Screen Window Placement test: element.requestFullscreen()</title>
+<link rel="help" href="https://w3c.github.io/window-placement/">
+This test uses multi-screen details to request fullscreen on different
+displays and swap between them.<br>
+It runs manually with `wpt serve` and a compatible browser.<br><br>
+<button id="setUpButton">Request screen details</button>
+<ul id="testButtons"></ul>
+<ul id="logger"></ul>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<script src="resources/helpers.js"></script>
+
+<script>
+'use strict';
+
+// Waits until `window` is located on `screen` or until 3 seconds elapses.
+async function ensureWindowOnScreen(window, screen) {
+ // Returns true if window `w` in on screen `s`.
+ const isWindowOnScreen = async (w, s) => {
+ const center = {
+ x: w.screenLeft + w.outerWidth / 2,
+ y: w.screenTop + w.outerHeight / 2
+ };
+ return center.x >= s.left && (center.x < s.left + s.width) &&
+ center.y >= s.top && (center.y < s.top + s.height) &&
+ (await w.getScreenDetails()).currentScreen == s;
+ }
+ // Checks every 100ms if window `w` is on screen `s` up to 3s maximum.
+ const waitForWindowOnScreen = async (w, s, resolve, timestamp = Date.now()) => {
+ if (!w || w.closed || Date.now() - timestamp > 3000)
+ resolve(false);
+ else if (await isWindowOnScreen(w, s))
+ resolve(true);
+ else
+ setTimeout(waitForWindowOnScreen.bind(this, w, s, resolve, timestamp), 100);
+ }
+ return new Promise(resolve => { waitForWindowOnScreen(window, screen, resolve); });
+}
+
+// Asserts that the browser window is correctly positioned on `screen`.
+// `expectFullscreen` specifies whether to expect the window to be
+// fullscreen or not.
+async function testWindowOnScreen(test, screen, expectFullscreen) {
+
+ // In chrome, the requestFullscreen promise may resolve before the
+ // transition completes and the bounds may be incorect in the meantime.
+ // Wait until the window is on the expected screen.
+ // TODO(crbug.com/1330724) Remove this.
+ await ensureWindowOnScreen(window, screen);
+
+ assert_equals(!!document.fullscreenElement, expectFullscreen);
+ assert_equals((await window.getScreenDetails()).currentScreen, screen);
+
+ if (expectFullscreen) {
+ // Window bounds should equal the bounds of the screen when in fullscreen.
+ assert_equals(window.screenX, screen.left);
+ assert_equals(window.screenY, screen.top);
+ assert_equals(window.innerWidth, screen.width);
+ assert_equals(window.innerHeight, screen.height);
+ } else {
+ // Verify the window is somewhere within the specified screen
+ assert_true(window.screenX >= screen.left);
+ assert_true(window.screenY >= screen.top);
+ assert_true(window.screenX + window.outerWidth <= screen.left + screen.width);
+ assert_true(window.screenY + window.outerHeight <= screen.top + screen.height);
+ }
+}
+
+promise_test(async setUpTest => {
+ await setUpWindowPlacement(setUpTest, setUpButton);
+ const screenDetails = await getScreenDetails();
+ assert_true(!!screenDetails, 'Error getting screen details');
+ for (const [i, fullscreenScreen] of screenDetails.screens.entries()) {
+ const originalScreen = screenDetails.currentScreen;
+ const swapFullscreen =
+ screenDetails.screens[(i + 1) % screenDetails.screens.length];
+ let testName =
+ `Fullscreen on '${fullscreenScreen.label}' and swap to ${swapFullscreen.label}`;
+ promise_test(async fullscreenTest => {
+ // Step 1: Enter Fullscreen.
+ await addTestTriggerButtonAndAwaitClick(testButtons,
+ `Step 1: ${testName} (Enter Fullscreen)`,
+ fullscreenTest);
+ log(`Requesting fullscreen on screen: ${fullscreenScreen.label}`);
+ await document.documentElement.requestFullscreen(
+ { screen: fullscreenScreen }
+ );
+ await testWindowOnScreen(fullscreenTest, fullscreenScreen,
+ /*expectFullscreen*/true);
+ // Step 2: Swap to another screen.
+ await addTestTriggerButtonAndAwaitClick(testButtons,
+ `Step 2: ${testName} (Swap screens)`,
+ fullscreenTest);
+ log(`Swapping fullscreen to screen: ${swapFullscreen.label}`);
+ await document.documentElement.requestFullscreen(
+ { screen: swapFullscreen }
+ );
+ await testWindowOnScreen(fullscreenTest, swapFullscreen,
+ /*expectFullscreen*/true);
+ // Step 3: Exit fullscreen. Should restore window to `originalScreen`.
+ await addTestTriggerButtonAndAwaitClick(testButtons,
+ `Step 3: ${testName} (Exit Fullscreen)`,
+ fullscreenTest);
+ log(`Exiting fullscreen. Window should restore to ${originalScreen.label}.`);
+ await document.exitFullscreen();
+ await testWindowOnScreen(fullscreenTest, originalScreen,
+ /*expectFullscreen*/false);
+ }, testName);
+ }
+}, 'Use multi-screen details to request fullscreen on target displays and swap between them');
+</script>
diff --git a/testing/web-platform/tests/window-placement/multi-screen-window-open.tentative.https.html b/testing/web-platform/tests/window-placement/multi-screen-window-open.tentative.https.html
new file mode 100644
index 0000000000..c453107d56
--- /dev/null
+++ b/testing/web-platform/tests/window-placement/multi-screen-window-open.tentative.https.html
@@ -0,0 +1,99 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<meta name="timeout" content="long">
+<!-- user agents are not required to support open features other than `noopener`
+ and on some platforms position and size features don't make sense -->
+<meta name="flags" content="may">
+<title>Multi-Screen Window Management test: window.open()</title>
+<link rel="help" href="https://w3c.github.io/window-placement/">
+This test uses multi-screen details to open a popup window on each screen.<br>
+It runs automated or manually with `wpt serve` and a compatible browser.<br><br>
+<button id="setUpButton">Request screen details</button>
+<ul id="popupButtons"></ul>
+<button id="cleanUpButton">Close any open popups</button><br>
+<input id="autoCleanUp" type="checkbox" checked=true>Auto-close popups</input>
+<ul id="logger"></ul>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<script src="resources/helpers.js"></script>
+
+<script>
+'use strict';
+let popups = [];
+
+cleanUpButton.addEventListener('click', async () => {
+ popups.forEach(p => p.close());
+});
+
+function checkPopupPlacement(popup, x, y, allowSameScreenClamping) {
+ // Window.screenX|Y may be zero, if the user agent wishes to hide information
+ // about the screen of the output device. They also may incorrectly reflect
+ // the origin of content viewport; in that case, estimate window coordinates
+ // by subtracing estimated frame insets (top-heavy, horizontally centered).
+ // Synchronous estimated placements may be clamped to the current screen.
+ const error = 10;
+ const dX = popup.screenX - x - (popup.outerWidth - popup.innerWidth) / 2;
+ const dY = popup.screenY - y - (popup.outerHeight - popup.innerHeight);
+
+ assert_true(!popup.screenX || popup.screenX == x || Math.abs(dX) <= error ||
+ (allowSameScreenClamping && popup.screenX >= screen.availLeft &&
+ popup.screenX < screen.availLeft + screen.availWidth));
+ assert_true(!popup.screenY || popup.screenY == y || Math.abs(dY) <= error ||
+ (allowSameScreenClamping && popup.screenY >= screen.availTop &&
+ popup.screenY < screen.availTop + screen.availHeight));
+}
+
+async function testPopupOnScreen(popupTest, screen) {
+ // Show a popup child window on the associated screen.
+ const left = screen.availLeft + Math.floor(screen.availWidth / 2) - 150;
+ const top = screen.availTop + Math.floor(screen.availHeight / 2) - 50;
+ log(`Opening a popup on '${screen.label}' at (${left}, ${top})`);
+ let popup = window.open(
+ '/resources/blank.html', '',
+ `left=${left},top=${top},width=300,height=100`);
+ popups.push(popup);
+ if (autoCleanUp.checked)
+ popupTest.add_cleanup(popup.close);
+
+ // Window.open() synchronously returns a Window with estimated screenX|Y.
+ // Initial `screenX` and `screenY` values should match `left` and `top`.
+ log(`<div style='margin-left: 40px'>Initial bounds:
+ (${popup.screenX}, ${popup.screenY})
+ </div>`);
+ // Allow synchronous estimated placements to be clamped to the current screen.
+ checkPopupPlacement(popup, left, top, true);
+ popup.initialScreenX = popup.screenX;
+ popup.initialScreenY = popup.screenY;
+
+ // Await document.visibilitychange to check resolved Window.screenX|Y values
+ // after asynchronous window creation and clamped placement has occurred.
+ const visibilitychangeWatcher =
+ new EventWatcher(popupTest, popup.document, ['visibilitychange']);
+ await visibilitychangeWatcher.wait_for('visibilitychange');
+ popup.document.write(`Expected: (${left}, ${top}) <br> \
+ Initial: (${popup.initialScreenX}, ${popup.initialScreenY}) <br> \
+ Resolved: (${popup.screenX}, ${popup.screenY}) `);
+ log(`<div style='margin-left: 40px'>Resolved bounds:
+ (${popup.screenX}, ${popup.screenY})
+ </div>`);
+ // Do not allow resolved placements to be clamped to the current screen.
+ checkPopupPlacement(popup, left, top, false);
+}
+
+promise_test(async setUpTest => {
+ await setUpWindowManagement(setUpTest, setUpButton);
+ const screenDetails = await getScreenDetails();
+ assert_true(!!screenDetails, 'Error getting screen details');
+ assert_greater_than(screenDetails.screens.length, 0, 'Connect a screen');
+ for (const s of screenDetails.screens) {
+ promise_test(async popupTest => {
+ await addTestTriggerButtonAndAwaitClick(popupButtons,
+ `Open a popup on '${s.label}'`,
+ popupTest);
+ await testPopupOnScreen(popupTest, s);
+ }, `Open a popup on '${s.label}'`);
+ }
+}, 'Use multi-screen details to open a popup window on each screen');
+</script>
diff --git a/testing/web-platform/tests/window-placement/resources/helpers.js b/testing/web-platform/tests/window-placement/resources/helpers.js
new file mode 100644
index 0000000000..f6acb54c26
--- /dev/null
+++ b/testing/web-platform/tests/window-placement/resources/helpers.js
@@ -0,0 +1,68 @@
+
+// Logs (appends) an HTML string to a logger element in a list format.
+// An element in the document with id "logger" will be used as the log
+// container.
+function log(str) {
+ const entry = document.createElement('li');
+ entry.innerHTML = str;
+ const loggerElement = document.getElementById('logger');
+ loggerElement.appendChild(entry);
+ return entry;
+}
+
+// Common setup for window management tests. Performs some basic assertions, and
+// then waits for a click on the `setUpButton` element (for manual tests).
+// Example usage:
+// promise_test(async setUpTest => {
+// await setUpWindowManagement(setUpTest, setUpButton);
+// ...
+// });
+async function setUpWindowManagement(setUpTest, setUpButton) {
+ assert_true(
+ 'getScreenDetails' in self && 'isExtended' in screen,
+ `API not supported; use Chromium (not content_shell) and enable
+ chrome://flags/#enable-experimental-web-platform-features`);
+ if (!screen.isExtended)
+ log(`WARNING: Use multiple screens for full test coverage`);
+ if (window.location.href.startsWith('file'))
+ log(`WARNING: Run via 'wpt serve'; file URLs lack permission support`);
+
+ try { // Support manual testing where test_driver is not running.
+ await test_driver.set_permission({ name: 'window-placement' }, 'granted');
+ } catch {
+ }
+ const setUpWatcher = new EventWatcher(setUpTest, setUpButton, ['click']);
+ const setUpClick = setUpWatcher.wait_for('click');
+ try { // Support manual testing where test_driver is not running.
+ await test_driver.click(setUpButton);
+ } catch {
+ }
+ await setUpClick;
+ setUpButton.disabled = true;
+}
+
+
+// Adds a button to the given `buttonContainer` element with the contents of
+// `name`. Attaches an event watcher to the given test and waits for a signal
+// from the test driver to click the button. If no test driver is available
+// (manual testing) then awaits an actual click from the user instead. If
+// `disableOnClick` is true, the button will also be disabled after it is
+// clicked.
+async function addTestTriggerButtonAndAwaitClick(buttonContainer, name, test) {
+ const button = document.createElement('button');
+ button.innerHTML = name;
+ const entry = document.createElement('li');
+ entry.appendChild(button);
+ buttonContainer.appendChild(entry);
+ const testWatcher = new EventWatcher(test, button, ['click']);
+ const buttonClick = testWatcher.wait_for('click');
+ // Disable the button when it is clicked.
+ button.onclick = function() {
+ button.disabled = true;
+ };
+ try { // Support manual testing where test_driver is not running.
+ await test_driver.click(button);
+ } catch {
+ }
+ await buttonClick;
+}