diff options
Diffstat (limited to 'dom/events/test/test_scroll_per_page.html')
-rw-r--r-- | dom/events/test/test_scroll_per_page.html | 259 |
1 files changed, 259 insertions, 0 deletions
diff --git a/dom/events/test/test_scroll_per_page.html b/dom/events/test/test_scroll_per_page.html new file mode 100644 index 0000000000..8d464b1a43 --- /dev/null +++ b/dom/events/test/test_scroll_per_page.html @@ -0,0 +1,259 @@ +<!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) { + 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); + case aNode.DOCUMENT_NODE: + return `document node`; + default: + return "unknown node"; + } + } + + function getScrollPositionStr(aNode) { + return `{ scrollTop: ${aNode.scrollTop}, scrollHeight: ${ + aNode.scrollHeight + }, scrollLeft: ${aNode.scrollLeft}, scrollWidth: ${aNode.scrollWidth} }`; + } + + async function doPageDownOrUp(aKey, aFocusedElement, aScrollTargetElement) { + let scrollEventTarget = + aScrollTargetElement === doc.documentElement + ? doc + : aScrollTargetElement; + let scrollEventFired = false; + function onScroll(aEvent) { + scrollEventFired |= aEvent.target === scrollEventTarget; + } + scrollEventTarget.addEventListener("scroll", onScroll); + if (!navigator.platform.includes("Mac")) { + synthesizeKey(`KEY_${aKey}`, {}, aWindow); + } else { + synthesizeKey(`KEY_${aKey}`, { altKey: true }, aWindow); + } + let retry = 3; + while (retry--) { + await waitToClearOutAnyPotentialScrolls(aWindow); + if (scrollEventFired) { + break; + } + } + ok(scrollEventFired, + `Scroll event should've been fired on ${getNodeDescription(scrollEventTarget)}`); + scrollEventTarget.removeEventListener("scroll", onScroll); + } + + async function doPageDown(aFocusedElement, aScrollTargetElement) { + await doPageDownOrUp("PageDown", aFocusedElement, aScrollTargetElement); + } + + async function doPageUp(aFocusedElement, aScrollTargetElement) { + await doPageDownOrUp("PageUp", aFocusedElement, aScrollTargetElement); + } + + // Let's put log of scroll events for making debug this test easier. + aWindow.addEventListener("scroll", (aEvent) => { + let scrollElement = + aEvent.target === doc + ? doc.documentElement + : aEvent.target; + info(`"scroll" event fired on ${getNodeDescription(aEvent.target)}: ${ + getScrollPositionStr(scrollElement) + }`); + }, { capture: true }); + + 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(editor, container); + 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(editor, container); + 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(editor, container); + 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(editor, container); + 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(editor, container); + 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(editor, container); + 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(editor, container); + ok(container.scrollTop > previousScrollTop, + `${description} #1: Should be scrolled down (got: ${container.scrollTop}, previous position: ${previousScrollTop})`); + previousScrollTop = container.scrollTop; + await doPageDown(editor, container); + ok(container.scrollTop > previousScrollTop, + `${description} #2: should be scrolled down (got:${container.scrollTop}, previous position: ${previousScrollTop})`); + previousScrollTop = container.scrollTop; + await doPageDown(editor, container); + ok(container.scrollTop > previousScrollTop, + `${description} #3: should be scrolled down (got:${container.scrollTop}, previous position: ${previousScrollTop})`); + await doPageUp(editor, container); + 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(editor, container); + ok(container.scrollTop > previousScrollTop, + `${description} #1: Should be scrolled down (got: ${container.scrollTop}, previous position: ${previousScrollTop})`); + previousScrollTop = container.scrollTop; + await doPageDown(editor, container); + ok(container.scrollTop > previousScrollTop, + `${description} #2: should be scrolled down (got:${container.scrollTop}, previous position: ${previousScrollTop})`); + previousScrollTop = container.scrollTop; + await doPageDown(editor, container); + ok(container.scrollTop > previousScrollTop, + `${description} #3: should be scrolled down (got:${container.scrollTop}, previous position: ${previousScrollTop})`); + await doPageUp(editor, container); + 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> |