tor-browser

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

browser_dbg-project-root.js (12412B)


      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 // This test covers changing to a distinct "project root"
      6 // i.e. displaying only one particular thread, domain, or directory in the Source Tree.
      7 
      8 "use strict";
      9 
     10 const httpServer = createTestHTTPServer();
     11 const HOST = `localhost:${httpServer.identity.primaryPort}`;
     12 const BASE_URL = `http://${HOST}/`;
     13 
     14 const PAGE_URL = BASE_URL + "index.html";
     15 const PAGE_CONTENT = `<!DOCTYPE html>
     16  <html>
     17    <head>
     18      <script type="text/javascript" src="/root-script.js"></script>
     19      <script type="text/javascript" src="/folder/folder-script.js"></script>
     20      <script type="text/javascript" src="/folder/sub-folder/sub-folder-script.js"></script>
     21    </head>
     22    <body></body>
     23  </html>`;
     24 const ALL_PAGE_SCRIPTS = [
     25  "root-script.js",
     26  "folder-script.js",
     27  "sub-folder-script.js",
     28 ];
     29 
     30 httpServer.registerPathHandler("/index.html", (request, response) => {
     31  response.setStatusLine(request.httpVersion, 200, "OK");
     32  response.write(PAGE_CONTENT);
     33 });
     34 httpServer.registerPathHandler("/root-script.js", (request, response) => {
     35  response.setHeader("Content-Type", "application/javascript");
     36  response.write("console.log('root script')");
     37 });
     38 httpServer.registerPathHandler(
     39  "/folder/folder-script.js",
     40  (request, response) => {
     41    response.setHeader("Content-Type", "application/javascript");
     42    response.write("console.log('folder script')");
     43  }
     44 );
     45 httpServer.registerPathHandler(
     46  "/folder/sub-folder/sub-folder-script.js",
     47  (request, response) => {
     48    response.setHeader("Content-Type", "application/javascript");
     49    response.write("console.log('sub folder script')");
     50  }
     51 );
     52 
     53 const PAGE2_URL = BASE_URL + "index2.html";
     54 const PAGE2_CONTENT = `<!DOCTYPE html>
     55  <html>
     56    <head>
     57      <script type="text/javascript" src="/src/script.js"></script>
     58      <script type="text/javascript">
     59        console.log("webpack script");
     60        //# sourceURL=webpack:///src/webpack-script.js
     61      </script>
     62      <script type="text/javascript">
     63        console.log("webpack with domain script");
     64        //# sourceURL=webpack://with-domain/webpack-with-domain-script.js
     65      </script>
     66      <script type="text/javascript">
     67        console.log("webpack short URL script");
     68        //# sourceURL=webpack:webpack-short-url-script.js
     69      </script>
     70      <script type="text/javascript">
     71        console.log("turbopack script");
     72        //# sourceURL=turbopack:///src/turbopack-script.js
     73      </script>
     74      <script type="text/javascript">
     75        console.log("turbopack script 2");
     76        //# sourceURL=turbopack://src2/turbopack-script-2.js
     77      </script>
     78      <script type="text/javascript">
     79        console.log("angular script");
     80        //# sourceURL=ng:///src/angular-script.js
     81      </script>
     82      <script type="text/javascript">
     83        console.log("angular script 2");
     84        //# sourceURL=ng://src2/angular-script-2.js
     85      </script>
     86      <script type="text/javascript">
     87        console.log("resource script");
     88        //# sourceURL=resource://devtools/test/resource-script.js
     89      </script>
     90    </head>
     91    <body></body>
     92  </html>`;
     93 const ALL_PAGE2_SCRIPTS = [
     94  "script.js",
     95  "webpack-script.js",
     96  "webpack-with-domain-script.js",
     97  "webpack-short-url-script.js",
     98  "turbopack-script.js",
     99  "turbopack-script-2.js",
    100  "angular-script.js",
    101  "angular-script-2.js",
    102  "resource-script.js",
    103  "worker-script.js",
    104 ];
    105 
    106 httpServer.registerPathHandler("/index2.html", (request, response) => {
    107  response.setStatusLine(request.httpVersion, 200, "OK");
    108  response.write(PAGE2_CONTENT);
    109 });
    110 httpServer.registerPathHandler("/src/script.js", (request, response) => {
    111  response.setHeader("Content-Type", "application/javascript");
    112  response.write(
    113    "console.log('src script'); const worker = new Worker('src/worker-script.js')"
    114  );
    115 });
    116 httpServer.registerPathHandler("/src/worker-script.js", (request, response) => {
    117  response.setHeader("Content-Type", "application/javascript");
    118  response.write("console.log('worker script')");
    119 });
    120 
    121 const httpServer2 = createTestHTTPServer();
    122 const ALT_HOST = `localhost:${httpServer2.identity.primaryPort}`;
    123 const ALT_BASE_URL = `http://${ALT_HOST}/`;
    124 
    125 const PAGE3_URL = ALT_BASE_URL + "index.html";
    126 const PAGE3_CONTENT = `<!DOCTYPE html>
    127  <html>
    128    <head>
    129      <script type="text/javascript" src="/lib/script.js"></script>
    130    </head>
    131    <body></body>
    132  </html>`;
    133 
    134 httpServer2.registerPathHandler("/index.html", (request, response) => {
    135  response.setStatusLine(request.httpVersion, 200, "OK");
    136  response.write(PAGE3_CONTENT);
    137 });
    138 httpServer2.registerPathHandler("/lib/script.js", (request, response) => {
    139  response.setStatusLine(request.httpVersion, 200, "OK");
    140  response.write("console.log('lib script')");
    141 });
    142 
    143 add_task(async function testProjectRoot() {
    144  await pushPref("devtools.debugger.show-content-scripts", true);
    145 
    146  const dbg = await initDebuggerWithAbsoluteURL(PAGE_URL, ...ALL_PAGE_SCRIPTS);
    147 
    148  await waitForSourcesInSourceTree(dbg, ALL_PAGE_SCRIPTS);
    149 
    150  await selectAndCheckProjectRoots(dbg, [
    151    {
    152      label: "Main Thread",
    153      tooltip: "Main Thread",
    154      sources: ALL_PAGE_SCRIPTS,
    155    },
    156    {
    157      label: HOST,
    158      tooltip: `${BASE_URL.slice(0, -1)} on Main Thread`,
    159      sources: ALL_PAGE_SCRIPTS,
    160    },
    161    {
    162      label: "folder",
    163      tooltip: `${BASE_URL}folder on Main Thread`,
    164      sources: ["folder-script.js", "sub-folder-script.js"],
    165    },
    166  ]);
    167 
    168  info("Reload and see if project root is preserved");
    169  await reload(dbg, "folder-script.js", "sub-folder-script.js");
    170  await checkProjectRoot(dbg, "folder", `${BASE_URL}folder on Main Thread`, [
    171    "folder-script.js",
    172    "sub-folder-script.js",
    173  ]);
    174 
    175  info("Select 'sub-folder' as project root");
    176  await selectAndCheckProjectRoots(dbg, [
    177    {
    178      label: "sub-folder",
    179      tooltip: `${BASE_URL}folder/sub-folder on Main Thread`,
    180      sources: ["sub-folder-script.js"],
    181    },
    182  ]);
    183 
    184  info("Navigate to a different page with the same origin");
    185  await navigateTo(PAGE2_URL);
    186  await checkProjectRoot(
    187    dbg,
    188    "sub-folder",
    189    `${BASE_URL}folder/sub-folder on Main Thread`,
    190    []
    191  );
    192 
    193  info("Clear project root");
    194  await clearProjectRoot(dbg);
    195  await waitForSourcesInSourceTree(dbg, ALL_PAGE2_SCRIPTS);
    196  checkNoProjectRoot(dbg);
    197 
    198  info("Load the test extension");
    199  const extension = await installAndStartExtension();
    200  await waitForSourcesInSourceTree(dbg, [
    201    ...ALL_PAGE2_SCRIPTS,
    202    "content_script.js",
    203  ]);
    204 
    205  await selectAndCheckProjectRoots(dbg, [
    206    {
    207      label: "Test extension",
    208      tooltip: `Test extension`,
    209      sources: ["content_script.js"],
    210    },
    211    {
    212      label: "Test extension",
    213      tooltip: `moz-extension://${extension.uuid} on Test extension`,
    214      sources: ["content_script.js"],
    215    },
    216    {
    217      label: "src",
    218      tooltip: `moz-extension://${extension.uuid}/src on Test extension`,
    219      sources: ["content_script.js"],
    220    },
    221  ]);
    222 
    223  info("Check that the project root is cleared when its thread is removed");
    224  await extension.unload();
    225  await waitForSourcesInSourceTree(dbg, ALL_PAGE2_SCRIPTS);
    226  checkNoProjectRoot(dbg);
    227 
    228  await selectAndCheckProjectRoots(dbg, [
    229    {
    230      label: "Webpack",
    231      tooltip: `webpack:// on Main Thread`,
    232      sources: [
    233        "webpack-script.js",
    234        "webpack-with-domain-script.js",
    235        "webpack-short-url-script.js",
    236      ],
    237    },
    238    {
    239      label: "src",
    240      tooltip: `webpack:///src on Main Thread`,
    241      sources: ["webpack-script.js"],
    242    },
    243  ]);
    244 
    245  info("Clear project root");
    246  await clearProjectRoot(dbg);
    247 
    248  await selectAndCheckProjectRoots(dbg, [
    249    {
    250      label: "Turbopack",
    251      tooltip: `turbopack:// on Main Thread`,
    252      sources: ["turbopack-script.js", "turbopack-script-2.js"],
    253    },
    254    {
    255      label: "src",
    256      tooltip: `turbopack:///src on Main Thread`,
    257      sources: ["turbopack-script.js"],
    258    },
    259  ]);
    260 
    261  info("Clear project root");
    262  await clearProjectRoot(dbg);
    263 
    264  await selectAndCheckProjectRoots(dbg, [
    265    {
    266      label: "Angular",
    267      tooltip: `ng:// on Main Thread`,
    268      sources: ["angular-script.js", "angular-script-2.js"],
    269    },
    270    {
    271      label: "src",
    272      tooltip: `ng:///src on Main Thread`,
    273      sources: ["angular-script.js"],
    274    },
    275  ]);
    276 
    277  info("Clear project root");
    278  await clearProjectRoot(dbg);
    279 
    280  await selectAndCheckProjectRoots(dbg, [
    281    {
    282      label: "resource://devtools",
    283      tooltip: `resource://devtools on Main Thread`,
    284      sources: ["resource-script.js"],
    285    },
    286    {
    287      label: "test",
    288      tooltip: `resource://devtools/test on Main Thread`,
    289      sources: ["resource-script.js"],
    290    },
    291  ]);
    292 
    293  info("Clear project root");
    294  await clearProjectRoot(dbg);
    295 
    296  await selectAndCheckProjectRoots(dbg, [
    297    {
    298      label: "worker-script.js",
    299      tooltip: `worker-script.js`,
    300      sources: ["worker-script.js"],
    301    },
    302    {
    303      label: HOST,
    304      tooltip: `${BASE_URL.slice(0, -1)} on worker-script.js`,
    305      sources: ["worker-script.js"],
    306    },
    307    {
    308      label: "src",
    309      tooltip: `${BASE_URL}src on worker-script.js`,
    310      sources: ["worker-script.js"],
    311    },
    312  ]);
    313 
    314  info("Navigate to a page with a different origin");
    315  await navigateTo(PAGE3_URL);
    316  checkNoProjectRoot(dbg);
    317 
    318  await selectAndCheckProjectRoots(dbg, [
    319    {
    320      label: "lib",
    321      tooltip: `${ALT_BASE_URL}lib on Main Thread`,
    322      sources: ["script.js"],
    323    },
    324  ]);
    325 
    326  info("Navigate to the first page");
    327  await navigateTo(PAGE_URL);
    328  checkNoProjectRoot(dbg);
    329 
    330  info("Navigate to the third page");
    331  await navigateTo(PAGE3_URL);
    332  await checkProjectRoot(dbg, "lib", `${ALT_BASE_URL}lib on Main Thread`, [
    333    "script.js",
    334  ]);
    335 
    336  info("Navigate to a data: URL");
    337  const dataURL =
    338    "data:text/html,<meta charset=utf8><script>console.log('inline script')</script>";
    339  await navigateTo(dataURL);
    340  checkNoProjectRoot(dbg);
    341 
    342  await selectAndCheckProjectRoots(dbg, [
    343    {
    344      label: "(no domain)",
    345      tooltip: `data: on Main Thread`,
    346      sources: [dataURL],
    347    },
    348  ]);
    349 });
    350 
    351 async function setProjectRoot(dbg, treeNode) {
    352  const dispatched = waitForDispatch(dbg.store, "SET_PROJECT_DIRECTORY_ROOT");
    353  await triggerSourceTreeContextMenu(dbg, treeNode, "#node-set-directory-root");
    354  await dispatched;
    355 }
    356 
    357 async function checkProjectRoot(dbg, label, tooltip, sources) {
    358  assertRootLabel(dbg, label);
    359  assertRootLabelTooltip(dbg, `Directory root set to ${tooltip}`);
    360  if (sources.length) {
    361    await waitForSourcesInSourceTree(dbg, sources);
    362  } else {
    363    ok(dbg.win.document.querySelector(".no-sources-message"));
    364  }
    365 }
    366 
    367 async function selectAndCheckProjectRoots(dbg, tests) {
    368  for (const test of tests) {
    369    const { label, tooltip, sources } = test;
    370 
    371    info(`Select ${label} as project root`);
    372    const item = findSourceNodeWithText(dbg, label);
    373    await setProjectRoot(dbg, item);
    374 
    375    await checkProjectRoot(dbg, label, tooltip, sources);
    376  }
    377 }
    378 
    379 async function checkNoProjectRoot(dbg) {
    380  ok(!dbg.win.document.querySelector(".sources-clear-root"));
    381 }
    382 
    383 function assertRootLabel(dbg, label) {
    384  const rootHeaderLabel = dbg.win.document.querySelector(
    385    ".sources-clear-root-label"
    386  );
    387  is(rootHeaderLabel.textContent, label);
    388 }
    389 
    390 function assertRootLabelTooltip(dbg, text) {
    391  const rootHeader = dbg.win.document.querySelector(
    392    ".sources-clear-root-label"
    393  );
    394  Assert.stringContains(rootHeader.title, text);
    395 }
    396 
    397 async function clearProjectRoot(dbg) {
    398  const rootHeader = dbg.win.document.querySelector(".sources-clear-root");
    399  rootHeader.click();
    400 }
    401 
    402 async function installAndStartExtension() {
    403  function contentScript() {
    404    console.log("content script loads");
    405 
    406    // This listener prevents the source from being garbage collected
    407    // and be missing from the scripts returned by `dbg.findScripts()`
    408    // in `ThreadActor._discoverSources`.
    409    window.onload = () => {};
    410  }
    411 
    412  const extension = ExtensionTestUtils.loadExtension({
    413    manifest: {
    414      name: "Test extension",
    415      content_scripts: [
    416        {
    417          js: ["src/content_script.js"],
    418          matches: ["http://*/*"],
    419          run_at: "document_start",
    420        },
    421      ],
    422    },
    423    useAddonManager: "temporary",
    424    files: {
    425      "src/content_script.js": contentScript,
    426    },
    427  });
    428 
    429  await extension.startup();
    430 
    431  return extension;
    432 }