browser_inspector_highlighter-cssshape_04.js (17612B)
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 // Test that shapes are updated correctly on mouse events. 8 9 const TEST_URL = URL_ROOT + "doc_inspector_highlighter_cssshapes.html"; 10 const { TYPES } = ChromeUtils.importESModule( 11 "resource://devtools/shared/highlighters.mjs" 12 ); 13 const HIGHLIGHTER_TYPE = TYPES.SHAPES; 14 15 add_task(async function testPolygon() { 16 const config = await taskSetup(); 17 18 await testPolygonMovePoint(config); 19 await testPolygonAddPoint(config); 20 await testPolygonRemovePoint(config); 21 22 config.helper.finalize(); 23 }); 24 25 add_task(async function testCircle() { 26 const config = await taskSetup(); 27 28 await testCircleMoveCenter(config); 29 await testCircleWithoutPosition(config); 30 31 config.helper.finalize(); 32 }); 33 34 add_task(async function testEllipse() { 35 const config = await taskSetup(); 36 37 await testEllipseMoveRadius(config); 38 39 config.helper.finalize(); 40 }); 41 42 add_task(async function testInset() { 43 const config = await taskSetup(); 44 45 await testInsetMoveEdges(config); 46 47 config.helper.finalize(); 48 }); 49 50 async function taskSetup() { 51 const env = await openInspectorForURL(TEST_URL); 52 const helper = await getHighlighterHelperFor(HIGHLIGHTER_TYPE)(env); 53 const { highlighterTestFront, inspector } = env; 54 const view = selectRuleView(inspector); 55 const highlighters = view.highlighters; 56 57 return { 58 inspector, 59 view, 60 highlighters, 61 highlighterTestFront, 62 helper, 63 }; 64 } 65 66 async function getComputedPropertyValue(selector, property, inspector) { 67 const highlightedNode = await getNodeFront(selector, inspector); 68 const computedStyle = 69 await highlightedNode.inspectorFront.pageStyle.getComputed(highlightedNode); 70 return computedStyle[property].value; 71 } 72 73 async function setup(config) { 74 const { view, selector, property, inspector } = config; 75 info(`Turn on shapes highlighter for ${selector}`); 76 await selectNode(selector, inspector); 77 await toggleShapesHighlighter(view, selector, property, true); 78 } 79 80 async function teardown(config) { 81 const { view, selector, property } = config; 82 info(`Turn off shapes highlighter for ${selector}`); 83 await toggleShapesHighlighter(view, selector, property, false); 84 } 85 86 async function testPolygonMovePoint(config) { 87 const { inspector, view, highlighterTestFront, helper } = config; 88 const selector = "#polygon"; 89 const property = "clip-path"; 90 91 await setup({ selector, property, ...config }); 92 93 const points = await highlighterTestFront.getHighlighterNodeAttribute( 94 "shapes-polygon", 95 "points", 96 inspector.inspectorFront.getKnownHighlighter(HIGHLIGHTER_TYPE) 97 ); 98 let [x, y] = points.split(" ")[0].split(","); 99 const quads = await getAllAdjustedQuadsForContentPageElement(selector); 100 const { top, left, width, height } = quads.border[0].bounds; 101 x = left + (width * x) / 100; 102 y = top + (height * y) / 100; 103 const dx = width / 10; 104 const dyPercent = 10; 105 const dy = height / dyPercent; 106 107 const onRuleViewChanged = view.once("ruleview-changed"); 108 info("Moving first polygon point"); 109 const { mouse } = helper; 110 await mouse.down(x, y); 111 await mouse.move(x + dx, y + dy); 112 await mouse.up(); 113 await reflowContentPage(); 114 info("Waiting for rule view changed from shape change"); 115 await onRuleViewChanged; 116 117 const definition = await getComputedPropertyValue( 118 selector, 119 property, 120 inspector 121 ); 122 ok( 123 definition.includes(`${dx}px ${dyPercent}%`), 124 `Point moved to ${dx}px ${dyPercent}%` 125 ); 126 127 await teardown({ selector, property, ...config }); 128 } 129 130 async function testPolygonAddPoint(config) { 131 const { inspector, view, highlighterTestFront, helper } = config; 132 const selector = "#polygon"; 133 const property = "clip-path"; 134 135 await setup({ selector, property, ...config }); 136 137 // Move first point to have same x as second point, then double click between 138 // the two points to add a new one. 139 const points = await highlighterTestFront.getHighlighterNodeAttribute( 140 "shapes-polygon", 141 "points", 142 inspector.inspectorFront.getKnownHighlighter(HIGHLIGHTER_TYPE) 143 ); 144 const pointsArray = points.split(" "); 145 const quads = await getAllAdjustedQuadsForContentPageElement(selector); 146 const { top, left, width, height } = quads.border[0].bounds; 147 let [x1, y1] = pointsArray[0].split(","); 148 let [x2, y2] = pointsArray[1].split(","); 149 x1 = left + (width * x1) / 100; 150 x2 = left + (width * x2) / 100; 151 y1 = top + (height * y1) / 100; 152 y2 = top + (height * y2) / 100; 153 154 const { mouse } = helper; 155 await mouse.down(x1, y1); 156 await mouse.move(x2, y1); 157 await mouse.up(); 158 await reflowContentPage(); 159 160 let newPointX = x2; 161 let newPointY = (y1 + y2) / 2; 162 163 const onRuleViewChanged = view.once("ruleview-changed"); 164 info("Adding new polygon point"); 165 BrowserTestUtils.synthesizeMouse( 166 ":root", 167 newPointX, 168 newPointY, 169 { clickCount: 2 }, 170 gBrowser.selectedTab.linkedBrowser 171 ); 172 173 await reflowContentPage(); 174 info("Waiting for rule view changed from shape change"); 175 await onRuleViewChanged; 176 177 // Decimal precision for coordinates with percentage units is 2 178 const precision = 2; 179 // Round to the desired decimal precision and cast to Number to remove trailing zeroes. 180 newPointX = Number(((newPointX * 100) / width).toFixed(precision)); 181 newPointY = Number(((newPointY * 100) / height).toFixed(precision)); 182 const definition = await getComputedPropertyValue( 183 selector, 184 property, 185 inspector 186 ); 187 ok( 188 definition.includes(`${newPointX}% ${newPointY}%`), 189 "Point successfuly added" 190 ); 191 192 await teardown({ selector, property, ...config }); 193 } 194 195 async function testPolygonRemovePoint(config) { 196 const { inspector, highlighters, highlighterTestFront, helper } = config; 197 const selector = "#polygon"; 198 const property = "clip-path"; 199 200 await setup({ selector, property, ...config }); 201 202 const points = await highlighterTestFront.getHighlighterNodeAttribute( 203 "shapes-polygon", 204 "points", 205 inspector.inspectorFront.getKnownHighlighter(HIGHLIGHTER_TYPE) 206 ); 207 const [x, y] = points.split(" ")[0].split(","); 208 const quads = await getAllAdjustedQuadsForContentPageElement(selector); 209 const { top, left, width, height } = quads.border[0].bounds; 210 211 const adjustedX = left + (width * x) / 100; 212 const adjustedY = top + (height * y) / 100; 213 214 info("Move mouse over first point in highlighter"); 215 const onEventHandled = highlighters.once("highlighter-event-handled"); 216 const { mouse } = helper; 217 await mouse.move(adjustedX, adjustedY); 218 await onEventHandled; 219 const markerHidden = await highlighterTestFront.getHighlighterNodeAttribute( 220 "shapes-marker-hover", 221 "hidden", 222 inspector.inspectorFront.getKnownHighlighter(HIGHLIGHTER_TYPE) 223 ); 224 ok(!markerHidden, "Marker on highlighter is visible"); 225 226 info("Double click on first point in highlighter"); 227 const onShapeChangeApplied = highlighters.once( 228 "shapes-highlighter-changes-applied" 229 ); 230 BrowserTestUtils.synthesizeMouse( 231 ":root", 232 adjustedX, 233 adjustedY, 234 { clickCount: 2 }, 235 gBrowser.selectedTab.linkedBrowser 236 ); 237 238 info("Waiting for shape changes to apply"); 239 await onShapeChangeApplied; 240 const definition = await getComputedPropertyValue( 241 selector, 242 property, 243 inspector 244 ); 245 ok(!definition.includes(`${x}% ${y}%`), "Point successfully removed"); 246 247 await teardown({ selector, property, ...config }); 248 } 249 250 async function testCircleMoveCenter(config) { 251 const { inspector, highlighters, highlighterTestFront, helper } = config; 252 const selector = "#circle"; 253 const property = "clip-path"; 254 255 const onShapeChangeApplied = highlighters.once( 256 "shapes-highlighter-changes-applied" 257 ); 258 await setup({ selector, property, ...config }); 259 260 const cx = parseFloat( 261 await highlighterTestFront.getHighlighterNodeAttribute( 262 "shapes-ellipse", 263 "cx", 264 inspector.inspectorFront.getKnownHighlighter(HIGHLIGHTER_TYPE) 265 ) 266 ); 267 const cy = parseFloat( 268 await highlighterTestFront.getHighlighterNodeAttribute( 269 "shapes-ellipse", 270 "cy", 271 inspector.inspectorFront.getKnownHighlighter(HIGHLIGHTER_TYPE) 272 ) 273 ); 274 const quads = await getAllAdjustedQuadsForContentPageElement(selector); 275 const { width, height } = quads.border[0].bounds; 276 const cxPixel = (width * cx) / 100; 277 const cyPixel = (height * cy) / 100; 278 const dx = width / 10; 279 const dy = height / 10; 280 281 info("Moving circle center"); 282 const { mouse } = helper; 283 await mouse.down(cxPixel, cyPixel, selector); 284 await mouse.move(cxPixel + dx, cyPixel + dy, selector); 285 await mouse.up(cxPixel + dx, cyPixel + dy, selector); 286 await reflowContentPage(); 287 info("Waiting for shape changes to apply"); 288 await onShapeChangeApplied; 289 290 const definition = await getComputedPropertyValue( 291 selector, 292 property, 293 inspector 294 ); 295 ok( 296 definition.includes(`at ${cx + 10}% ${cy + 10}%`), 297 "Circle center successfully moved" 298 ); 299 300 await teardown({ selector, property, ...config }); 301 } 302 303 async function testCircleWithoutPosition(config) { 304 const { inspector, highlighters, highlighterTestFront, helper } = config; 305 const selector = "#circle-without-position"; 306 const property = "clip-path"; 307 308 await setup({ selector, property, ...config }); 309 310 const rx = parseFloat( 311 await highlighterTestFront.getHighlighterNodeAttribute( 312 "shapes-ellipse", 313 "rx", 314 inspector.inspectorFront.getKnownHighlighter(HIGHLIGHTER_TYPE) 315 ) 316 ); 317 318 const cx = parseFloat( 319 await highlighterTestFront.getHighlighterNodeAttribute( 320 "shapes-ellipse", 321 "cx", 322 inspector.inspectorFront.getKnownHighlighter(HIGHLIGHTER_TYPE) 323 ) 324 ); 325 const cy = parseFloat( 326 await highlighterTestFront.getHighlighterNodeAttribute( 327 "shapes-ellipse", 328 "cy", 329 inspector.inspectorFront.getKnownHighlighter(HIGHLIGHTER_TYPE) 330 ) 331 ); 332 const quads = await getAllAdjustedQuadsForContentPageElement(selector); 333 const { width, height } = quads.content[0].bounds; 334 const highlightedNode = await getNodeFront(selector, inspector); 335 const computedStyle = 336 await highlightedNode.inspectorFront.pageStyle.getComputed(highlightedNode); 337 const paddingTop = parseFloat(computedStyle["padding-top"].value); 338 const paddingLeft = parseFloat(computedStyle["padding-left"].value); 339 const cxPixel = paddingLeft + (width * cx) / 100; 340 const cyPixel = paddingTop + (height * cy) / 100; 341 const rxPixel = cxPixel + (width * rx) / 100; 342 const dx = width / 10; 343 const dy = height / 10; 344 345 const { mouse } = helper; 346 info("Moving circle rx"); 347 let onShapeChangeApplied = highlighters.once( 348 "shapes-highlighter-changes-applied" 349 ); 350 await mouse.down(rxPixel, cyPixel, selector); 351 await mouse.move(rxPixel + dx, cyPixel, selector); 352 await mouse.up(rxPixel + dx, cyPixel, selector); 353 await reflowContentPage(); 354 await onShapeChangeApplied; 355 356 let definition = await getComputedPropertyValue( 357 selector, 358 property, 359 inspector 360 ); 361 is( 362 definition, 363 `circle(${rx + 10}%)`, 364 "Circle without position radiuses successfully changed" 365 ); 366 367 info("Moving circle center"); 368 onShapeChangeApplied = highlighters.once( 369 "shapes-highlighter-changes-applied" 370 ); 371 await mouse.down(cxPixel, cyPixel, selector); 372 await mouse.move(cxPixel + dx, cyPixel, selector); 373 await mouse.up(cxPixel + dx, cyPixel, selector); 374 await reflowContentPage(); 375 info("Waiting for shape changes to apply"); 376 await onShapeChangeApplied; 377 378 definition = await getComputedPropertyValue(selector, property, inspector); 379 is( 380 definition, 381 `circle(${rx + 10}% at ${cxPixel + dx}px ${cyPixel}px)`, 382 `Circle without position center (${cxPixel},${cyPixel}) successfully moved (${dx},${dy})` 383 ); 384 385 await teardown({ selector, property, ...config }); 386 } 387 388 async function testEllipseMoveRadius(config) { 389 const { inspector, highlighters, highlighterTestFront, helper } = config; 390 const selector = "#ellipse"; 391 const property = "clip-path"; 392 393 await setup({ selector, property, ...config }); 394 395 const rx = parseFloat( 396 await highlighterTestFront.getHighlighterNodeAttribute( 397 "shapes-ellipse", 398 "rx", 399 inspector.inspectorFront.getKnownHighlighter(HIGHLIGHTER_TYPE) 400 ) 401 ); 402 const ry = parseFloat( 403 await highlighterTestFront.getHighlighterNodeAttribute( 404 "shapes-ellipse", 405 "ry", 406 inspector.inspectorFront.getKnownHighlighter(HIGHLIGHTER_TYPE) 407 ) 408 ); 409 const cx = parseFloat( 410 await highlighterTestFront.getHighlighterNodeAttribute( 411 "shapes-ellipse", 412 "cx", 413 inspector.inspectorFront.getKnownHighlighter(HIGHLIGHTER_TYPE) 414 ) 415 ); 416 const cy = parseFloat( 417 await highlighterTestFront.getHighlighterNodeAttribute( 418 "shapes-ellipse", 419 "cy", 420 inspector.inspectorFront.getKnownHighlighter(HIGHLIGHTER_TYPE) 421 ) 422 ); 423 const quads = await getAllAdjustedQuadsForContentPageElement("#ellipse"); 424 const { width, height } = quads.content[0].bounds; 425 const highlightedNode = await getNodeFront(selector, inspector); 426 const computedStyle = 427 await highlightedNode.inspectorFront.pageStyle.getComputed(highlightedNode); 428 const paddingTop = parseFloat(computedStyle["padding-top"].value); 429 const paddingLeft = parseFloat(computedStyle["padding-left"].value); 430 const cxPixel = paddingLeft + (width * cx) / 100; 431 const cyPixel = paddingTop + (height * cy) / 100; 432 const rxPixel = cxPixel + (width * rx) / 100; 433 const ryPixel = cyPixel + (height * ry) / 100; 434 const dx = width / 10; 435 const dy = height / 10; 436 437 const { mouse } = helper; 438 info("Moving ellipse rx"); 439 await mouse.down(rxPixel, cyPixel, selector); 440 await mouse.move(rxPixel + dx, cyPixel, selector); 441 await mouse.up(rxPixel + dx, cyPixel, selector); 442 await reflowContentPage(); 443 444 info("Moving ellipse ry"); 445 const onShapeChangeApplied = highlighters.once( 446 "shapes-highlighter-changes-applied" 447 ); 448 await mouse.down(cxPixel, ryPixel, selector); 449 await mouse.move(cxPixel, ryPixel - dy, selector); 450 await mouse.up(cxPixel, ryPixel - dy, selector); 451 await reflowContentPage(); 452 await onShapeChangeApplied; 453 454 const definition = await getComputedPropertyValue( 455 selector, 456 property, 457 inspector 458 ); 459 ok( 460 definition.includes(`${rx + 10}% ${ry - 10}%`), 461 "Ellipse radiuses successfully moved" 462 ); 463 464 await teardown({ selector, property, ...config }); 465 } 466 467 async function testInsetMoveEdges(config) { 468 const { inspector, highlighters, highlighterTestFront, helper } = config; 469 const selector = "#inset"; 470 const property = "clip-path"; 471 472 await setup({ selector, property, ...config }); 473 474 const x = parseFloat( 475 await highlighterTestFront.getHighlighterNodeAttribute( 476 "shapes-rect", 477 "x", 478 inspector.inspectorFront.getKnownHighlighter(HIGHLIGHTER_TYPE) 479 ) 480 ); 481 const y = parseFloat( 482 await highlighterTestFront.getHighlighterNodeAttribute( 483 "shapes-rect", 484 "y", 485 inspector.inspectorFront.getKnownHighlighter(HIGHLIGHTER_TYPE) 486 ) 487 ); 488 const width = parseFloat( 489 await highlighterTestFront.getHighlighterNodeAttribute( 490 "shapes-rect", 491 "width", 492 inspector.inspectorFront.getKnownHighlighter(HIGHLIGHTER_TYPE) 493 ) 494 ); 495 const height = parseFloat( 496 await highlighterTestFront.getHighlighterNodeAttribute( 497 "shapes-rect", 498 "height", 499 inspector.inspectorFront.getKnownHighlighter(HIGHLIGHTER_TYPE) 500 ) 501 ); 502 const quads = await getAllAdjustedQuadsForContentPageElement(selector); 503 const { width: elemWidth, height: elemHeight } = quads.content[0].bounds; 504 505 const left = (elemWidth * x) / 100; 506 const top = (elemHeight * y) / 100; 507 const right = left + (elemWidth * width) / 100; 508 const bottom = top + (elemHeight * height) / 100; 509 const xCenter = (left + right) / 2; 510 const yCenter = (top + bottom) / 2; 511 const dx = elemWidth / 10; 512 const dy = elemHeight / 10; 513 const { mouse } = helper; 514 515 info("Moving inset top"); 516 let onShapeChangeApplied = highlighters.once( 517 "shapes-highlighter-changes-applied" 518 ); 519 await mouse.down(xCenter, top, selector); 520 await mouse.move(xCenter, top + dy, selector); 521 await mouse.up(xCenter, top + dy, selector); 522 await reflowContentPage(); 523 await onShapeChangeApplied; 524 525 // TODO: Test bottom inset marker after Bug 1456777 is fixed. 526 // Bug 1456777 - https://bugzilla.mozilla.org/show_bug.cgi?id=1456777 527 // The test element is larger than the viewport when tests run in headless mode. 528 // When moved, the bottom marker value is getting clamped to the viewport. 529 530 info("Moving inset left"); 531 onShapeChangeApplied = highlighters.once( 532 "shapes-highlighter-changes-applied" 533 ); 534 await mouse.down(left, yCenter, selector); 535 await mouse.move(left + dx, yCenter, selector); 536 await mouse.up(left + dx, yCenter, selector); 537 await reflowContentPage(); 538 await onShapeChangeApplied; 539 540 info("Moving inset right"); 541 onShapeChangeApplied = highlighters.once( 542 "shapes-highlighter-changes-applied" 543 ); 544 await mouse.down(right, yCenter, selector); 545 await mouse.move(right + dx, yCenter, selector); 546 await mouse.up(right + dx, yCenter, selector); 547 await reflowContentPage(); 548 await onShapeChangeApplied; 549 550 const definition = await getComputedPropertyValue( 551 selector, 552 property, 553 inspector 554 ); 555 556 // NOTE: No change to bottom inset until Bug 1456777 is fixed. 557 ok( 558 definition.includes( 559 `${top + dy}px ${elemWidth - right - dx}px ${100 - y - height}% ${ 560 x + 10 561 }%` 562 ), 563 "Inset edges successfully moved" 564 ); 565 566 await teardown({ selector, property, ...config }); 567 }