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 }