browser_test_position_sticky.js (4714B)
1 /* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */ 2 /* vim: set sts=2 sw=2 et tw=80: */ 3 "use strict"; 4 5 Services.scriptloader.loadSubScript( 6 "chrome://mochitests/content/browser/gfx/layers/apz/test/mochitest/apz_test_utils.js", 7 this 8 ); 9 10 Services.scriptloader.loadSubScript( 11 "chrome://mochitests/content/browser/gfx/layers/apz/test/mochitest/apz_test_native_event_utils.js", 12 this 13 ); 14 15 Services.scriptloader.loadSubScript( 16 "chrome://mochikit/content/tests/SimpleTest/WindowSnapshot.js", 17 this 18 ); 19 20 // usesFailurePatterns is defined in SimpleTest.js and used in 21 // WindowSnapshot.js but SimpleTest.js can't be loaded in browser mochitests 22 // (there's an equivalent script named browser-test.js for browser mochitests), 23 // so we define usesFailurePatterns which just returns false to make functions 24 // in WindowSnapshot.js work without loading SimpleTest.js. 25 function usesFailurePatterns() { 26 return false; 27 } 28 29 async function convertDataURLtoCanvas(aDataURL, aWidth, aHeight) { 30 const canvas = document.createElementNS( 31 "http://www.w3.org/1999/xhtml", 32 "canvas" 33 ); 34 canvas.width = aWidth; 35 canvas.height = aHeight; 36 const image = new Image(); 37 const ctx = canvas.getContext("2d"); 38 const loadPromise = new Promise(resolve => 39 image.addEventListener("load", resolve) 40 ); 41 image.src = aDataURL; 42 await loadPromise; 43 ctx.drawImage(image, 0, 0); 44 return canvas; 45 } 46 47 add_task(async () => { 48 function httpURL(filename) { 49 let chromeURL = getRootDirectory(gTestPath) + filename; 50 return chromeURL.replace( 51 "chrome://mochitests/content/", 52 "http://mochi.test:8888/" 53 ); 54 } 55 56 const url = httpURL("helper_position_sticky_flicker.html"); 57 const tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, url); 58 59 const { rect, scrollbarWidth } = await SpecialPowers.spawn( 60 tab.linkedBrowser, 61 [], 62 async () => { 63 const sticky = content.document.getElementById("sticky"); 64 65 // Get the area in the screen coords where the position:sticky element is. 66 let stickyRect = sticky.getBoundingClientRect(); 67 stickyRect.x += content.window.mozInnerScreenX; 68 stickyRect.y += content.window.mozInnerScreenY; 69 70 // generate some DIVs to make the page complex enough. 71 for (let i = 1; i <= 120000; i++) { 72 const div = content.document.createElement("div"); 73 div.innerText = `${i}`; 74 content.document.body.appendChild(div); 75 } 76 77 await content.wrappedJSObject.promiseApzFlushedRepaints(); 78 await content.wrappedJSObject.waitUntilApzStable(); 79 80 let w = {}, 81 h = {}; 82 SpecialPowers.DOMWindowUtils.getScrollbarSizes( 83 content.document.documentElement, 84 w, 85 h 86 ); 87 88 // Reduce the scrollbar width from the sticky area. 89 stickyRect.width -= w.value; 90 return { 91 rect: stickyRect, 92 scrollbarWidth: w.value, 93 }; 94 } 95 ); 96 97 // Take a snapshot where the position:sticky element is initially painted. 98 const referenceDataURL = await getSnapshot(rect); 99 const referenceCanvas = await convertDataURLtoCanvas( 100 referenceDataURL, 101 rect.width, 102 rect.height 103 ); 104 105 let mouseX = window.innerWidth - scrollbarWidth / 2; 106 let mouseY = tab.linkedBrowser.getBoundingClientRect().y + 5; 107 108 // Scroll fast to cause checkerboarding multiple times. 109 const dragFinisher = await promiseNativeMouseDrag( 110 window, 111 mouseX, 112 mouseY, 113 0, 114 window.innerHeight, 115 100 116 ); 117 118 // On debug builds there seems to be no chance that the content process gets 119 // painted during above promiseNativeMouseDrag call, wait two frames to make 120 // sure it happens so that this test is likely able to fail without proper 121 // fix. 122 if (AppConstants.DEBUG) { 123 await SpecialPowers.spawn(tab.linkedBrowser, [], async () => { 124 await content.wrappedJSObject.promiseFrame(content.window); 125 await content.wrappedJSObject.promiseFrame(content.window); 126 }); 127 } 128 129 // Take a snapshot again where the position:sticky element should be painted. 130 const snapshotDataURL = await getSnapshot(rect); 131 const snapshotCanvas = await convertDataURLtoCanvas( 132 snapshotDataURL, 133 rect.width, 134 rect.height 135 ); 136 137 await dragFinisher(); 138 139 const disablePixelAlignment = SpecialPowers.getBoolPref( 140 "layout.disable-pixel-alignment" 141 ); 142 // With disabling pixel alignment, there appears 1px line glitch at the top of 143 // the image, we allow it. 144 const fuzz = disablePixelAlignment 145 ? { maxDifference: 1, numDifferentPixels: rect.width } 146 : null; 147 148 assertSnapshots( 149 snapshotCanvas, 150 referenceCanvas, 151 true /* expectEqual */, 152 fuzz, 153 "test case", 154 "reference" 155 ); 156 157 BrowserTestUtils.removeTab(tab); 158 });