tor-browser

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

raf-loop.html (4117B)


      1 <!doctype html>
      2 <meta charset="utf-8" />
      3 <title>
      4  Largest Contentful Paint after soft navigation: requestAnimationFrame can add additional LCP
      5  entry.
      6 </title>
      7 <script src="/resources/testharness.js"></script>
      8 <script src="/resources/testharnessreport.js"></script>
      9 <script src="/resources/testdriver.js"></script>
     10 <script src="/resources/testdriver-vendor.js"></script>
     11 <script src="/soft-navigation-heuristics/resources/soft-navigation-test-helper.js"></script>
     12 <body>
     13  <button id="click-target" onclick="clickHandler()">Click!</button>
     14 </body>
     15 <script>
     16  // The click handler uses a RAF (requestAnimationFrame) loop to defer work, which
     17  // ultimately causes as second (and larger) soft LCP entry to be added.
     18  // The termination condition for the RAF loop is that the first soft LCP entry
     19  // (from clickHandler) has been observed. So, this example guarantees that
     20  // there are two soft LCP entries.
     21  //
     22  // Note: This test could become brittle if performance observer tasks were
     23  // deprioritized by the scheduler, while RAF loop iterations were to run
     24  // back-to-back; in that case, adding a setTimeout or scheduler.yield into the
     25  // RAF loop may become necessary.
     26  // See shaseley's comment on crrev.com/c/6658297.
     27  function clickHandler() {
     28    let smallLcpIssued = false;
     29 
     30    new PerformanceObserver((list, observer) => {
     31      if (list.getEntries().some((e) => e.id === "small-lcp")) {
     32        smallLcpIssued = true;
     33        observer.disconnect();
     34      }
     35    }).observe({ type: "interaction-contentful-paint" });
     36 
     37    document.body.innerHTML = `
     38          <div id='small-lcp'>Hello, world.</div>
     39        `;
     40    history.pushState({}, "", "/test");
     41 
     42    function rafLoop() {
     43      if (smallLcpIssued) {
     44        const div = document.createElement("div");
     45        div.innerHTML = "The quick brown fox jumps over the lazy dog.";
     46        div.id = "large-lcp";
     47        document.body.appendChild(div);
     48      } else {
     49        requestAnimationFrame(rafLoop);
     50      }
     51    }
     52    rafLoop();
     53  }
     54 
     55  promise_test(async (t) => {
     56    assert_implements(window.LargestContentfulPaint, "LargestContentfulPaint is not implemented");
     57    const helper = new SoftNavigationTestHelper(t);
     58    const lcpEntries =
     59        await helper.getBufferedPerformanceEntriesWithTimeout("largest-contentful-paint");
     60    assert_equals(lcpEntries.length, 1, "There should be only one LCP entry");
     61    assert_equals(lcpEntries[0].id, "click-target", "The first entry should be the button");
     62 
     63    const promise = Promise.all([
     64      SoftNavigationTestHelper.getPerformanceEntries("soft-navigation"),
     65      SoftNavigationTestHelper.getPerformanceEntries(
     66        "interaction-contentful-paint",
     67        /*minNumEntries=*/ 2,
     68      ),
     69    ]);
     70    if (test_driver) {
     71      test_driver.click(document.getElementById("click-target"));
     72    }
     73    const [softNavigationEntries, softLcpEntries] = await promise;
     74    assert_equals(
     75      softNavigationEntries.length,
     76      1,
     77      "There should be only one soft navigation entry",
     78    );
     79    assert_equals(softLcpEntries.length, 2, "There should be two soft LCP entries");
     80    assert_equals(
     81      softLcpEntries[0].id,
     82      "small-lcp",
     83      "The first soft LCP entry should be the small text",
     84    );
     85    assert_equals(
     86      softLcpEntries[1].id,
     87      "large-lcp",
     88      "The second soft LCP entry should be the large text",
     89    );
     90    assert_equals(
     91      softNavigationEntries[0].navigationId,
     92      softLcpEntries[0].navigationId,
     93      "The soft navigation entry should have the same navigation ID as the first soft LCP entry",
     94    );
     95    assert_equals(
     96      softNavigationEntries[0].navigationId,
     97      softLcpEntries[1].navigationId,
     98      "The soft navigation entry should have the same navigation ID as the second soft LCP entry",
     99    );
    100    assert_not_equals(
    101      lcpEntries[0].navigationId,
    102      softNavigationEntries[0].navigationId,
    103      "The soft navigation entry should have a different navigation ID than the initial (hard) LCP entry",
    104    );
    105  }, "Largest Contentful Paint after soft navigation: requestAnimationFrame can add additional LCP entry.");
    106 </script>