tor-browser

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

browser_markup_mutation_02.js (6300B)


      1 /* Any copyright is dedicated to the Public Domain.
      2 http://creativecommons.org/publicdomain/zero/1.0/ */
      3 
      4 "use strict";
      5 
      6 // Test that markup-containers in the markup-view do flash when their
      7 // corresponding DOM nodes mutate
      8 
      9 // Have to use the same timer functions used by the inspector.
     10 // eslint-disable-next-line mozilla/no-redeclare-with-import-autofix
     11 const { clearTimeout } = ChromeUtils.importESModule(
     12  "resource://gre/modules/Timer.sys.mjs"
     13 );
     14 
     15 const TEST_URL = URL_ROOT + "doc_markup_flashing.html";
     16 
     17 // The test data contains a list of mutations to test.
     18 // Each item is an object:
     19 // - desc: a description of the test step, for better logging
     20 // - mutate: a generator function that should make changes to the content DOM
     21 // - attribute: if set, the test will expect the corresponding attribute to
     22 //   flash instead of the whole node
     23 // - flashedNode: [optional] the css selector of the node that is expected to
     24 //   flash in the markup-view as a result of the mutation.
     25 //   If missing, the rootNode (".list") will be expected to flash
     26 const TEST_DATA = [
     27  {
     28    desc: "Adding a new node should flash the new node",
     29    async mutate() {
     30      await SpecialPowers.spawn(gBrowser.selectedBrowser, [], () => {
     31        const newLi = content.document.createElement("LI");
     32        newLi.textContent = "new list item";
     33        content.document.querySelector(".list").appendChild(newLi);
     34      });
     35    },
     36    flashedNode: ".list li:nth-child(3)",
     37  },
     38  {
     39    desc: "Removing a node should flash its parent",
     40    async mutate() {
     41      await SpecialPowers.spawn(gBrowser.selectedBrowser, [], () => {
     42        const root = content.document.querySelector(".list");
     43        root.removeChild(root.lastElementChild);
     44      });
     45    },
     46  },
     47  {
     48    desc: "Re-appending an existing node should only flash this node",
     49    async mutate() {
     50      await SpecialPowers.spawn(gBrowser.selectedBrowser, [], () => {
     51        const root = content.document.querySelector(".list");
     52        root.appendChild(root.firstElementChild);
     53      });
     54    },
     55    flashedNode: ".list .item:last-child",
     56  },
     57  {
     58    desc: "Adding an attribute should flash the attribute",
     59    attribute: "test-name",
     60    async mutate() {
     61      await setContentPageElementAttribute(
     62        ".list",
     63        "test-name",
     64        "value-" + Date.now()
     65      );
     66    },
     67  },
     68  {
     69    desc:
     70      "Adding an attribute with css reserved characters should flash the " +
     71      "attribute",
     72    attribute: "one:two",
     73    async mutate() {
     74      await setContentPageElementAttribute(
     75        ".list",
     76        "one:two",
     77        "value-" + Date.now()
     78      );
     79    },
     80  },
     81  {
     82    desc: "Editing an attribute should flash the attribute",
     83    attribute: "class",
     84    async mutate() {
     85      await setContentPageElementAttribute(
     86        ".list",
     87        "class",
     88        "list value-" + Date.now()
     89      );
     90    },
     91  },
     92  {
     93    desc: "Multiple changes to an attribute should flash the attribute",
     94    attribute: "class",
     95    async mutate() {
     96      await SpecialPowers.spawn(gBrowser.selectedBrowser, [], () => {
     97        const root = content.document.querySelector(".list");
     98        root.removeAttribute("class");
     99        root.setAttribute("class", "list value-" + Date.now());
    100        root.setAttribute("class", "list value-" + Date.now());
    101        root.removeAttribute("class");
    102        root.setAttribute("class", "list value-" + Date.now());
    103        root.setAttribute("class", "list value-" + Date.now());
    104      });
    105    },
    106  },
    107  {
    108    desc: "Removing an attribute should flash the node",
    109    async mutate() {
    110      await SpecialPowers.spawn(gBrowser.selectedBrowser, [], () => {
    111        const root = content.document.querySelector(".list");
    112        root.removeAttribute("class");
    113      });
    114    },
    115  },
    116 ];
    117 
    118 add_task(async function () {
    119  await pushPref("privacy.reduceTimerPrecision", false);
    120 
    121  const { inspector } = await openInspectorForURL(TEST_URL);
    122 
    123  // Make sure mutated nodes flash for a very long time so we can more easily
    124  // assert they do
    125  inspector.markup.CONTAINER_FLASHING_DURATION = 1000 * 60 * 60;
    126 
    127  info("Getting the <ul.list> root node to test mutations on");
    128  const rootNodeFront = await getNodeFront(".list", inspector);
    129 
    130  info("Selecting the last element of the root node before starting");
    131  await selectNode(".list .item:nth-child(2)", inspector);
    132 
    133  for (const { mutate, flashedNode, desc, attribute } of TEST_DATA) {
    134    info("Starting test: " + desc);
    135 
    136    info("Mutating the DOM and listening for markupmutation event");
    137    const onMutation = inspector.once("markupmutation");
    138    await mutate();
    139    const mutations = await onMutation;
    140 
    141    info("Wait for the breadcrumbs widget to update if it needs to");
    142    if (inspector.breadcrumbs._hasInterestingMutations(mutations)) {
    143      await inspector.once("breadcrumbs-updated");
    144    }
    145 
    146    info("Asserting that the correct markup-container is flashing");
    147    let flashingNodeFront = rootNodeFront;
    148    if (flashedNode) {
    149      flashingNodeFront = await getNodeFront(flashedNode, inspector);
    150    }
    151 
    152    if (attribute) {
    153      await assertAttributeFlashing(flashingNodeFront, attribute, inspector);
    154    } else {
    155      await assertNodeFlashing(flashingNodeFront, inspector);
    156    }
    157  }
    158 });
    159 
    160 function assertNodeFlashing(nodeFront, inspector) {
    161  const container = getContainerForNodeFront(nodeFront, inspector);
    162  ok(container, "Markup container for node found");
    163  ok(
    164    container.tagState.classList.contains("theme-bg-contrast"),
    165    "Markup container for node is flashing"
    166  );
    167 
    168  // Clear the mutation flashing timeout now that we checked the node was
    169  // flashing.
    170  clearTimeout(container._flashMutationTimer);
    171  container._flashMutationTimer = null;
    172  container.tagState.classList.remove("theme-bg-contrast");
    173 }
    174 
    175 function assertAttributeFlashing(nodeFront, attribute, inspector) {
    176  const container = getContainerForNodeFront(nodeFront, inspector);
    177  ok(container, "Markup container for node found");
    178  ok(
    179    container.editor.attrElements.get(attribute),
    180    "Attribute exists on editor"
    181  );
    182 
    183  const attributeElement = container.editor.getAttributeElement(attribute);
    184 
    185  ok(
    186    attributeElement.classList.contains("theme-bg-contrast"),
    187    "Element for " + attribute + " attribute is flashing"
    188  );
    189 
    190  attributeElement.classList.remove("theme-bg-contrast");
    191 }