tor-browser

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

browser_dbg-call-stack.js (8479B)


      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 "use strict";
      6 
      7 // Ignore strange errors when shutting down.
      8 PromiseTestUtils.allowMatchingRejectionsGlobally(/No such actor/);
      9 
     10 add_task(async function testBasicFrames() {
     11  const dbg = await initDebugger(
     12    "doc-script-switching.html",
     13    "script-switching-01.js",
     14    "script-switching-02.js"
     15  );
     16 
     17  const found = findElement(dbg, "callStackBody");
     18  is(found, null, "Call stack is hidden");
     19 
     20  invokeInTab("firstCall");
     21  await waitForPaused(dbg);
     22 
     23  const frames = findAllElements(dbg, "frames");
     24  assertFrameIsSelected(dbg, frames[0], "secondCall");
     25 
     26  info("Assert pause at the correct location");
     27  await assertPausedAtSourceAndLine(
     28    dbg,
     29    findSource(dbg, "script-switching-02.js").id,
     30    6
     31  );
     32 
     33  info("Click the second frame and assert the frame and the selected location");
     34  frames[1].click();
     35  await assertSelectedLocation(
     36    dbg,
     37    findSource(dbg, "script-switching-01.js").id,
     38    8
     39  );
     40  assertFrameIsSelected(dbg, frames[1], "firstCall");
     41 
     42  const button = toggleButton(dbg);
     43  ok(!button, "toggle button shouldn't be there");
     44 
     45  await resume(dbg);
     46 });
     47 
     48 add_task(async function testFrameNavigation() {
     49  const dbg = await initDebugger("doc-frames.html", "frames.js");
     50 
     51  const source = findSource(dbg, "frames.js");
     52  invokeInTab("startRecursion");
     53  await waitForPaused(dbg);
     54 
     55  let frames = findAllElements(dbg, "frames");
     56  assertFrameIsSelected(dbg, frames[0], "recurseA");
     57  assertFrameContent(dbg, frames[0], "recurseA", "frames.js:3");
     58 
     59  // check to make sure that the toggle button isn't there
     60  let button = toggleButton(dbg);
     61 
     62  is(button.innerText, "Expand rows", "toggle button should be 'expand'");
     63  is(frames.length, 7, "There should be at most seven frames");
     64 
     65  frames[0].focus();
     66 
     67  info("Assert the Home and End Keys on the frame list");
     68  pressKey(dbg, "End");
     69  assertFrameContent(
     70    dbg,
     71    dbg.win.document.activeElement,
     72    "recurseA",
     73    "frames.js:8"
     74  );
     75 
     76  pressKey(dbg, "Start");
     77  assertFrameContent(
     78    dbg,
     79    dbg.win.document.activeElement,
     80    "recurseA",
     81    "frames.js:3"
     82  );
     83 
     84  info("Assert navigating through the frames");
     85  pressKey(dbg, "Down");
     86  is(frames[1], dbg.win.document.activeElement, "The second frame is focused");
     87 
     88  pressKey(dbg, "Down");
     89  is(frames[2], dbg.win.document.activeElement, "The third frame is focused");
     90 
     91  info(
     92    "Assert that selecting the third frame jumps to the correct source location"
     93  );
     94  pressKey(dbg, "Enter");
     95 
     96  await assertSelectedLocation(dbg, source.id, 8);
     97  assertFrameIsSelected(dbg, frames[2], "recurseA");
     98  assertFrameContent(dbg, frames[2], "recurseA", "frames.js:8");
     99 
    100  is(
    101    dbg.win.document.activeElement,
    102    findElement(dbg, "CodeMirrorLines"),
    103    "Selecting the frame via the Enter key will open the source, set the cursor at the frame location and focus CodeMirror"
    104  );
    105 
    106  info("Focus the frame again in the frame list");
    107  frames[2].focus();
    108 
    109  info("Navigate up and assert the second frame");
    110  pressKey(dbg, "Up");
    111  is(
    112    frames[1],
    113    dbg.win.document.activeElement,
    114    "The second frame is now focused"
    115  );
    116 
    117  info(
    118    "Assert that selecting the second frame jumps to the correct source location"
    119  );
    120  pressKey(dbg, "Enter");
    121 
    122  await assertSelectedLocation(dbg, source.id, 18);
    123  assertFrameIsSelected(dbg, frames[1], "recurseB");
    124 
    125  frames[0].focus();
    126 
    127  button.click();
    128 
    129  button = toggleButton(dbg);
    130  frames = findAllElements(dbg, "frames");
    131  is(button.innerText, "Collapse rows", "toggle button should be collapsed");
    132  is(frames.length, 22, "All of the frames should be shown");
    133  await waitForSelectedSource(dbg, "frames.js");
    134 });
    135 
    136 add_task(async function testGroupFrames() {
    137  const url = createMockAngularPage();
    138  const tab = await addTab(url);
    139  info("Open debugger");
    140  const toolbox = await openToolboxForTab(tab, "jsdebugger");
    141  const dbg = createDebuggerContext(toolbox);
    142 
    143  const found = findElement(dbg, "callStackBody");
    144  is(found, null, "Call stack is hidden");
    145 
    146  const pausedContent = SpecialPowers.spawn(
    147    gBrowser.selectedBrowser,
    148    [],
    149    function () {
    150      content.document.querySelector("button.pause").click();
    151    }
    152  );
    153 
    154  await waitForPaused(dbg);
    155  const group = findElementWithSelector(dbg, ".frames .frames-group");
    156  is(
    157    group.querySelector(".badge").textContent,
    158    "2",
    159    "Group has expected badge"
    160  );
    161  is(
    162    group.querySelector(".group-description-name").textContent,
    163    "Angular",
    164    "Group has expected location"
    165  );
    166 
    167  info("Expand the frame group");
    168  group.focus();
    169  pressKey(dbg, "Enter");
    170 
    171  info("Press arrow to select first frame element");
    172  pressKey(dbg, "Down");
    173 
    174  info("Assert the Home and End Keys in the Frame Group");
    175  pressKey(dbg, "End");
    176  info("The last frame item in the group is not selected");
    177  assertFrameIsNotSelected(dbg, dbg.win.document.activeElement, "<anonymous>");
    178  assertFrameContent(dbg, dbg.win.document.activeElement, "<anonymous>");
    179 
    180  pressKey(dbg, "Start");
    181  info("The group header is focused");
    182  is(
    183    dbg.win.document.activeElement.querySelector(".group-description-name")
    184      .innerText,
    185    "Angular",
    186    "The group is correct"
    187  );
    188 
    189  const frameElements = findAllElements(dbg, "frames");
    190  is(
    191    frameElements[0],
    192    dbg.win.document.activeElement,
    193    "The first frame is now focused"
    194  );
    195 
    196  const source = findSource(dbg, "angular.js");
    197  await assertPausedAtSourceAndLine(dbg, source.id, 4);
    198  await assertSelectedLocation(dbg, source.id, 4);
    199  assertFrameIsSelected(dbg, frameElements[1], "<anonymous>");
    200 
    201  info("Select the frame group");
    202  frameElements[1].focus();
    203  pressKey(dbg, "Up");
    204 
    205  info(
    206    "Assert that the frame group does not collapse when a frame group item is selected"
    207  );
    208  pressKey(dbg, "Enter");
    209  const frameGroupHeader = frameElements[1].parentNode.previousElementSibling;
    210  ok(
    211    frameGroupHeader.classList.contains("expanded"),
    212    "The frame group is still expanded"
    213  );
    214  is(
    215    frameGroupHeader.querySelector(".group-description-name").innerText,
    216    "Angular",
    217    "The group is correct"
    218  );
    219  is(
    220    frameGroupHeader.title,
    221    "Select a non-group frame to collapse Angular frames",
    222    "The group title is correct"
    223  );
    224 
    225  await resume(dbg);
    226 
    227  info("Wait for content to be resumed");
    228  await pausedContent;
    229 });
    230 
    231 function toggleButton(dbg) {
    232  const callStackBody = findElement(dbg, "callStackBody");
    233  return callStackBody.querySelector(".show-more");
    234 }
    235 
    236 function assertFrameContent(dbg, element, expectedTitle, expectedLocation) {
    237  is(
    238    element.querySelector(".title").innerText,
    239    expectedTitle,
    240    "The frame title is correct"
    241  );
    242 
    243  if (expectedLocation) {
    244    is(
    245      element.querySelector(".location").innerText,
    246      expectedLocation,
    247      "The location is correct"
    248    );
    249  }
    250 }
    251 
    252 async function assertSelectedLocation(dbg, sourceId, line) {
    253  await waitFor(() => {
    254    const selectedLocation = dbg.selectors.getSelectedLocation();
    255    return (
    256      selectedLocation.source.id == sourceId && selectedLocation.line == line
    257    );
    258  });
    259  ok(true, "The correct location is selected");
    260 }
    261 
    262 // Create an HTTP server to simulate an angular app with anonymous functions
    263 // and return the URL.
    264 function createMockAngularPage() {
    265  const httpServer = createTestHTTPServer();
    266 
    267  httpServer.registerContentType("html", "text/html");
    268  httpServer.registerContentType("js", "application/javascript");
    269 
    270  const htmlFilename = "angular-mock.html";
    271  httpServer.registerPathHandler(
    272    `/${htmlFilename}`,
    273    function (request, response) {
    274      response.setStatusLine(request.httpVersion, 200, "OK");
    275      response.write(`
    276        <html>
    277            <button class="pause">Click me</button>
    278            <script type="text/javascript" src="angular.js"></script>
    279        </html>`);
    280    }
    281  );
    282 
    283  // Register an angular.js file in order to create a Group with anonymous functions in
    284  // the callstack panel.
    285  httpServer.registerPathHandler("/angular.js", function (request, response) {
    286    response.setHeader("Content-Type", "application/javascript");
    287    response.write(`
    288      document.querySelector("button.pause").addEventListener("click", () => {
    289        (function() {
    290          debugger;
    291        })();
    292      })
    293    `);
    294  });
    295 
    296  const port = httpServer.identity.primaryPort;
    297  return `http://localhost:${port}/${htmlFilename}`;
    298 }