diff options
Diffstat (limited to 'layout/base/tests/test_scroll_per_page.html')
-rw-r--r-- | layout/base/tests/test_scroll_per_page.html | 247 |
1 files changed, 247 insertions, 0 deletions
diff --git a/layout/base/tests/test_scroll_per_page.html b/layout/base/tests/test_scroll_per_page.html new file mode 100644 index 0000000000..dc8faef893 --- /dev/null +++ b/layout/base/tests/test_scroll_per_page.html @@ -0,0 +1,247 @@ +<!DOCTYPE html> +<html> +<head> + <title>Test for scroll per page</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <script type="text/javascript" src="/tests/gfx/layers/apz/test/mochitest/apz_test_utils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> + +<pre id="test"> +<script class="testbody" type="text/javascript"> +SimpleTest.waitForExplicitFinish(); +addLoadEvent(() => { + open("window_empty_document.html", "_blank", "width=500,height=500,scrollbars=yes"); +}); + +async function doTests(aWindow) { + const IS_WIN = navigator.platform.includes("Win"); + // On macOS and Linux, PageUp/PageDown requires native event to resolve + // default action of PageDown and PageUp. Although macOS widget has + // nsIWidget::AttachNativeKeyEvent(), we cannot use synthesizeKey() for the + // following tests. So, use nsISelectionController.pageMove() instead on + // non-Windows platforms. + const kUseKeyboardEvent = IS_WIN; + let selectionController; + if (!kUseKeyboardEvent) { + selectionController = SpecialPowers.wrap(aWindow) + .docShell + .QueryInterface(SpecialPowers.Ci.nsIInterfaceRequestor) + .getInterface(SpecialPowers.Ci.nsISelectionDisplay) + .QueryInterface(SpecialPowers.Ci.nsISelectionController); + } + + await SpecialPowers.pushPrefEnv({"set": [["general.smoothScroll", false]]}); + await SimpleTest.promiseFocus(aWindow); + + function getNodeDescription(aNode) { + function getElementDescription(aElement) { + if (aElement.getAttribute("id") !== null) { + return `${aElement.tagName.toLowerCase()}#${aElement.getAttribute("id")}`; + } + if (aElement.tagName === "BR") { + return `${getElementDescription(aElement.previousSibling)} + br`; + } + return aElement.tagName.toLowerCase(); + } + switch (aNode.nodeType) { + case aNode.TEXT_NODE: + return `text node in ${getElementDescription(aNode.parentElement)}`; + case aNode.ELEMENT_NODE: + return getElementDescription(aNode); + default: + return "unknown node"; + } + } + + function waitForScrollEvent() { + return new Promise(resolve => { + aWindow.addEventListener("scroll", () => { SimpleTest.executeSoon(resolve); }, {once: true, capture: true}); + }); + } + + async function doPageDown() { + let waitForScrolling = waitForScrollEvent(); + if (kUseKeyboardEvent) { + synthesizeKey("KEY_PageDown", {}, aWindow); + } else { + selectionController.pageMove(true, false); + } + await waitForScrolling; + } + + async function doPageUp() { + let waitForScrolling = waitForScrollEvent(); + if (kUseKeyboardEvent) { + synthesizeKey("KEY_PageUp", {}, aWindow); + } else { + selectionController.pageMove(false, false); + } + await waitForScrolling; + } + + let doc = aWindow.document; + let body = doc.body; + let selection = doc.getSelection(); + let container; + + body.innerHTML = '<div id="largeDiv" style="height: 1500px;">' + + "<p>previous line of the editor.</p>" + + '<div id="editor" contenteditable style="margin-top 500px; height: 5em; overflow: auto;">' + + "Here is first line<br>" + + "Here is second line" + + "</div>" + + "<p>next line of the editor.</p>" + + "</div>"; + container = doc.documentElement; + let editor = doc.getElementById("editor"); + editor.focus(); + await waitToClearOutAnyPotentialScrolls(aWindow); + + let description = "PageDown in non-scrollable editing host: "; + let previousScrollTop = container.scrollTop; + await doPageDown(); + ok(container.scrollTop > previousScrollTop, + `${description}the document should be scrolled down even if user presses PageDown in the editing host got: ${container.scrollTop}, previous position: ${previousScrollTop}`); + let range = selection.getRangeAt(0); + is(range.startContainer, editor.firstChild.nextSibling.nextSibling, + `${description}selection start shouldn't be moved to outside of the editing host (got: ${getNodeDescription(range.startContainer)})`); + ok(range.collapsed, description + "selection should be collapsed"); + is(doc.activeElement, editor, + description + "the editing host should keep having focus"); + + description = "PageUp in non-scrollable editing host: "; + previousScrollTop = container.scrollTop; + await doPageUp(); + ok(container.scrollTop < previousScrollTop, + `${description}the document should be scrolled up even if user presses PageDown in the editing host got: ${container.scrollTop}, previous position: ${previousScrollTop}`); + range = selection.getRangeAt(0); + is(range.startContainer, editor.firstChild, + `${description}selection start shouldn't be moved to outside of the editing host (got: ${getNodeDescription(range.startContainer)})`); + ok(range.collapsed, description + "selection should be collapsed"); + is(doc.activeElement, editor, + description + "the editing host should keep having focus"); + + body.innerHTML = '<div id="largeDiv" style="height: 1500px;">' + + "<p>previous line of the editor.</p>" + + '<div id="editor" contenteditable style="margin-top 500px; height: 5em; overflow: auto;">' + + '<div id="innerDiv" style="height: 10em;">' + + "Here is first line<br>" + + "Here is second line" + + "</div>" + + "</div>" + + "<p>next line of the editor.</p>" + + "</div>"; + editor = doc.getElementById("editor"); + container = editor; + editor.focus(); + await waitToClearOutAnyPotentialScrolls(aWindow); + + description = "PageDown in scrollable editing host: "; + previousScrollTop = container.scrollTop; + await doPageDown(); + ok(container.scrollTop > previousScrollTop, + `${description}the editor should be scrolled down even if user presses PageDown in the editing host got: ${container.scrollTop}, previous position: ${previousScrollTop}`); + range = selection.getRangeAt(0); + is(range.startContainer, editor.firstChild.firstChild.nextSibling.nextSibling, + `${description}selection start shouldn't be moved to outside of the editing host (got: ${getNodeDescription(range.startContainer)})`); + ok(range.collapsed, description + "selection should be collapsed"); + is(doc.activeElement, editor, + description + "the editing host should keep having focus"); + + description = "PageUp in scrollable editing host: "; + previousScrollTop = container.scrollTop; + await doPageUp(); + ok(container.scrollTop < previousScrollTop, + `${description}the editor should be scrolled up even if user presses PageDown in the editing host got: ${container.scrollTop}, previous position: ${previousScrollTop}`); + range = selection.getRangeAt(0); + is(range.startContainer, editor.firstChild.firstChild, + `${description}selection start shouldn't be moved to outside of the editing host (got: ${getNodeDescription(range.startContainer)})`); + ok(range.collapsed, description + "selection should be collapsed"); + is(doc.activeElement, editor, + description + "the editing host should keep having focus"); + + // Should scroll one page of the scrollable element + body.innerHTML = `<div id="editor" contenteditable style="height: 1500px;">${"abc<br>".repeat(100)}</div>`; + editor = doc.getElementById("editor"); + container = doc.documentElement; + editor.focus(); + await waitToClearOutAnyPotentialScrolls(aWindow); + + description = "PageDown in too large editing host: "; + previousScrollTop = container.scrollTop; + await doPageDown(); + ok(container.scrollTop > previousScrollTop, + `${description} The document should be scrolled down (got: ${container.scrollTop}, previous position: ${previousScrollTop})`); + ok(container.scrollTop <= previousScrollTop + container.clientHeight, + `${description} The document should not be scrolled down too much (got: ${container.scrollTop}, previous position: ${previousScrollTop}, scroll height: ${container.clientHeight})`); + + selection.selectAllChildren(editor); + selection.collapseToEnd(); + await waitToClearOutAnyPotentialScrolls(aWindow); + + description = "PageUp in too large editing host: "; + container.scrollTop = container.scrollHeight; + previousScrollTop = container.scrollTop; + await doPageUp(); + ok(container.scrollTop >= previousScrollTop - container.clientHeight, + `${description} The document should not be scrolled up too much (got: ${container.scrollTop}, previous position: ${previousScrollTop}, scroll height: ${container.clientHeight})`); + + // Shouldn't scroll to caret position after pagedown scrolls editing host. + body.innerHTML = '<div id="editor" contenteditable style="height: 300px; overflow: auto;"><div style="height: 1500px;">abc<br>def<br></div></div>'; + editor = doc.getElementById("editor"); + container = editor; + editor.focus(); + await waitToClearOutAnyPotentialScrolls(aWindow); + + description = "PageDown in scrollable editing host"; + previousScrollTop = container.scrollTop; + await doPageDown(); + ok(container.scrollTop > previousScrollTop, + `${description} #1: Should be scrolled down (got: ${container.scrollTop}, previous position: ${previousScrollTop})`); + previousScrollTop = container.scrollTop; + await doPageDown(); + ok(container.scrollTop > previousScrollTop, + `${description} #2: should be scrolled down (got:${container.scrollTop}, previous position: ${previousScrollTop})`); + previousScrollTop = container.scrollTop; + await doPageDown(); + ok(container.scrollTop > previousScrollTop, + `${description} #3: should be scrolled down (got:${container.scrollTop}, previous position: ${previousScrollTop})`); + await doPageUp(); + ok(container.scrollTop < 300, + `PageUp in scrollable editing host after scrolled down 3 pages: should be scrolled up to show caret (got:${container.scrollTop}`); + + // Shouldn't scroll to caret position after pagedown scrolls outside of editing host. + // NOTE: We've set the window height is 500px above, but on Android, the viewport size depends on the screen size. + // Therefore, we need to compute enough height to test below with actual height of the window. + body.innerHTML = `<div id="editor" contenteditable style="height: ${aWindow.innerHeight * 3}px">abc<br>def<br></div>`; + editor = doc.getElementById("editor"); + container = doc.documentElement; + editor.focus(); + selection.collapse(editor.firstChild); + await waitToClearOutAnyPotentialScrolls(aWindow); + + description = "PageDown in too high non-scrollable editing host"; + previousScrollTop = container.scrollTop; + await doPageDown(); + ok(container.scrollTop > previousScrollTop, + `${description} #1: Should be scrolled down (got: ${container.scrollTop}, previous position: ${previousScrollTop})`); + previousScrollTop = container.scrollTop; + await doPageDown(); + ok(container.scrollTop > previousScrollTop, + `${description} #2: should be scrolled down (got:${container.scrollTop}, previous position: ${previousScrollTop})`); + previousScrollTop = container.scrollTop; + await doPageDown(); + ok(container.scrollTop > previousScrollTop, + `${description} #3: should be scrolled down (got:${container.scrollTop}, previous position: ${previousScrollTop})`); + await doPageUp(); + ok(container.scrollTop < 300, + `PageUp in too high non-scrollable editing host after scrolled down 3 pages: should be scrolled up to show caret (got:${container.scrollTop}`); + + aWindow.close(); + SimpleTest.finish(); +} +</script> +</html> |