tor-browser

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

browser_dbg-event-breakpoints.js (11705B)


      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 add_task(async function () {
      8  await pushPref("dom.element.commandfor.enabled", true);
      9  await pushPref("dom.events.textevent.enabled", true);
     10  await pushPref("dom.closewatcher.enabled", true);
     11 
     12  const dbg = await initDebugger(
     13    "doc-event-breakpoints.html",
     14    "event-breakpoints.js"
     15  );
     16  await selectSource(dbg, "event-breakpoints.js");
     17  await waitForSelectedSource(dbg, "event-breakpoints.js");
     18  const eventBreakpointsSource = findSource(dbg, "event-breakpoints.js");
     19 
     20  // We want to set each breakpoint individually to test adding/removing breakpoints, see Bug 1748589.
     21  await toggleEventBreakpoint(dbg, "Mouse", "event.mouse.click");
     22 
     23  invokeInTab("clickHandler");
     24  await waitForPaused(dbg);
     25  await assertPausedAtSourceAndLine(dbg, eventBreakpointsSource.id, 12);
     26 
     27  const whyPaused = await waitFor(
     28    () => dbg.win.document.querySelector(".why-paused")?.innerText
     29  );
     30  is(
     31    whyPaused,
     32    `Paused on event breakpoint\nclickTargetClicked - event-breakpoints.js:12:2\nDOM 'click' event`,
     33    "whyPaused does state that the debugger is paused as a result of a click event breakpoint"
     34  );
     35  await resume(dbg);
     36 
     37  await toggleEventBreakpoint(dbg, "XHR", "event.xhr.load");
     38  invokeInTab("xhrHandler");
     39  await waitForPaused(dbg);
     40  await assertPausedAtSourceAndLine(dbg, eventBreakpointsSource.id, 24);
     41  await resume(dbg);
     42 
     43  await toggleEventBreakpoint(dbg, "Timer", "timer.timeout.set");
     44  await toggleEventBreakpoint(dbg, "Timer", "timer.timeout.fire");
     45  invokeInTab("timerHandler");
     46  await waitForPaused(dbg);
     47  await assertPausedAtSourceAndLine(dbg, eventBreakpointsSource.id, 31);
     48  await resume(dbg);
     49 
     50  await waitForPaused(dbg);
     51  await assertPausedAtSourceAndLine(dbg, eventBreakpointsSource.id, 32);
     52  await resume(dbg);
     53 
     54  await toggleEventBreakpoint(dbg, "Script", "script.source.firstStatement");
     55  invokeInTab("evalHandler");
     56  await waitForPaused(dbg);
     57  await assertPausedAtSourceAndLine(dbg, findSource(dbg, "eval-test.js").id, 2);
     58  await resume(dbg);
     59  await toggleEventBreakpoint(dbg, "Script", "script.source.firstStatement");
     60 
     61  await toggleEventBreakpoint(dbg, "Control", "event.control.focusin");
     62  await toggleEventBreakpoint(dbg, "Control", "event.control.focusout");
     63  invokeOnElement("#focus-text", "focus");
     64  await waitForPaused(dbg);
     65  await assertPausedAtSourceAndLine(dbg, eventBreakpointsSource.id, 47);
     66  await resume(dbg);
     67 
     68  // wait for focus-out event to fire
     69  await waitForPaused(dbg);
     70  await assertPausedAtSourceAndLine(dbg, eventBreakpointsSource.id, 52);
     71  await resume(dbg);
     72 
     73  info("Deselect focus events");
     74  // We need to give the input focus to test composition, but we don't want the
     75  // focus breakpoints to fire.
     76  await toggleEventBreakpoint(dbg, "Control", "event.control.focusin");
     77  await toggleEventBreakpoint(dbg, "Control", "event.control.focusout");
     78 
     79  await toggleEventBreakpoint(dbg, "Control", "event.control.command");
     80  invokeOnElement("#invoker", "click");
     81  await waitForPaused(dbg);
     82  await assertPausedAtSourceAndLine(dbg, eventBreakpointsSource.id, 77);
     83  await resume(dbg);
     84 
     85  info("Enable closewatcher cancel and close events");
     86  await toggleEventBreakpoint(dbg, "CloseWatcher", "event.closewatcher.cancel");
     87  await toggleEventBreakpoint(dbg, "CloseWatcher", "event.closewatcher.close");
     88  invokeInTab("closeWatcherRequestClose");
     89  info("Wait for pause in cancel event listener");
     90  await waitForPaused(dbg);
     91  await assertPausedAtSourceAndLine(dbg, eventBreakpointsSource.id, 116);
     92  await resume(dbg);
     93  info("And wait for pause in close event listener after resuming");
     94  await waitForPaused(dbg);
     95  await assertPausedAtSourceAndLine(dbg, eventBreakpointsSource.id, 120);
     96  await resume(dbg);
     97 
     98  info("Enable beforetoggle and toggle events");
     99  await toggleEventBreakpoint(dbg, "Control", "event.control.beforetoggle");
    100  await toggleEventBreakpoint(dbg, "Control", "event.control.toggle");
    101  invokeOnElement("#popover-toggle", "click");
    102  info("Wait for pause in beforetoggle event listener");
    103  await waitForPaused(dbg);
    104  await assertPausedAtSourceAndLine(dbg, eventBreakpointsSource.id, 93);
    105  await resume(dbg);
    106  info("And wait for pause in toggle event listener after resuming");
    107  await waitForPaused(dbg);
    108  await assertPausedAtSourceAndLine(dbg, eventBreakpointsSource.id, 97);
    109  await resume(dbg);
    110 
    111  await toggleEventBreakpoint(
    112    dbg,
    113    "Keyboard",
    114    "event.keyboard.compositionstart"
    115  );
    116  invokeOnElement("#focus-text", "focus");
    117 
    118  info("Type some characters during composition");
    119  invokeComposition();
    120 
    121  await waitForPaused(dbg);
    122  await assertPausedAtSourceAndLine(dbg, eventBreakpointsSource.id, 57);
    123  await resume(dbg);
    124 
    125  info("Deselect compositionstart and select compositionupdate");
    126  await toggleEventBreakpoint(
    127    dbg,
    128    "Keyboard",
    129    "event.keyboard.compositionstart"
    130  );
    131  await toggleEventBreakpoint(
    132    dbg,
    133    "Keyboard",
    134    "event.keyboard.compositionupdate"
    135  );
    136 
    137  invokeOnElement("#focus-text", "focus");
    138 
    139  info("Type some characters during composition");
    140  invokeComposition();
    141 
    142  await waitForPaused(dbg);
    143  await assertPausedAtSourceAndLine(dbg, eventBreakpointsSource.id, 62);
    144  await resume(dbg);
    145 
    146  info("Deselect compositionupdate and select compositionend");
    147  await toggleEventBreakpoint(
    148    dbg,
    149    "Keyboard",
    150    "event.keyboard.compositionupdate"
    151  );
    152  await toggleEventBreakpoint(dbg, "Keyboard", "event.keyboard.compositionend");
    153  invokeOnElement("#focus-text", "focus");
    154 
    155  info("Type some characters during composition");
    156  invokeComposition();
    157 
    158  info("Commit the composition");
    159  EventUtils.synthesizeComposition({
    160    type: "compositioncommitasis",
    161    key: { key: "KEY_Enter" },
    162  });
    163 
    164  await waitForPaused(dbg);
    165  await assertPausedAtSourceAndLine(dbg, eventBreakpointsSource.id, 67);
    166  await resume(dbg);
    167 
    168  info("Test textInput");
    169  await toggleEventBreakpoint(dbg, "Keyboard", "event.keyboard.textInput");
    170  invokeOnElement("#focus-text", "focus");
    171  EventUtils.sendChar("N");
    172  await waitForPaused(dbg);
    173  await assertPausedAtSourceAndLine(dbg, eventBreakpointsSource.id, 102);
    174  await resume(dbg);
    175  await toggleEventBreakpoint(dbg, "Keyboard", "event.keyboard.textInput");
    176 
    177  info(`Check that breakpoint can be set on "scrollend"`);
    178  await toggleEventBreakpoint(dbg, "Control", "event.control.scrollend");
    179 
    180  await SpecialPowers.spawn(gBrowser.selectedBrowser, [], () => {
    181    content.scrollTo({ top: 20, behavior: "smooth" });
    182  });
    183 
    184  await waitForPaused(dbg);
    185  await assertPausedAtSourceAndLine(dbg, eventBreakpointsSource.id, 72);
    186  await resume(dbg);
    187 
    188  info(`Check that breakpoint can be set on "pointerrawupdate"`);
    189  await toggleEventBreakpoint(dbg, "Pointer", "event.pointer.pointerrawupdate");
    190 
    191  SpecialPowers.spawn(gBrowser.selectedBrowser, [], () => {
    192    // EventUtils.synthesize throws when dispatching a pointerrawupdate for some reason,
    193    // let's build and dispatch the event directly
    194    content.document
    195      .getElementById("pointer-target")
    196      .dispatchEvent(
    197        new content.wrappedJSObject.PointerEvent("pointerrawupdate", {})
    198      );
    199  });
    200 
    201  await waitForPaused(dbg);
    202  await assertPausedAtSourceAndLine(dbg, eventBreakpointsSource.id, 107);
    203  await resume(dbg);
    204  await toggleEventBreakpoint(dbg, "Pointer", "event.pointer.pointerrawupdate");
    205 
    206  info("Check that the click event breakpoint is still enabled");
    207  invokeInTab("clickHandler");
    208  await waitForPaused(dbg);
    209  await assertPausedAtSourceAndLine(dbg, eventBreakpointsSource.id, 12);
    210  await resume(dbg);
    211 
    212  info("Check that disabling an event breakpoint works");
    213  await toggleEventBreakpoint(dbg, "Mouse", "event.mouse.click");
    214  invokeInTab("clickHandler");
    215  // wait for a bit to make sure the debugger do not pause
    216  await wait(100);
    217  assertNotPaused(dbg);
    218 
    219  info("Check that we can re-enable event breakpoints");
    220  await toggleEventBreakpoint(dbg, "Mouse", "event.mouse.click");
    221  invokeInTab("clickHandler");
    222  await waitForPaused(dbg);
    223  await assertPausedAtSourceAndLine(dbg, eventBreakpointsSource.id, 12);
    224  await resume(dbg);
    225 
    226  info(
    227    "Test that we don't pause on event breakpoints when source is blackboxed."
    228  );
    229  await clickElement(dbg, "blackbox");
    230  await waitForDispatch(dbg.store, "BLACKBOX_WHOLE_SOURCES");
    231 
    232  invokeInTab("clickHandler");
    233  // wait for a bit to make sure the debugger do not pause
    234  await wait(100);
    235  assertNotPaused(dbg);
    236 
    237  invokeInTab("xhrHandler");
    238  // wait for a bit to make sure the debugger do not pause
    239  await wait(100);
    240  assertNotPaused(dbg);
    241 
    242  invokeInTab("timerHandler");
    243  // wait for a bit to make sure the debugger do not pause
    244  await wait(100);
    245  assertNotPaused(dbg);
    246 
    247  // Cleanup - unblackbox the source
    248  await clickElement(dbg, "blackbox");
    249  await waitForDispatch(dbg.store, "UNBLACKBOX_WHOLE_SOURCES");
    250 
    251  info(`Check that breakpoint can be set on "beforeUnload" event`);
    252  await toggleEventBreakpoint(dbg, "Load", "event.load.beforeunload");
    253  let onReload = reload(dbg);
    254  await waitForPaused(dbg);
    255  await assertPausedAtSourceAndLine(dbg, eventBreakpointsSource.id, 82);
    256  await resume(dbg);
    257  await onReload;
    258  await toggleEventBreakpoint(dbg, "Load", "event.load.beforeunload");
    259 
    260  info(`Check that breakpoint can be set on "unload" event`);
    261  await toggleEventBreakpoint(dbg, "Load", "event.load.unload");
    262  onReload = reload(dbg);
    263  await waitForPaused(dbg);
    264  await assertPausedAtSourceAndLine(dbg, eventBreakpointsSource.id, 87);
    265  await resume(dbg);
    266  await onReload;
    267  await toggleEventBreakpoint(dbg, "Load", "event.load.unload");
    268 });
    269 
    270 // Cover CmdOrCtrl+click on event breakpoints
    271 add_task(async function () {
    272  const dbg = await initDebugger(
    273    "doc-event-breakpoints.html",
    274    "event-breakpoints.js"
    275  );
    276 
    277  // Toggle two distinct categories
    278  await toggleEventBreakpoint(dbg, "Load", "event.load.unload");
    279  await toggleEventBreakpoint(dbg, "Mouse", "event.mouse.click");
    280 
    281  info("CmdOrCtrl + click on the Timer category");
    282  const loadGroupCheckbox = findElementWithSelector(dbg, `input[value="Load"]`);
    283  const mouseGroupCheckbox = findElementWithSelector(
    284    dbg,
    285    `input[value="Mouse"]`
    286  );
    287  const timerGroupCheckbox = findElementWithSelector(
    288    dbg,
    289    `input[value="Timer"]`
    290  );
    291  is(loadGroupCheckbox.indeterminate, true);
    292  is(mouseGroupCheckbox.indeterminate, true);
    293  is(timerGroupCheckbox.checked, false);
    294  timerGroupCheckbox.scrollIntoView();
    295  EventUtils.synthesizeMouseAtCenter(
    296    timerGroupCheckbox,
    297    { [Services.appinfo.OS === "Darwin" ? "metaKey" : "ctrlKey"]: true },
    298    dbg.win
    299  );
    300  info("Wait for the checkboxes to update");
    301  await waitFor(
    302    () =>
    303      timerGroupCheckbox.checked === true &&
    304      loadGroupCheckbox.indeterminate === false
    305  );
    306  is(loadGroupCheckbox.indeterminate, false);
    307  is(mouseGroupCheckbox.indeterminate, false);
    308  is(timerGroupCheckbox.checked, true);
    309 });
    310 
    311 async function invokeOnElement(selector, action) {
    312  await SpecialPowers.focus(gBrowser.selectedBrowser);
    313  await SpecialPowers.spawn(
    314    gBrowser.selectedBrowser,
    315    [selector, action],
    316    (_selector, _action) => {
    317      content.document.querySelector(_selector)[_action]();
    318    }
    319  );
    320 }
    321 
    322 function invokeComposition() {
    323  const string = "ex";
    324  EventUtils.synthesizeCompositionChange({
    325    composition: {
    326      string,
    327      clauses: [
    328        {
    329          length: string.length,
    330          attr: Ci.nsITextInputProcessor.ATTR_RAW_CLAUSE,
    331        },
    332      ],
    333    },
    334    caret: { start: string.length, length: 0 },
    335    key: { key: string[string.length - 1] },
    336  });
    337 }