tor-browser

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

browser_inspector_inspect_loading_document.js (5564B)


      1 /* Any copyright is dedicated to the Public Domain.
      2 http://creativecommons.org/publicdomain/zero/1.0/ */
      3 
      4 "use strict";
      5 
      6 // Fix blank inspector bug when opening DevTools on a webpage with a document
      7 // where document.write is called without ever calling document.close.
      8 // Such a document remains forever in the "loading" readyState. See Bug 1765760.
      9 
     10 const TEST_URL =
     11  `data:text/html;charset=utf-8,` +
     12  encodeURIComponent(`
     13  <!DOCTYPE html>
     14  <html lang="en">
     15    <body>
     16      <div id=outsideframe></div>
     17      <script type="text/javascript">
     18        const iframe = document.createElement("iframe");
     19        iframe.src = "about:blank";
     20        iframe.addEventListener('load', () => {
     21          iframe.contentDocument.write('<div id=inframe>inframe</div>');
     22        }, true);
     23        document.body.appendChild(iframe);
     24      </script>
     25    </body>
     26  </html>
     27 `);
     28 
     29 add_task(async function testSlowLoadingFrame() {
     30  const loadingTab = BrowserTestUtils.addTab(gBrowser, TEST_URL);
     31  gBrowser.selectedTab = loadingTab;
     32 
     33  // Note: we cannot use `await addTab` here because the iframe never finishes
     34  // loading. But we still want to wait for the frame to reach the loading state
     35  // and to display a test element so that we can reproduce the initial issue
     36  // fixed by Bug 1765760.
     37  info("Wait for the loading iframe to be ready to test");
     38  await TestUtils.waitForCondition(async () => {
     39    try {
     40      return await ContentTask.spawn(gBrowser.selectedBrowser, {}, () => {
     41        const iframe = content.document.querySelector("iframe");
     42        return (
     43          iframe?.contentDocument.readyState === "loading" &&
     44          iframe.contentDocument.getElementById("inframe")
     45        );
     46      });
     47    } catch (e) {
     48      return false;
     49    }
     50  });
     51 
     52  const { inspector } = await openInspector();
     53 
     54  info("Check the markup view displays the loading iframe successfully");
     55  await assertMarkupViewAsTree(
     56    `
     57    body
     58      div id="outsideframe"
     59      script!ignore-children
     60      iframe
     61        #document
     62          html
     63            head
     64            body
     65              div id="inframe"`,
     66    "body",
     67    inspector
     68  );
     69 });
     70 
     71 add_task(async function testSlowLoadingDocument() {
     72  info("Create a test server serving a slow document");
     73  const httpServer = createTestHTTPServer();
     74  httpServer.registerContentType("html", "text/html");
     75 
     76  // This promise allows to block serving the complete document from the test.
     77  let unblockRequest;
     78  const onRequestUnblocked = new Promise(r => (unblockRequest = r));
     79 
     80  httpServer.registerPathHandler(`/`, async function (request, response) {
     81    response.processAsync();
     82    response.setStatusLine(request.httpVersion, 200, "OK");
     83 
     84    // Split the page content in 2 parts:
     85    // - opening body tag and the "#start" div will be returned immediately
     86    // - "#end" div and closing body tag are blocked on a promise.
     87    const page_start = "<body><div id='start'>start</div>";
     88    const page_end = "<div id='end'>end</div></body>";
     89    const page = page_start + page_end;
     90 
     91    response.setHeader("Content-Type", "text/html; charset=utf-8", false);
     92    response.setHeader("Content-Length", page.length + "", false);
     93    response.write(page_start);
     94 
     95    await onRequestUnblocked;
     96 
     97    response.write(page_end);
     98    response.finish();
     99  });
    100 
    101  const port = httpServer.identity.primaryPort;
    102  const TEST_URL_2 = `http://localhost:${port}/`;
    103 
    104  // Same as in the other task, we cannot wait for the full load.
    105  info("Open a new tab on TEST_URL_2 and select it");
    106  const loadingTab = BrowserTestUtils.addTab(gBrowser, TEST_URL_2);
    107  gBrowser.selectedTab = loadingTab;
    108 
    109  info("Wait for the #start div to be available in the document");
    110  await TestUtils.waitForCondition(async () => {
    111    try {
    112      return await ContentTask.spawn(gBrowser.selectedBrowser, {}, () =>
    113        content.document.getElementById("start")
    114      );
    115    } catch (e) {
    116      return false;
    117    }
    118  });
    119 
    120  const { inspector } = await openInspector();
    121 
    122  info("Check that the inspector is not blank and only shows the #start div");
    123  await assertMarkupViewAsTree(
    124    `
    125    body
    126      div id="start"`,
    127    "body",
    128    inspector
    129  );
    130 
    131  // Navigate to about:blank to clean the state.
    132  await navigateTo("about:blank");
    133 
    134  const markuploaded = inspector.once("markuploaded");
    135  const onNewRoot = inspector.once("new-root");
    136  const onUpdated = inspector.once("inspector-updated");
    137 
    138  await navigateTo(TEST_URL_2, { waitForLoad: false });
    139  info("Wait for the #start div to be available as a markupview container");
    140  await TestUtils.waitForCondition(async () => {
    141    const nodeFront = await getNodeFront("#start", inspector);
    142    return nodeFront && getContainerForNodeFront(nodeFront, inspector);
    143  });
    144 
    145  info("Check that the inspector is not blank and only shows the #start div");
    146  await assertMarkupViewAsTree(
    147    `
    148    body
    149      div id="start"`,
    150    "body",
    151    inspector
    152  );
    153 
    154  info("Unblock the document request");
    155  unblockRequest();
    156 
    157  info("Wait for the #end div to be available as a markupview container");
    158  await TestUtils.waitForCondition(async () => {
    159    const nodeFront = await getNodeFront("#end", inspector);
    160    return nodeFront && getContainerForNodeFront(nodeFront, inspector);
    161  });
    162 
    163  info("Check that the inspector will ultimately show the #end div");
    164  await assertMarkupViewAsTree(
    165    `
    166    body
    167      div id="start"
    168      div id="end"`,
    169    "body",
    170    inspector
    171  );
    172 
    173  info(
    174    "Waiting for inspector to update after having released the document load"
    175  );
    176  await markuploaded;
    177  await onNewRoot;
    178  await onUpdated;
    179 });