Skip to content

Instantly share code, notes, and snippets.

@munro
Created January 5, 2016 21:06
Show Gist options
  • Star 11 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save munro/7f81bd1657499866f7c2 to your computer and use it in GitHub Desktop.
Save munro/7f81bd1657499866f7c2 to your computer and use it in GitHub Desktop.
Selenium wait for all images to load, including background images.
from textwrap import dedent
def wait_until_images_loaded(driver, timeout=30):
"""Waits for all images & background images to load."""
driver.set_script_timeout(timeout)
driver.execute_async_script(dedent('''
function extractCSSURL(text) {
var url_str = text.replace(/.*url\((.*)\).*/, '$1');
if (url_str[0] === '"') {
return JSON.parse(url_str);
}
if (url_str[0] === "'") {
return JSON.parse(
url_str
.replace(/'/g, '__DOUBLE__QUOTE__HERE__')
.replace(/"/g, "'")
.replace(/__DOUBLE__QUOTE__HERE__/g, '"')
);
}
return url_str;
}
function imageResolved(url) {
return new $.Deferred(function (d) {
var img = new Image();
img.onload = img.onload = function () {
d.resolve(url);
};
img.src = url;
if (img.complete) {
d.resolve(url);
}
}).promise();
}
var callback = arguments[arguments.length - 1];
$.when.apply($, [].concat(
$('img[src]')
.map(function (elem) { return $(this).attr('src'); })
.toArray(),
$('[style*="url("]')
.map(function () { return extractCSSURL($(this).attr('style')); })
.toArray()
.map(function (url) { return imageResolved(url); })
)).then(function () { callback(arguments); });
return undefined;
'''))
@madsheep
Copy link

Hi man - just letting you know, this is pretty cool. I know you did it 5 years ago, but you should know, you saved a poor soul from doing dumb stuff today. Kudos over the internet.

@munro
Copy link
Author

munro commented Oct 15, 2020

@madsheep aw thanks man, I’m glad it helped!

@jamesrealiflex
Copy link

Bro sorry for the inconvenience but I don't know how the script works can you help me, I'm trying to wait for the visibility of an image on a

@kker4m
Copy link

kker4m commented Apr 23, 2023

It's an incredible job. Thank you for accomplishing this great work 8 years ago.

@wallacefcosta
Copy link

Awesome yet functional for the poor souls, not for making bad decisions, thank you very much!!!

@munro
Copy link
Author

munro commented May 26, 2023

I haven't fully tested this (which is why I haven't updated the gist) but here's code that works without jQuery dependency:

Let me know if this works and I'll update the gist!!

// Function to extract URL from CSS 'url()' function
function extractCSSURL(text) {
    var url_str = text.replace(/.*url\((.*)\).*/, '$1');
    // If the URL is enclosed with double quotes
    if (url_str[0] === '"') {
        return JSON.parse(url_str);
    }
    // If the URL is enclosed with single quotes
    if (url_str[0] === "'") {
        return JSON.parse(
            url_str
                .replace(/'/g, '__DOUBLE__QUOTE__HERE__')
                .replace(/"/g, "'")
                .replace(/__DOUBLE__QUOTE__HERE__/g, '"')
        );
    }
    // Return the URL as is
    return url_str;
}

// Function to create a promise that resolves when the image is loaded
function imageResolved(url) {
    return new Promise(function (resolve) {
        var img = new Image();
        img.onload = function () {
            resolve(url);
        };
        img.src = url;
        // If the image is already loaded, resolve the promise immediately
        if (img.complete) {
            resolve(url);
        }
    });
}

// The last argument is expected to be a callback function
var callback = arguments[arguments.length - 1];

Promise.all([
    // Get all img tags, create a promise for each one
    ...Array.from(document.querySelectorAll('img[src]'), img => imageResolved(img.src)),
    // Get all inline styles with 'url()' and create a promise for each one
    ...Array.from(document.querySelectorAll('[style*="url("]'), elem => imageResolved(extractCSSURL(elem.style.cssText)))
])
.then(function () {
    // After all images are loaded, wait for all fonts to load
    return document.fonts.ready;
})
.then(function() {
    // After all fonts are loaded, check for images in CSS stylesheets
    let cssImagesPromises = [];
    for(let i = 0; i < document.styleSheets.length; i++) {
        let rules = document.styleSheets[i].cssRules;
        for (let j = 0; j < rules.length; j++) {
            let style = rules[j].style;
            // Check if a background image is found and if it's a URL
            if (style && String(style.backgroundImage).startsWith('url(')) {
                let url = extractCSSURL(style.backgroundImage);
                cssImagesPromises.push(imageResolved(url));
            }
        }
    }
    return Promise.all(cssImagesPromises);
})
.then(function () { 
    // Call the callback function when all promises are resolved
    callback(arguments); 
});

return undefined;

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment