Source code

Revision control

Copy as Markdown

Other Tools

Test Info: Warnings

<!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>