@@ -191,21 +191,20 @@ export function runTestCases(testCases: TestsCase[]) {
191191 .intercom-lightweight-app {
192192 display: none !important;
193193 }
194-
195- /* Switch image rendering to pixelated */
196- img {
197- image-rendering: pixelated;
198- }
199194 ` ,
200195 threshold : screenshotOptions ?. threshold ?? undefined ,
201196 fullPage : testEntry . fullPage ?? false ,
202197 beforeScreenshot : async ( { runStabilization } ) => {
203198 await runStabilization ( ) ;
204199 await waitForIcons ( page ) ;
200+ await roundImageSizes ( page ) ;
205201 if ( screenshotOptions ?. waitForTOCScrolling !== false ) {
206202 await waitForTOCScrolling ( page ) ;
207203 }
208204 } ,
205+ afterScreenshot : async ( ) => {
206+ await restoreImageSizes ( page ) ;
207+ } ,
209208 } ) ;
210209 }
211210 } ) ;
@@ -326,7 +325,14 @@ async function waitForIcons(page: Page) {
326325 function loadImage ( src : string ) {
327326 return new Promise ( ( resolve , reject ) => {
328327 const img = new Image ( ) ;
329- img . onload = ( ) => resolve ( img ) ;
328+ img . onload = ( ) => {
329+ // Wait two frames to ensure the image has been rendered
330+ requestAnimationFrame ( ( ) => {
331+ requestAnimationFrame ( ( ) => {
332+ resolve ( true ) ;
333+ } ) ;
334+ } ) ;
335+ } ;
330336 img . onerror = ( _error ) => reject ( new Error ( `Failed to load image: ${ src } ` ) ) ;
331337 img . src = src ;
332338 } ) ;
@@ -348,6 +354,70 @@ async function waitForIcons(page: Page) {
348354 } ) ;
349355}
350356
357+ /**
358+ * Take all images, measure them and set their width and height to rounded values.
359+ */
360+ async function roundImageSizes ( page : Page ) {
361+ await page . waitForFunction ( async ( ) => {
362+ const images = Array . from ( document . querySelectorAll ( 'img' ) ) ;
363+ await Promise . all (
364+ images . map ( async ( img ) => {
365+ return new Promise < void > ( ( resolve ) => {
366+ const setDimensions = ( ) => {
367+ // Mark it as stabilized
368+ img . dataset . stabilized = 'true' ;
369+ // Preserve the original width and height
370+ img . dataset . originalWidth = img . style . width ?? '' ;
371+ img . dataset . originalHeight = img . style . height ?? '' ;
372+ const rect = img . getBoundingClientRect ( ) ;
373+ img . style . width = `${ Math . round ( rect . width ) } px` ;
374+ img . style . height = `${ Math . round ( rect . height ) } px` ;
375+ resolve ( ) ;
376+ } ;
377+
378+ if ( img . complete ) {
379+ setDimensions ( ) ;
380+ } else {
381+ const cleanup = ( ) => {
382+ img . removeEventListener ( 'load' , handleLoad ) ;
383+ img . removeEventListener ( 'error' , handleError ) ;
384+ } ;
385+ const handleError = ( ) => {
386+ cleanup ( ) ;
387+ resolve ( ) ;
388+ } ;
389+ const handleLoad = ( ) => {
390+ cleanup ( ) ;
391+ setDimensions ( ) ;
392+ } ;
393+ img . addEventListener ( 'load' , handleLoad ) ;
394+ img . addEventListener ( 'error' , handleError ) ;
395+ }
396+ } ) ;
397+ } )
398+ ) ;
399+ return true ;
400+ } ) ;
401+ }
402+
403+ /**
404+ * Restore images to their original size.
405+ */
406+ async function restoreImageSizes ( page : Page ) {
407+ await page . evaluate ( ( ) => {
408+ const images = Array . from ( document . querySelectorAll ( 'img[data-stabilized]' ) ) ;
409+ images . forEach ( ( img ) => {
410+ if ( img instanceof HTMLImageElement ) {
411+ img . style . width = img . dataset . originalWidth ?? '' ;
412+ img . style . height = img . dataset . originalHeight ?? '' ;
413+ delete img . dataset . originalWidth ;
414+ delete img . dataset . originalHeight ;
415+ delete img . dataset . stabilized ;
416+ }
417+ } ) ;
418+ } ) ;
419+ }
420+
351421/**
352422 * Wait for TOC to be correctly scrolled into view.
353423 */
0 commit comments