browser_animation_keyframes-graph_computed-value-path_easing-hint.js (9338B)
1 /* Any copyright is dedicated to the Public Domain. 2 http://creativecommons.org/publicdomain/zero/1.0/ */ 3 4 "use strict"; 5 6 // Test for following easing hint in ComputedValuePath. 7 // * element existence 8 // * path segments 9 // * hint text 10 11 const TEST_DATA = [ 12 { 13 targetClass: "no-easing", 14 properties: [ 15 { 16 name: "opacity", 17 expectedHints: [ 18 { 19 hint: "linear", 20 path: [ 21 { x: 0, y: 100 }, 22 { x: 500, y: 50 }, 23 { x: 1000, y: 0 }, 24 ], 25 }, 26 ], 27 }, 28 ], 29 }, 30 { 31 targetClass: "effect-easing", 32 properties: [ 33 { 34 name: "opacity", 35 expectedHints: [ 36 { 37 hint: "linear", 38 path: [ 39 { x: 0, y: 100 }, 40 { x: 199, y: 81 }, 41 { x: 200, y: 80 }, 42 { x: 399, y: 61 }, 43 { x: 400, y: 60 }, 44 { x: 599, y: 41 }, 45 { x: 600, y: 40 }, 46 { x: 799, y: 21 }, 47 { x: 800, y: 20 }, 48 { x: 1000, y: 0 }, 49 ], 50 }, 51 ], 52 }, 53 ], 54 }, 55 { 56 targetClass: "keyframe-easing", 57 properties: [ 58 { 59 name: "opacity", 60 expectedHints: [ 61 { 62 hint: "steps(2)", 63 path: [ 64 { x: 0, y: 100 }, 65 { x: 499, y: 100 }, 66 { x: 500, y: 50 }, 67 { x: 999, y: 50 }, 68 { x: 1000, y: 0 }, 69 ], 70 }, 71 ], 72 }, 73 ], 74 }, 75 { 76 targetClass: "both-easing", 77 properties: [ 78 { 79 name: "margin-left", 80 expectedHints: [ 81 { 82 hint: "steps(1)", 83 path: [ 84 { x: 0, y: 0 }, 85 { x: 999, y: 0 }, 86 { x: 1000, y: 100 }, 87 ], 88 }, 89 ], 90 }, 91 { 92 name: "opacity", 93 expectedHints: [ 94 { 95 hint: "steps(2)", 96 path: [ 97 { x: 0, y: 100 }, 98 { x: 499, y: 100 }, 99 { x: 500, y: 50 }, 100 { x: 999, y: 50 }, 101 { x: 1000, y: 0 }, 102 ], 103 }, 104 ], 105 }, 106 ], 107 }, 108 { 109 targetClass: "narrow-keyframes", 110 properties: [ 111 { 112 name: "opacity", 113 expectedHints: [ 114 { 115 hint: "linear", 116 path: [ 117 { x: 0, y: 0 }, 118 { x: 100, y: 100 }, 119 ], 120 }, 121 { 122 hint: "steps(1)", 123 path: [ 124 { x: 129, y: 100 }, 125 { x: 130, y: 0 }, 126 ], 127 }, 128 { 129 hint: "linear", 130 path: [ 131 { x: 130, y: 0 }, 132 { x: 1000, y: 100 }, 133 ], 134 }, 135 ], 136 }, 137 ], 138 }, 139 { 140 targetClass: "duplicate-keyframes", 141 properties: [ 142 { 143 name: "opacity", 144 expectedHints: [ 145 { 146 hint: "linear", 147 path: [ 148 { x: 0, y: 0 }, 149 { x: 500, y: 100 }, 150 ], 151 }, 152 { 153 hint: "", 154 path: [ 155 { x: 500, y: 100 }, 156 { x: 500, y: 0 }, 157 ], 158 }, 159 { 160 hint: "steps(1)", 161 path: [ 162 { x: 500, y: 0 }, 163 { x: 999, y: 0 }, 164 { x: 1000, y: 100 }, 165 ], 166 }, 167 ], 168 }, 169 ], 170 }, 171 { 172 targetClass: "color-keyframes", 173 properties: [ 174 { 175 name: "color", 176 expectedHints: [ 177 { 178 hint: "ease-in", 179 rect: { 180 x: 0, 181 height: 100, 182 width: 400, 183 }, 184 }, 185 { 186 hint: "ease-out", 187 rect: { 188 x: 400, 189 height: 100, 190 width: 600, 191 }, 192 }, 193 ], 194 }, 195 ], 196 }, 197 { 198 targetClass: "jump-start", 199 properties: [ 200 { 201 name: "opacity", 202 expectedHints: [ 203 { 204 hint: "steps(2, jump-start)", 205 path: [ 206 { x: 0, y: 50 }, 207 { x: 499, y: 50 }, 208 { x: 500, y: 0 }, 209 { x: 1000, y: 0 }, 210 ], 211 }, 212 ], 213 }, 214 ], 215 }, 216 { 217 targetClass: "jump-end", 218 properties: [ 219 { 220 name: "opacity", 221 expectedHints: [ 222 { 223 hint: "steps(2)", 224 path: [ 225 { x: 0, y: 100 }, 226 { x: 499, y: 100 }, 227 { x: 500, y: 50 }, 228 { x: 999, y: 50 }, 229 { x: 1000, y: 0 }, 230 ], 231 }, 232 ], 233 }, 234 ], 235 }, 236 { 237 targetClass: "jump-both", 238 properties: [ 239 { 240 name: "opacity", 241 expectedHints: [ 242 { 243 hint: "steps(3, jump-both)", 244 path: [ 245 { x: 0, y: 75 }, 246 { x: 330, y: 75 }, 247 { x: 340, y: 50 }, 248 { x: 660, y: 50 }, 249 { x: 670, y: 25 }, 250 { x: 999, y: 25 }, 251 { x: 1000, y: 0 }, 252 ], 253 }, 254 ], 255 }, 256 ], 257 }, 258 ]; 259 260 // Prevent test timeout's on windows code coverage: Bug 1470757 261 requestLongerTimeout(2); 262 263 add_task(async function () { 264 await addTab(URL_ROOT + "doc_multi_easings.html"); 265 await removeAnimatedElementsExcept(TEST_DATA.map(t => `.${t.targetClass}`)); 266 const { animationInspector, panel } = await openAnimationInspector(); 267 268 for (const { properties, targetClass } of TEST_DATA) { 269 info(`Checking keyframes graph for ${targetClass}`); 270 const onDetailRendered = animationInspector.once( 271 "animation-keyframes-rendered" 272 ); 273 await clickOnAnimationByTargetSelector( 274 animationInspector, 275 panel, 276 `.${targetClass}` 277 ); 278 await onDetailRendered; 279 280 for (const { name, expectedHints } of properties) { 281 const testTarget = `${name} in ${targetClass}`; 282 info(`Checking easing hint for ${testTarget}`); 283 info(`Checking easing hint existence for ${testTarget}`); 284 const hintEls = panel.querySelectorAll(`.${name} .hint`); 285 is( 286 hintEls.length, 287 expectedHints.length, 288 `Count of easing hint elements of ${testTarget} ` + 289 `should be ${expectedHints.length}` 290 ); 291 292 for (let i = 0; i < expectedHints.length; i++) { 293 const hintTarget = `hint[${i}] of ${testTarget}`; 294 295 info(`Checking ${hintTarget}`); 296 const hintEl = hintEls[i]; 297 const expectedHint = expectedHints[i]; 298 299 info(`Checking <title> in ${hintTarget}`); 300 const titleEl = hintEl.querySelector("title"); 301 ok(titleEl, `<title> element in ${hintTarget} should be existence`); 302 is( 303 titleEl.textContent, 304 expectedHint.hint, 305 `Content of <title> in ${hintTarget} should be ${expectedHint.hint}` 306 ); 307 308 let interactionEl = null; 309 let displayedEl = null; 310 if (expectedHint.path) { 311 info(`Checking <path> in ${hintTarget}`); 312 interactionEl = hintEl.querySelector("path"); 313 displayedEl = interactionEl; 314 ok( 315 interactionEl, 316 `The <path> element in ${hintTarget} should be existence` 317 ); 318 assertPathSegments(interactionEl, false, expectedHint.path); 319 } else { 320 info(`Checking <rect> in ${hintTarget}`); 321 interactionEl = hintEl.querySelector("rect"); 322 displayedEl = hintEl.querySelector("line"); 323 ok( 324 interactionEl, 325 `The <rect> element in ${hintTarget} should be existence` 326 ); 327 is( 328 parseInt(interactionEl.getAttribute("x"), 10), 329 expectedHint.rect.x, 330 `x of <rect> in ${hintTarget} should be ${expectedHint.rect.x}` 331 ); 332 is( 333 parseInt(interactionEl.getAttribute("width"), 10), 334 expectedHint.rect.width, 335 `width of <rect> in ${hintTarget} should be ${expectedHint.rect.width}` 336 ); 337 } 338 339 info(`Checking interaction for ${hintTarget}`); 340 interactionEl.scrollIntoView(false); 341 const win = hintEl.ownerGlobal; 342 // Mouse over the pathEl. 343 ok( 344 isStrokeChangedByMouseOver(interactionEl, displayedEl, win), 345 `stroke-opacity of hintEl for ${hintTarget} should be 1 ` + 346 "while mouse is over the element" 347 ); 348 // Mouse out from pathEl. 349 EventUtils.synthesizeMouse( 350 panel.querySelector(".animation-toolbar"), 351 0, 352 0, 353 { type: "mouseover" }, 354 win 355 ); 356 is( 357 parseInt(win.getComputedStyle(displayedEl).strokeOpacity, 10), 358 0, 359 `stroke-opacity of hintEl for ${hintTarget} should be 0 ` + 360 "while mouse is out from the element" 361 ); 362 } 363 } 364 } 365 }); 366 367 function isStrokeChangedByMouseOver(mouseoverEl, displayedEl, win) { 368 const boundingBox = mouseoverEl.getBoundingClientRect(); 369 const x = boundingBox.width / 2; 370 371 for (let y = 0; y < boundingBox.height; y++) { 372 EventUtils.synthesizeMouse(mouseoverEl, x, y, { type: "mouseover" }, win); 373 374 if (win.getComputedStyle(displayedEl).strokeOpacity == 1) { 375 return true; 376 } 377 } 378 379 return false; 380 }