tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

test_scroll_per_page.html (12286B)


      1 <!DOCTYPE html>
      2 <html>
      3 <head>
      4  <title>Test for scroll per page</title>
      5  <script src="/tests/SimpleTest/SimpleTest.js"></script>
      6  <script src="/tests/SimpleTest/EventUtils.js"></script>
      7  <script type="text/javascript" src="/tests/gfx/layers/apz/test/mochitest/apz_test_utils.js"></script>
      8  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
      9 </head>
     10 <body>
     11 
     12 <pre id="test">
     13 <script class="testbody" type="text/javascript">
     14 SimpleTest.waitForExplicitFinish();
     15 addLoadEvent(() => {
     16  open("window_empty_document.html", "_blank", "width=500,height=500,scrollbars=yes");
     17 });
     18 
     19 async function doTests(aWindow) {
     20  await SpecialPowers.pushPrefEnv({"set": [["general.smoothScroll", false]]});
     21  await SimpleTest.promiseFocus(aWindow);
     22 
     23  function getNodeDescription(aNode) {
     24    function getElementDescription(aElement) {
     25      if (aElement.getAttribute("id") !== null) {
     26        return `${aElement.tagName.toLowerCase()}#${aElement.getAttribute("id")}`;
     27      }
     28      if (aElement.tagName === "BR") {
     29        return `${getElementDescription(aElement.previousSibling)} + br`;
     30      }
     31      return aElement.tagName.toLowerCase();
     32    }
     33    switch (aNode.nodeType) {
     34      case aNode.TEXT_NODE:
     35        return `text node in ${getElementDescription(aNode.parentElement)}`;
     36      case aNode.ELEMENT_NODE:
     37        return getElementDescription(aNode);
     38      case aNode.DOCUMENT_NODE:
     39        return `document node`;
     40      default:
     41        return "unknown node";
     42    }
     43  }
     44 
     45  function getScrollPositionStr(aNode) {
     46    return `{ scrollTop: ${aNode.scrollTop}, scrollHeight: ${
     47      aNode.scrollHeight
     48    }, scrollLeft: ${aNode.scrollLeft}, scrollWidth: ${aNode.scrollWidth} }`;
     49  }
     50 
     51  async function doPageDownOrUp(aKey, aFocusedElement, aScrollTargetElement) {
     52    let scrollEventTarget =
     53      aScrollTargetElement === doc.documentElement
     54        ? doc
     55        : aScrollTargetElement;
     56    let scrollEventFired = false;
     57    function onScroll(aEvent) {
     58      scrollEventFired |= aEvent.target === scrollEventTarget;
     59    }
     60    scrollEventTarget.addEventListener("scroll", onScroll);
     61    if (!navigator.platform.includes("Mac")) {
     62      synthesizeKey(`KEY_${aKey}`, {}, aWindow);
     63    } else {
     64      synthesizeKey(`KEY_${aKey}`, { altKey: true }, aWindow);
     65    }
     66    let retry = 3;
     67    while (retry--) {
     68      await waitToClearOutAnyPotentialScrolls(aWindow);
     69      if (scrollEventFired) {
     70        break;
     71      }
     72    }
     73    ok(scrollEventFired,
     74      `Scroll event should've been fired on ${getNodeDescription(scrollEventTarget)}`);
     75    scrollEventTarget.removeEventListener("scroll", onScroll);
     76  }
     77 
     78  async function doPageDown(aFocusedElement, aScrollTargetElement) {
     79    await doPageDownOrUp("PageDown", aFocusedElement, aScrollTargetElement);
     80  }
     81 
     82  async function doPageUp(aFocusedElement, aScrollTargetElement) {
     83    await doPageDownOrUp("PageUp", aFocusedElement, aScrollTargetElement);
     84  }
     85 
     86  // Let's put log of scroll events for making debug this test easier.
     87  aWindow.addEventListener("scroll", (aEvent) => {
     88    let scrollElement =
     89      aEvent.target === doc
     90        ? doc.documentElement
     91        : aEvent.target;
     92    info(`"scroll" event fired on ${getNodeDescription(aEvent.target)}: ${
     93      getScrollPositionStr(scrollElement)
     94    }`);
     95  }, { capture: true });
     96 
     97  let doc = aWindow.document;
     98  let body = doc.body;
     99  let selection = doc.getSelection();
    100  let container;
    101 
    102  body.innerHTML = '<div id="largeDiv" style="height: 1500px;">' +
    103                   "<p>previous line of the editor.</p>" +
    104                   '<div id="editor" contenteditable style="margin-top 500px; height: 5em; overflow: auto;">' +
    105                   "Here is first line<br>" +
    106                   "Here is second line" +
    107                   "</div>" +
    108                   "<p>next line of the editor.</p>" +
    109                   "</div>";
    110  container = doc.documentElement;
    111  let editor = doc.getElementById("editor");
    112  editor.focus();
    113  await waitToClearOutAnyPotentialScrolls(aWindow);
    114 
    115  let description = "PageDown in non-scrollable editing host: ";
    116  let previousScrollTop = container.scrollTop;
    117  await doPageDown(editor, container);
    118  ok(container.scrollTop > previousScrollTop,
    119     `${description}the document should be scrolled down even if user presses PageDown in the editing host got: ${container.scrollTop}, previous position: ${previousScrollTop}`);
    120  let range = selection.getRangeAt(0);
    121  is(range.startContainer, editor.firstChild.nextSibling.nextSibling,
    122     `${description}selection start shouldn't be moved to outside of the editing host (got: ${getNodeDescription(range.startContainer)})`);
    123  ok(range.collapsed, description + "selection should be collapsed");
    124  is(doc.activeElement, editor,
    125     description + "the editing host should keep having focus");
    126 
    127  description = "PageUp in non-scrollable editing host: ";
    128  previousScrollTop = container.scrollTop;
    129  await doPageUp(editor, container);
    130  ok(container.scrollTop < previousScrollTop,
    131     `${description}the document should be scrolled up even if user presses PageDown in the editing host got: ${container.scrollTop}, previous position: ${previousScrollTop}`);
    132  range = selection.getRangeAt(0);
    133  is(range.startContainer, editor.firstChild,
    134     `${description}selection start shouldn't be moved to outside of the editing host (got: ${getNodeDescription(range.startContainer)})`);
    135  ok(range.collapsed, description + "selection should be collapsed");
    136  is(doc.activeElement, editor,
    137     description + "the editing host should keep having focus");
    138 
    139  body.innerHTML = '<div id="largeDiv" style="height: 1500px;">' +
    140                   "<p>previous line of the editor.</p>" +
    141                   '<div id="editor" contenteditable style="margin-top 500px; height: 5em; overflow: auto;">' +
    142                   '<div id="innerDiv" style="height: 10em;">' +
    143                   "Here is first line<br>" +
    144                   "Here is second line" +
    145                   "</div>" +
    146                   "</div>" +
    147                   "<p>next line of the editor.</p>" +
    148                   "</div>";
    149  editor = doc.getElementById("editor");
    150  container = editor;
    151  editor.focus();
    152  await waitToClearOutAnyPotentialScrolls(aWindow);
    153 
    154  description = "PageDown in scrollable editing host: ";
    155  previousScrollTop = container.scrollTop;
    156  await doPageDown(editor, container);
    157  ok(container.scrollTop > previousScrollTop,
    158     `${description}the editor should be scrolled down even if user presses PageDown in the editing host got: ${container.scrollTop}, previous position: ${previousScrollTop}`);
    159  range = selection.getRangeAt(0);
    160  is(range.startContainer, editor.firstChild.firstChild.nextSibling.nextSibling,
    161     `${description}selection start shouldn't be moved to outside of the editing host (got: ${getNodeDescription(range.startContainer)})`);
    162  ok(range.collapsed, description + "selection should be collapsed");
    163  is(doc.activeElement, editor,
    164     description + "the editing host should keep having focus");
    165 
    166  description = "PageUp in scrollable editing host: ";
    167  previousScrollTop = container.scrollTop;
    168  await doPageUp(editor, container);
    169  ok(container.scrollTop < previousScrollTop,
    170     `${description}the editor should be scrolled up even if user presses PageDown in the editing host got: ${container.scrollTop}, previous position: ${previousScrollTop}`);
    171  range = selection.getRangeAt(0);
    172  is(range.startContainer, editor.firstChild.firstChild,
    173     `${description}selection start shouldn't be moved to outside of the editing host (got: ${getNodeDescription(range.startContainer)})`);
    174  ok(range.collapsed, description + "selection should be collapsed");
    175  is(doc.activeElement, editor,
    176     description + "the editing host should keep having focus");
    177 
    178  // Should scroll one page of the scrollable element
    179  body.innerHTML = `<div id="editor" contenteditable style="height: 1500px;">${"abc<br>".repeat(100)}</div>`;
    180  editor = doc.getElementById("editor");
    181  container = doc.documentElement;
    182  editor.focus();
    183  await waitToClearOutAnyPotentialScrolls(aWindow);
    184 
    185  description = "PageDown in too large editing host: ";
    186  previousScrollTop = container.scrollTop;
    187  await doPageDown(editor, container);
    188  ok(container.scrollTop > previousScrollTop,
    189     `${description} The document should be scrolled down (got: ${container.scrollTop}, previous position: ${previousScrollTop})`);
    190  ok(container.scrollTop <= previousScrollTop + container.clientHeight,
    191     `${description} The document should not be scrolled down too much (got: ${container.scrollTop}, previous position: ${previousScrollTop}, scroll height: ${container.clientHeight})`);
    192 
    193  selection.selectAllChildren(editor);
    194  selection.collapseToEnd();
    195  await waitToClearOutAnyPotentialScrolls(aWindow);
    196 
    197  description = "PageUp in too large editing host: ";
    198  container.scrollTop = container.scrollHeight;
    199  previousScrollTop = container.scrollTop;
    200  await doPageUp(editor, container);
    201  ok(container.scrollTop >= previousScrollTop - container.clientHeight,
    202     `${description} The document should not be scrolled up too much (got: ${container.scrollTop}, previous position: ${previousScrollTop}, scroll height: ${container.clientHeight})`);
    203 
    204  // Shouldn't scroll to caret position after pagedown scrolls editing host.
    205  body.innerHTML = '<div id="editor" contenteditable style="height: 300px; overflow: auto;"><div style="height: 1500px;">abc<br>def<br></div></div>';
    206  editor = doc.getElementById("editor");
    207  container = editor;
    208  editor.focus();
    209  await waitToClearOutAnyPotentialScrolls(aWindow);
    210 
    211  description = "PageDown in scrollable editing host";
    212  previousScrollTop = container.scrollTop;
    213  await doPageDown(editor, container);
    214  ok(container.scrollTop > previousScrollTop,
    215     `${description} #1: Should be scrolled down (got: ${container.scrollTop}, previous position: ${previousScrollTop})`);
    216  previousScrollTop = container.scrollTop;
    217  await doPageDown(editor, container);
    218  ok(container.scrollTop > previousScrollTop,
    219     `${description} #2: should be scrolled down (got:${container.scrollTop}, previous position: ${previousScrollTop})`);
    220  previousScrollTop = container.scrollTop;
    221  await doPageDown(editor, container);
    222  ok(container.scrollTop > previousScrollTop,
    223     `${description} #3: should be scrolled down (got:${container.scrollTop}, previous position: ${previousScrollTop})`);
    224  await doPageUp(editor, container);
    225  ok(container.scrollTop < 300,
    226     `PageUp in scrollable editing host after scrolled down 3 pages: should be scrolled up to show caret (got:${container.scrollTop}`);
    227 
    228  // Shouldn't scroll to caret position after pagedown scrolls outside of editing host.
    229  // NOTE: We've set the window height is 500px above, but on Android, the viewport size depends on the screen size.
    230  //       Therefore, we need to compute enough height to test below with actual height of the window.
    231  body.innerHTML = `<div id="editor" contenteditable style="height: ${aWindow.innerHeight * 3}px">abc<br>def<br></div>`;
    232  editor = doc.getElementById("editor");
    233  container = doc.documentElement;
    234  editor.focus();
    235  selection.collapse(editor.firstChild);
    236  await waitToClearOutAnyPotentialScrolls(aWindow);
    237 
    238  description = "PageDown in too high non-scrollable editing host";
    239  previousScrollTop = container.scrollTop;
    240  await doPageDown(editor, container);
    241  ok(container.scrollTop > previousScrollTop,
    242     `${description} #1: Should be scrolled down (got: ${container.scrollTop}, previous position: ${previousScrollTop})`);
    243  previousScrollTop = container.scrollTop;
    244  await doPageDown(editor, container);
    245  ok(container.scrollTop > previousScrollTop,
    246     `${description} #2: should be scrolled down (got:${container.scrollTop}, previous position: ${previousScrollTop})`);
    247  previousScrollTop = container.scrollTop;
    248  await doPageDown(editor, container);
    249  ok(container.scrollTop > previousScrollTop,
    250     `${description} #3: should be scrolled down (got:${container.scrollTop}, previous position: ${previousScrollTop})`);
    251  await doPageUp(editor, container);
    252  ok(container.scrollTop < 300,
    253     `PageUp in too high non-scrollable editing host after scrolled down 3 pages: should be scrolled up to show caret (got:${container.scrollTop}`);
    254 
    255  aWindow.close();
    256  SimpleTest.finish();
    257 }
    258 </script>
    259 </html>