tor-browser

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

browser_dbg-preview-moving-token.js (5722B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
      4 
      5 // Test the debugger preview popup when moving from one token to another.
      6 
      7 "use strict";
      8 
      9 add_task(async function () {
     10  const dbg = await initDebugger("doc-preview.html", "preview.js");
     11 
     12  await selectSource(dbg, "preview.js");
     13 
     14  info(
     15    "Check that moving the mouse to another token when popup is displayed updates highlighted token and popup position"
     16  );
     17  invokeInTab("classPreview");
     18  await waitForPaused(dbg);
     19 
     20  // Scroll one line *fore* the hovered expression to guarantee showing the line entirely.
     21  // It may not scroll if the line 50 is partially visible.
     22  //
     23  // Also ensure scrolling so that the scrolled line is at the top/start of the viewport
     24  // so that the preview popup can be shown at the bottom of the token and not on its right.
     25  await scrollEditorIntoView(dbg, 49, 0, "start");
     26 
     27  // Wait for all the updates to the document to complete to make all
     28  // token elements have been rendered
     29  await waitForDocumentLoadComplete(dbg);
     30 
     31  info("Hover token `Foo` in `Foo.#privateStatic` expression");
     32  const fooTokenEl = await getTokenElAtLine(dbg, "Foo", 50, 44);
     33  const { element: fooPopupEl } = await tryHoverToken(dbg, fooTokenEl, "popup");
     34  ok(!!fooPopupEl, "popup is displayed");
     35  ok(
     36    fooTokenEl.classList.contains("preview-token"),
     37    "`Foo` token is highlighted"
     38  );
     39 
     40  // store original position
     41  const originalPopupPosition = fooPopupEl.getBoundingClientRect().x;
     42 
     43  info(
     44    "Move mouse over the `#privateStatic` token in `Foo.#privateStatic` expression"
     45  );
     46  const privateStaticTokenEl = await getTokenElAtLine(
     47    dbg,
     48    "#privateStatic",
     49    50,
     50    48
     51  );
     52 
     53  // The sequence of event to trigger the bug this is covering isn't easily reproducible
     54  // by firing a few chosen events (because of React async rendering), so we are going to
     55  // mimick moving the mouse from the `Foo` to `#privateStatic` in a given amount of time
     56 
     57  // So get all the different token quads to compute their center
     58  const fooTokenQuad = fooTokenEl.getBoxQuads()[0];
     59  const privateStaticTokenQuad = privateStaticTokenEl.getBoxQuads()[0];
     60  const fooXCenter =
     61    fooTokenQuad.p1.x + (fooTokenQuad.p2.x - fooTokenQuad.p1.x) / 2;
     62  const fooYCenter =
     63    fooTokenQuad.p1.y + (fooTokenQuad.p3.y - fooTokenQuad.p1.y) / 2;
     64  const privateStaticXCenter =
     65    privateStaticTokenQuad.p1.x +
     66    (privateStaticTokenQuad.p2.x - privateStaticTokenQuad.p1.x) / 2;
     67  const privateStaticYCenter =
     68    privateStaticTokenQuad.p1.y +
     69    (privateStaticTokenQuad.p3.y - privateStaticTokenQuad.p1.y) / 2;
     70 
     71  // we can then compute the distance to cover between the two token centers
     72  const xDistance = privateStaticXCenter - fooXCenter;
     73  const yDistance = privateStaticYCenter - fooYCenter;
     74  const movementDuration = 50;
     75  const xIncrements = xDistance / movementDuration;
     76  const yIncrements = yDistance / movementDuration;
     77 
     78  // Finally, we're going to fire a mouseover event every ms
     79  info("Move mousecursor between the `Foo` token to the `#privateStatic` one");
     80  for (let i = 0; i < movementDuration; i++) {
     81    const x = fooXCenter + (yDistance + i * xIncrements);
     82    const y = fooYCenter + (yDistance + i * yIncrements);
     83    EventUtils.synthesizeMouseAtPoint(
     84      x,
     85      y,
     86      {
     87        type: "mouseover",
     88      },
     89      fooTokenEl.ownerGlobal
     90    );
     91    await wait(1);
     92  }
     93 
     94  info("Wait for the popup to display the data for `#privateStatic`");
     95  await waitFor(() => {
     96    const popup = findElement(dbg, "popup");
     97    if (!popup) {
     98      return false;
     99    }
    100    // for `Foo`, the header text content is "Foo", so when it's "Object", we know the
    101    // popup was updated
    102    return (
    103      popup.querySelector(".preview-popup .node .objectBox")?.textContent ===
    104      "Object"
    105    );
    106  });
    107  ok(true, "Popup is displayed for #privateStatic");
    108 
    109  ok(
    110    !fooTokenEl.classList.contains("preview-token"),
    111    "`Foo` token is not highlighted anymore"
    112  );
    113  ok(
    114    privateStaticTokenEl.classList.contains("preview-token"),
    115    "`#privateStatic` token is highlighted"
    116  );
    117 
    118  const privateStaticPopupEl = await waitForElement(dbg, "popup");
    119  const newPopupPosition = privateStaticPopupEl.getBoundingClientRect().x;
    120  isnot(
    121    Math.round(newPopupPosition),
    122    Math.round(originalPopupPosition),
    123    `Popup position was updated`
    124  );
    125 
    126  // Move many times between a token, its gap and then outside to hide it many times
    127  // to highlight any potential race condition.
    128  for (let i = 0; i < 10; i++) {
    129    info(
    130      `Move out by passing over the gap, before going on the right of the token to hide the preview (try #${i + 1})`
    131    );
    132    EventUtils.synthesizeMouseAtCenter(
    133      privateStaticPopupEl.querySelector(".gap"),
    134      { type: "mousemove" },
    135      privateStaticPopupEl.ownerGlobal
    136    );
    137    EventUtils.synthesizeMouseAtPoint(
    138      privateStaticTokenQuad.p2.x + 100,
    139      privateStaticYCenter,
    140      {
    141        type: "mousemove",
    142      },
    143      fooTokenEl.ownerGlobal
    144    );
    145    info("Wait for popup to be hidden when going right");
    146    await waitUntil(() => findElement(dbg, "popup") == null);
    147 
    148    info("Move back in the center of the token to show the preview again");
    149    EventUtils.synthesizeMouseAtPoint(
    150      privateStaticXCenter,
    151      privateStaticYCenter,
    152      {
    153        type: "mousemove",
    154      },
    155      fooTokenEl.ownerGlobal
    156    );
    157    info("Wait for popup to be shown on private field again");
    158    await waitUntil(() => !!findElement(dbg, "popup"));
    159  }
    160 
    161  await closePreviewForToken(dbg, privateStaticTokenEl, "popup");
    162  await resume(dbg);
    163 });