tor-browser

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

browser_inspector_menu-01-sensitivity.js (10764B)


      1 /* Any copyright is dedicated to the Public Domain.
      2 http://creativecommons.org/publicdomain/zero/1.0/ */
      3 "use strict";
      4 
      5 // Test that context menu items are enabled / disabled correctly.
      6 
      7 const TEST_URL = URL_ROOT + "doc_inspector_menu.html";
      8 
      9 const PASTE_MENU_ITEMS = [
     10  "node-menu-pasteinnerhtml",
     11  "node-menu-pasteouterhtml",
     12  "node-menu-pastebefore",
     13  "node-menu-pasteafter",
     14  "node-menu-pastefirstchild",
     15  "node-menu-pastelastchild",
     16 ];
     17 
     18 const ACTIVE_ON_DOCTYPE_ITEMS = [
     19  "node-menu-showdomproperties",
     20  "node-menu-useinconsole",
     21 ];
     22 
     23 const ACTIVE_ON_SHADOW_ROOT_ITEMS = [
     24  "node-menu-pasteinnerhtml",
     25  "node-menu-copyinner",
     26  "node-menu-edithtml",
     27 ].concat(ACTIVE_ON_DOCTYPE_ITEMS);
     28 
     29 const ALL_MENU_ITEMS = [
     30  "node-menu-edithtml",
     31  "node-menu-copyinner",
     32  "node-menu-copyouter",
     33  "node-menu-copyuniqueselector",
     34  "node-menu-copycsspath",
     35  "node-menu-copyxpath",
     36  "node-menu-copyimagedatauri",
     37  "node-menu-delete",
     38  "node-menu-pseudo-hover",
     39  "node-menu-pseudo-active",
     40  "node-menu-pseudo-focus",
     41  "node-menu-pseudo-focus-within",
     42  "node-menu-scrollnodeintoview",
     43  "node-menu-screenshotnode",
     44  "node-menu-add-attribute",
     45  "node-menu-copy-attribute",
     46  "node-menu-edit-attribute",
     47  "node-menu-remove-attribute",
     48 ].concat(PASTE_MENU_ITEMS, ACTIVE_ON_DOCTYPE_ITEMS);
     49 
     50 const INACTIVE_ON_DOCTYPE_ITEMS = ALL_MENU_ITEMS.filter(
     51  item => !ACTIVE_ON_DOCTYPE_ITEMS.includes(item)
     52 );
     53 
     54 const INACTIVE_ON_DOCUMENT_ITEMS = INACTIVE_ON_DOCTYPE_ITEMS;
     55 
     56 const INACTIVE_ON_SHADOW_ROOT_ITEMS = ALL_MENU_ITEMS.filter(
     57  item => !ACTIVE_ON_SHADOW_ROOT_ITEMS.includes(item)
     58 );
     59 
     60 /**
     61 * Test cases, each item of this array may define the following properties:
     62 *   desc: string that will be logged
     63 *   selector: selector of the node to be selected
     64 *   disabled: items that should have disabled state
     65 *   clipboardData: clipboard content
     66 *   clipboardDataType: clipboard content type
     67 *   attributeTrigger: attribute that will be used as context menu trigger
     68 *   shadowRoot: if true, selects the shadow root from the node, rather than
     69 *   the node itself.
     70 */
     71 const TEST_CASES = [
     72  {
     73    desc: "doctype node with empty clipboard",
     74    selector: null,
     75    disabled: INACTIVE_ON_DOCTYPE_ITEMS,
     76  },
     77  {
     78    desc: "doctype node with html on clipboard",
     79    clipboardData: "<p>some text</p>",
     80    clipboardDataType: "text",
     81    selector: null,
     82    disabled: INACTIVE_ON_DOCTYPE_ITEMS,
     83  },
     84  {
     85    desc: "element node HTML on the clipboard",
     86    clipboardData: "<p>some text</p>",
     87    clipboardDataType: "text",
     88    disabled: [
     89      "node-menu-copyimagedatauri",
     90      "node-menu-copy-attribute",
     91      "node-menu-edit-attribute",
     92      "node-menu-remove-attribute",
     93    ],
     94    selector: "#sensitivity",
     95  },
     96  {
     97    desc: "<html> element",
     98    clipboardData: "<p>some text</p>",
     99    clipboardDataType: "text",
    100    selector: "html",
    101    disabled: [
    102      "node-menu-copyimagedatauri",
    103      "node-menu-pastebefore",
    104      "node-menu-pasteafter",
    105      "node-menu-pastefirstchild",
    106      "node-menu-pastelastchild",
    107      "node-menu-copy-attribute",
    108      "node-menu-edit-attribute",
    109      "node-menu-remove-attribute",
    110      "node-menu-delete",
    111    ],
    112  },
    113  {
    114    desc: "<body> with HTML on clipboard",
    115    clipboardData: "<p>some text</p>",
    116    clipboardDataType: "text",
    117    selector: "body",
    118    disabled: [
    119      "node-menu-copyimagedatauri",
    120      "node-menu-pastebefore",
    121      "node-menu-pasteafter",
    122      "node-menu-copy-attribute",
    123      "node-menu-edit-attribute",
    124      "node-menu-remove-attribute",
    125    ],
    126  },
    127  {
    128    desc: "<img> with HTML on clipboard",
    129    clipboardData: "<p>some text</p>",
    130    clipboardDataType: "text",
    131    selector: "img",
    132    disabled: [
    133      "node-menu-copy-attribute",
    134      "node-menu-edit-attribute",
    135      "node-menu-remove-attribute",
    136    ],
    137  },
    138  {
    139    desc: "<head> with HTML on clipboard",
    140    clipboardData: "<p>some text</p>",
    141    clipboardDataType: "text",
    142    selector: "head",
    143    disabled: [
    144      "node-menu-copyimagedatauri",
    145      "node-menu-pastebefore",
    146      "node-menu-pasteafter",
    147      "node-menu-screenshotnode",
    148      "node-menu-copy-attribute",
    149      "node-menu-edit-attribute",
    150      "node-menu-remove-attribute",
    151    ],
    152  },
    153  {
    154    desc: "<head> with no html on clipboard",
    155    selector: "head",
    156    disabled: PASTE_MENU_ITEMS.concat([
    157      "node-menu-copyimagedatauri",
    158      "node-menu-screenshotnode",
    159      "node-menu-copy-attribute",
    160      "node-menu-edit-attribute",
    161      "node-menu-remove-attribute",
    162    ]),
    163  },
    164  {
    165    desc: "<element> with text on clipboard",
    166    clipboardData: "some text",
    167    clipboardDataType: "text",
    168    selector: "#paste-area",
    169    disabled: [
    170      "node-menu-copyimagedatauri",
    171      "node-menu-copy-attribute",
    172      "node-menu-edit-attribute",
    173      "node-menu-remove-attribute",
    174    ],
    175  },
    176  {
    177    desc: "<element> with base64 encoded image data uri on clipboard",
    178    clipboardData:
    179      "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABC" +
    180      "AAAAAA6fptVAAAACklEQVQYV2P4DwABAQEAWk1v8QAAAABJRU5ErkJggg==",
    181    clipboardDataType: "image",
    182    selector: "#paste-area",
    183    disabled: PASTE_MENU_ITEMS.concat([
    184      "node-menu-copyimagedatauri",
    185      "node-menu-copy-attribute",
    186      "node-menu-edit-attribute",
    187      "node-menu-remove-attribute",
    188    ]),
    189  },
    190  {
    191    desc: "<element> with empty string on clipboard",
    192    clipboardData: "",
    193    clipboardDataType: "text",
    194    selector: "#paste-area",
    195    disabled: PASTE_MENU_ITEMS.concat([
    196      "node-menu-copyimagedatauri",
    197      "node-menu-copy-attribute",
    198      "node-menu-edit-attribute",
    199      "node-menu-remove-attribute",
    200    ]),
    201  },
    202  {
    203    desc: "<element> with whitespace only on clipboard",
    204    clipboardData: " \n\n\t\n\n  \n",
    205    clipboardDataType: "text",
    206    selector: "#paste-area",
    207    disabled: PASTE_MENU_ITEMS.concat([
    208      "node-menu-copyimagedatauri",
    209      "node-menu-copy-attribute",
    210      "node-menu-edit-attribute",
    211      "node-menu-remove-attribute",
    212    ]),
    213  },
    214  {
    215    desc: "<element> that isn't visible on the page, empty clipboard",
    216    selector: "#hiddenElement",
    217    disabled: PASTE_MENU_ITEMS.concat([
    218      "node-menu-copyimagedatauri",
    219      "node-menu-screenshotnode",
    220      "node-menu-copy-attribute",
    221      "node-menu-edit-attribute",
    222      "node-menu-remove-attribute",
    223    ]),
    224  },
    225  {
    226    desc: "<element> nested in another hidden element, empty clipboard",
    227    selector: "#nestedHiddenElement",
    228    disabled: PASTE_MENU_ITEMS.concat([
    229      "node-menu-copyimagedatauri",
    230      "node-menu-screenshotnode",
    231      "node-menu-copy-attribute",
    232      "node-menu-edit-attribute",
    233      "node-menu-remove-attribute",
    234    ]),
    235  },
    236  {
    237    desc: "<element> with context menu triggered on attribute, empty clipboard",
    238    selector: "#attributes",
    239    disabled: PASTE_MENU_ITEMS.concat(["node-menu-copyimagedatauri"]),
    240    attributeTrigger: "data-edit",
    241  },
    242  {
    243    desc: "Shadow Root",
    244    clipboardData: "<p>some text</p>",
    245    clipboardDataType: "text",
    246    disabled: INACTIVE_ON_SHADOW_ROOT_ITEMS,
    247    selector: "#host",
    248    shadowRoot: true,
    249  },
    250  {
    251    desc: "Document node in iFrame",
    252    disabled: INACTIVE_ON_DOCUMENT_ITEMS,
    253    selector: "iframe",
    254    documentNode: true,
    255  },
    256 ];
    257 
    258 var clipboard = require("resource://devtools/shared/platform/clipboard.js");
    259 registerCleanupFunction(() => {
    260  clipboard.copyString("");
    261  clipboard = null;
    262 });
    263 
    264 add_task(async function () {
    265  const { inspector } = await openInspectorForURL(TEST_URL);
    266  for (const test of TEST_CASES) {
    267    const {
    268      desc,
    269      disabled,
    270      selector,
    271      attributeTrigger,
    272      documentNode = false,
    273      shadowRoot = false,
    274    } = test;
    275 
    276    info(`Test ${desc}`);
    277    setupClipboard(test.clipboardData, test.clipboardDataType);
    278 
    279    const front = await getNodeFrontForSelector(
    280      selector,
    281      inspector,
    282      documentNode,
    283      shadowRoot
    284    );
    285 
    286    info("Selecting the specified node.");
    287    await selectNode(front, inspector);
    288 
    289    info("Simulating context menu click on the selected node container.");
    290    const nodeFrontContainer = getContainerForNodeFront(front, inspector);
    291    const contextMenuTrigger = attributeTrigger
    292      ? nodeFrontContainer.tagLine.querySelector(
    293          `[data-attr="${attributeTrigger}"]`
    294        )
    295      : nodeFrontContainer.tagLine;
    296 
    297    const allMenuItems = openContextMenuAndGetAllItems(inspector, {
    298      target: contextMenuTrigger,
    299    });
    300 
    301    for (const id of ALL_MENU_ITEMS) {
    302      const menuItem = allMenuItems.find(item => item.id === id);
    303      const shouldBeDisabled = disabled.includes(id);
    304      const shouldBeDisabledText = shouldBeDisabled ? "disabled" : "enabled";
    305      is(
    306        menuItem.disabled,
    307        shouldBeDisabled,
    308        `#${id} should be ${shouldBeDisabledText} for test case ${desc}`
    309      );
    310    }
    311  }
    312 });
    313 
    314 /**
    315 * A helper that fetches a front for a node that matches the given selector or
    316 * doctype node if the selector is falsy.
    317 */
    318 async function getNodeFrontForSelector(
    319  selector,
    320  inspector,
    321  documentNode,
    322  shadowRoot
    323 ) {
    324  if (selector) {
    325    info("Retrieving front for selector " + selector);
    326    const node = await getNodeFront(selector, inspector);
    327    if (shadowRoot) {
    328      return getShadowRoot(node, inspector);
    329    }
    330    if (documentNode) {
    331      return getFrameDocument(node, inspector);
    332    }
    333    return node;
    334  }
    335 
    336  info("Retrieving front for doctype node");
    337  const { nodes } = await inspector.walker.children(inspector.walker.rootNode);
    338  return nodes[0];
    339 }
    340 
    341 /**
    342 * A helper that populates the clipboard with data of given type. Clears the
    343 * clipboard if data is falsy.
    344 */
    345 function setupClipboard(data, type) {
    346  if (!data) {
    347    info("Clearing the clipboard.");
    348    clipboard.copyString("");
    349  } else if (type === "text") {
    350    info("Populating clipboard with text.");
    351    clipboard.copyString(data);
    352  } else if (type === "image") {
    353    info("Populating clipboard with image content");
    354    copyImageToClipboard(data);
    355  }
    356 }
    357 
    358 /**
    359 * The code below is a simplified version of the sdk/clipboard helper set() method.
    360 */
    361 function copyImageToClipboard(data) {
    362  const imageTools = Cc["@mozilla.org/image/tools;1"].getService(Ci.imgITools);
    363 
    364  // Image data is stored as base64 in the test.
    365  const image = atob(data);
    366 
    367  const imgPtr = Cc["@mozilla.org/supports-interface-pointer;1"].createInstance(
    368    Ci.nsISupportsInterfacePointer
    369  );
    370  imgPtr.data = imageTools.decodeImageFromBuffer(
    371    image,
    372    image.length,
    373    "image/png"
    374  );
    375 
    376  const xferable = Cc["@mozilla.org/widget/transferable;1"].createInstance(
    377    Ci.nsITransferable
    378  );
    379  xferable.init(null);
    380  xferable.addDataFlavor("image/png");
    381  xferable.setTransferData("image/png", imgPtr);
    382 
    383  Services.clipboard.setData(
    384    xferable,
    385    null,
    386    Services.clipboard.kGlobalClipboard
    387  );
    388 }