browser_inspector_breadcrumbs.js (9283B)
1 /* Any copyright is dedicated to the Public Domain. 2 http://creativecommons.org/publicdomain/zero/1.0/ */ 3 "use strict"; 4 5 // Test that the breadcrumbs widget content is correct. 6 7 const TEST_URI = URL_ROOT + "doc_inspector_breadcrumbs.html"; 8 const NODES = [ 9 { 10 selector: "#i1111", 11 ids: "i1 i11 i111 i1111", 12 nodeName: "div", 13 title: "div#i1111", 14 }, 15 { selector: "#i22", ids: "i2 i22", nodeName: "div", title: "div#i22" }, 16 { 17 selector: "#i2111", 18 ids: "i2 i21 i211 i2111", 19 nodeName: "div", 20 title: "div#i2111", 21 }, 22 { 23 selector: "#i21", 24 ids: "i2 i21 i211 i2111", 25 nodeName: "div", 26 title: "div#i21", 27 }, 28 { 29 selector: "#i22211", 30 ids: "i2 i22 i222 i2221 i22211", 31 nodeName: "div", 32 title: "div#i22211", 33 }, 34 { 35 selector: "#i22", 36 ids: "i2 i22 i222 i2221 i22211", 37 nodeName: "div", 38 title: "div#i22", 39 }, 40 { selector: "#i3", ids: "i3", nodeName: "article", title: "article#i3" }, 41 { 42 selector: "clipPath", 43 ids: "vector clip", 44 nodeName: "clipPath", 45 title: "clipPath#clip", 46 }, 47 ]; 48 49 add_task(async function () { 50 const { inspector } = await openInspectorForURL(TEST_URI); 51 const breadcrumbs = inspector.panelDoc.getElementById( 52 "inspector-breadcrumbs" 53 ); 54 const container = breadcrumbs.querySelector(".html-arrowscrollbox-inner"); 55 56 for (const node of NODES) { 57 info("Testing node " + node.selector); 58 59 info("Selecting node and waiting for breadcrumbs to update"); 60 const breadcrumbsUpdated = inspector.once("breadcrumbs-updated"); 61 await selectNode(node.selector, inspector); 62 await breadcrumbsUpdated; 63 64 info("Performing checks for node " + node.selector); 65 const buttonsLabelIds = node.ids.split(" "); 66 67 // html > body > … 68 is( 69 container.childNodes.length, 70 buttonsLabelIds.length + 2, 71 "Node " + node.selector + ": Items count" 72 ); 73 74 for (let i = 2; i < container.childNodes.length; i++) { 75 const expectedId = "#" + buttonsLabelIds[i - 2]; 76 const button = container.childNodes[i]; 77 const labelId = button.querySelector(".breadcrumbs-widget-item-id"); 78 is( 79 labelId.textContent, 80 expectedId, 81 "Node " + node.selector + ": button " + i + " matches" 82 ); 83 } 84 85 const pressedButton = container.querySelector( 86 `button[aria-pressed="true"]` 87 ); 88 const labelId = pressedButton.querySelector(".breadcrumbs-widget-item-id"); 89 const id = inspector.selection.nodeFront.id; 90 is( 91 labelId.textContent, 92 "#" + id, 93 "Node " + node.selector + ": selection matches" 94 ); 95 96 const labelTag = pressedButton.querySelector( 97 ".breadcrumbs-widget-item-tag" 98 ); 99 is( 100 labelTag.textContent, 101 node.nodeName, 102 "Node " + node.selector + " has the expected tag name" 103 ); 104 105 is( 106 pressedButton.getAttribute("title"), 107 node.title, 108 "Node " + node.selector + " has the expected tooltip" 109 ); 110 } 111 112 await testPseudoElements(inspector, container); 113 await testComments(inspector, container); 114 }); 115 116 async function testPseudoElements(inspector, container) { 117 info("Checking for pseudo elements"); 118 119 const checkBreadcrumbContent = async (nodeFront, expected, desc) => { 120 const onBreadcrumbsUpdated = inspector.once("breadcrumbs-updated"); 121 await selectNode(nodeFront, inspector); 122 await onBreadcrumbsUpdated; 123 Assert.deepEqual( 124 [...container.childNodes].map(el => el.textContent), 125 expected, 126 desc 127 ); 128 }; 129 130 const pseudoParent = await getNodeFront("#pseudo-container", inspector); 131 const children = await inspector.walker.children(pseudoParent); 132 is(children.nodes.length, 2, "Pseudo children returned from walker"); 133 134 const beforeElement = children.nodes[0]; 135 await checkBreadcrumbContent( 136 beforeElement, 137 ["html", "body", "div#pseudo-container", "::before"], 138 "::before shows up in breadcrumb" 139 ); 140 141 const afterElement = children.nodes[1]; 142 await checkBreadcrumbContent( 143 afterElement, 144 ["html", "body", "div#pseudo-container", "::after"], 145 "::after shows up in breadcrumb" 146 ); 147 148 const dialogNodeFront = await getNodeFront("dialog", inspector); 149 const dialogChildren = await inspector.walker.children(dialogNodeFront); 150 is( 151 dialogChildren.nodes.length, 152 2, 153 "Expected number of children for the dialog element" 154 ); 155 const backdropElement = dialogChildren.nodes[0]; 156 await checkBreadcrumbContent( 157 backdropElement, 158 ["html", "body", "dialog", "::backdrop"], 159 ":backdrop shows up in breadcrumb" 160 ); 161 162 info("Check rules on ::view-transition"); 163 const htmlNodeFront = await getNodeFront("html", inspector); 164 const onMarkupMutation = inspector.once("markupmutation"); 165 await SpecialPowers.spawn(gBrowser.selectedBrowser, [], async () => { 166 const document = content.document; 167 content.testTransition = document.startViewTransition(); 168 await content.testTransition; 169 }); 170 await onMarkupMutation; 171 172 const htmlChildren = await inspector.markup.walker.children(htmlNodeFront); 173 const viewTransitionNodeFront = htmlChildren.nodes[2]; 174 175 is( 176 viewTransitionNodeFront.getAttribute("type"), 177 ":view-transition", 178 "Got expected ::view-transition node front" 179 ); 180 181 await checkBreadcrumbContent( 182 viewTransitionNodeFront, 183 ["html", "::view-transition"], 184 "::view-transition shows up in breadcrumb" 185 ); 186 187 const viewTransitionChildren = await inspector.markup.walker.children( 188 viewTransitionNodeFront 189 ); 190 const viewTransitionGroupNodeFront = viewTransitionChildren.nodes[0]; 191 is( 192 viewTransitionGroupNodeFront.getAttribute("type"), 193 ":view-transition-group", 194 "Got expected ::view-transition-group node front" 195 ); 196 197 await checkBreadcrumbContent( 198 viewTransitionGroupNodeFront, 199 ["html", "::view-transition", "::view-transition-group(root)"], 200 "::view-transition-group(root) shows up in breadcrumb" 201 ); 202 203 const viewTransitionGroupChildren = await inspector.markup.walker.children( 204 viewTransitionGroupNodeFront 205 ); 206 const viewTransitionImagePairNodeFront = viewTransitionGroupChildren.nodes[0]; 207 is( 208 viewTransitionImagePairNodeFront.getAttribute("type"), 209 ":view-transition-image-pair", 210 "Got expected ::view-transition-image-pair node front" 211 ); 212 213 await checkBreadcrumbContent( 214 viewTransitionImagePairNodeFront, 215 [ 216 "html", 217 "::view-transition", 218 "::view-transition-group(root)", 219 "::view-transition-image-pair(root)", 220 ], 221 "::view-transition-image-pair(root) shows up in breadcrumb" 222 ); 223 224 const viewTransitionImagePairChildren = 225 await inspector.markup.walker.children(viewTransitionImagePairNodeFront); 226 const [viewTransitionOldNodeFront, viewTransitionNewNodeFront] = 227 viewTransitionImagePairChildren.nodes; 228 is( 229 viewTransitionOldNodeFront.getAttribute("type"), 230 ":view-transition-old", 231 "Got expected ::view-transition-old node front" 232 ); 233 is( 234 viewTransitionNewNodeFront.getAttribute("type"), 235 ":view-transition-new", 236 "Got expected ::view-transition-new node front" 237 ); 238 239 await checkBreadcrumbContent( 240 viewTransitionOldNodeFront, 241 [ 242 "html", 243 "::view-transition", 244 "::view-transition-group(root)", 245 "::view-transition-image-pair(root)", 246 "::view-transition-old(root)", 247 ], 248 "::view-transition-old(root) shows up in breadcrumb" 249 ); 250 251 await checkBreadcrumbContent( 252 viewTransitionNewNodeFront, 253 [ 254 "html", 255 "::view-transition", 256 "::view-transition-group(root)", 257 "::view-transition-image-pair(root)", 258 "::view-transition-new(root)", 259 ], 260 "::view-transition-new(root) shows up in breadcrumb" 261 ); 262 263 // Cancel transition 264 await SpecialPowers.spawn(gBrowser.selectedBrowser, [], async () => { 265 content.testTransition.skipTransition(); 266 delete content.testTransition; 267 }); 268 } 269 270 async function testComments(inspector, container) { 271 info("Checking for comment elements"); 272 273 const breadcrumbs = inspector.breadcrumbs; 274 const pressedButtonIndex = 2; 275 const button = container.childNodes[pressedButtonIndex]; 276 277 let onBreadcrumbsUpdated = inspector.once("breadcrumbs-updated"); 278 button.click(); 279 await onBreadcrumbsUpdated; 280 281 is(breadcrumbs.currentIndex, pressedButtonIndex, "New button is selected"); 282 ok( 283 breadcrumbs.outer.hasAttribute("aria-activedescendant"), 284 "Active descendant must be set" 285 ); 286 287 const comment = [...inspector.markup._containers].find( 288 ([node]) => node.nodeType === Node.COMMENT_NODE 289 )[0]; 290 291 let onInspectorUpdated = inspector.once("inspector-updated"); 292 inspector.selection.setNodeFront(comment); 293 await onInspectorUpdated; 294 295 is( 296 breadcrumbs.currentIndex, 297 -1, 298 "When comment is selected no breadcrumb should be pressed" 299 ); 300 ok( 301 !breadcrumbs.outer.hasAttribute("aria-activedescendant"), 302 "Active descendant must not be set" 303 ); 304 305 onInspectorUpdated = inspector.once("inspector-updated"); 306 onBreadcrumbsUpdated = inspector.once("breadcrumbs-updated"); 307 button.click(); 308 await Promise.all([onInspectorUpdated, onBreadcrumbsUpdated]); 309 310 is( 311 breadcrumbs.currentIndex, 312 pressedButtonIndex, 313 "Same button is selected again" 314 ); 315 ok( 316 breadcrumbs.outer.hasAttribute("aria-activedescendant"), 317 "Active descendant must be set again" 318 ); 319 }