151 votes

Selenium attend que le document soit prêt

Quelqu'un peut-il me dire comment faire en sorte que Selenium attende le chargement complet de la page ? Je veux quelque chose de générique, je sais que je peux configurer WebDriverWait et appeler quelque chose comme 'find' pour le faire attendre mais je ne veux pas aller aussi loin. J'ai juste besoin de tester que la page se charge avec succès et de passer à la page suivante à tester.

J'ai trouvé quelque chose en .net mais je n'ai pas réussi à le faire fonctionner en java ...

IWait<IWebDriver> wait = new OpenQA.Selenium.Support.UI.WebDriverWait(driver, TimeSpan.FromSeconds(30.00));
wait.Until(driver1 => ((IJavaScriptExecutor)driver).ExecuteScript("return document.readyState").Equals("complete"));

Quelqu'un a-t-il une idée ?

104voto

Slanec Points 14354

La solution que vous proposez n'attend que DOM readyState pour signaler complete . Mais Selenium essaie par défaut d'attendre ces éléments (et un peu plus) lors du chargement de la page via la fonction driver.get() y element.click() méthodes. Elles sont déjà bloquantes, elles attendent que la page soit complètement chargée et elles devraient fonctionner correctement.

Les problèmes, évidemment, sont les redirections via les requêtes AJAX et l'exécution de scripts - ceux-ci ne peuvent pas être capturés par Selenium, il n'attend pas qu'ils se terminent. De même, vous ne pouvez pas les attraper de manière fiable via readyState - il attend un peu, ce qui peut être utile, mais il signalera complete bien avant que tout le contenu AJAX ne soit téléchargé.

Il n'existe pas de solution générale qui fonctionnerait partout et pour tout le monde, c'est pourquoi c'est difficile et que chacun utilise quelque chose d'un peu différent.

La règle générale est de s'en remettre à WebDriver pour faire sa part, puis d'utiliser des attentes implicites, puis des attentes explicites pour les éléments que vous voulez affirmer sur la page, mais il y a beaucoup d'autres techniques possibles. Vous devez choisir celle (ou une combinaison de plusieurs d'entre elles) qui fonctionne le mieux dans votre cas, sur votre page testée.

Voir mes deux réponses à ce sujet pour plus d'informations :

84voto

Manigandan Points 1445

Essayez ce code :

  driver.manage().timeouts().pageLoadTimeout(10, TimeUnit.SECONDS);

Le code ci-dessus attendra jusqu'à 10 secondes pour le chargement de la page. Si le chargement de la page dépasse le temps imparti, il lancera la commande TimeoutException . Vous attrapez l'exception et répondez à vos besoins. Je ne suis pas sûr qu'il quitte le chargement de la page après la levée de l'exception. Je n'ai pas encore essayé ce code. Je veux juste l'essayer.

Il s'agit d'une attente implicite. Si vous le définissez une fois, il aura une portée jusqu'à la destruction de l'instance du pilote Web.

Voir le la documentation pour WebDriver.Timeouts pour plus d'informations.

73voto

Ben Dyer Points 544

Voici une version Java fonctionnelle de l'exemple que vous avez donné :

void waitForLoad(WebDriver driver) {
    new WebDriverWait(driver, 30).until((ExpectedCondition<Boolean>) wd ->
            ((JavascriptExecutor) wd).executeScript("return document.readyState").equals("complete"));
}

Exemple pour c# :

public static void WaitForLoad(IWebDriver driver, int timeoutSec = 15)
{
    IJavaScriptExecutor js = (IJavaScriptExecutor)driver;
    WebDriverWait wait = new WebDriverWait(driver, new TimeSpan(0, 0, timeoutSec));
    wait.Until(wd => js.ExecuteScript("return document.readyState").ToString() == "complete");
}

Exemple pour PHP :

final public function waitUntilDomReadyState(RemoteWebDriver $webDriver): void
{
    $webDriver->wait()->until(function () {
        return $webDriver->executeScript('return document.readyState') === 'complete';
    });
}

14voto

hwjp Points 3041

Voici ma tentative de solution complètement générique, en Python :

Tout d'abord, une fonction "wait" générique (utilisez un WebDriverWait si vous voulez, je les trouve moches) :

def wait_for(condition_function):
    start_time = time.time()
    while time.time() < start_time + 3:
        if condition_function():
            return True
        else:
            time.sleep(0.1)
    raise Exception('Timeout waiting for {}'.format(condition_function.__name__))

Ensuite, la solution s'appuie sur le fait que Selenium enregistre un numéro d'identification (interne) pour tous les éléments d'une page, y compris l'élément de haut niveau. <html> élément. Lorsqu'une page est rafraîchie ou chargée, elle reçoit un nouvel élément html avec un nouvel ID.

Ainsi, supposons que vous souhaitiez cliquer sur un lien dont le texte est "mon lien", par exemple :

old_page = browser.find_element_by_tag_name('html')

browser.find_element_by_link_text('my link').click()

def page_has_loaded():
    new_page = browser.find_element_by_tag_name('html')
    return new_page.id != old_page.id

wait_for(page_has_loaded)

Pour une aide plus pythique, réutilisable et générique, vous pouvez créer un gestionnaire de contexte :

from contextlib import contextmanager

@contextmanager
def wait_for_page_load(browser):
    old_page = browser.find_element_by_tag_name('html')

    yield

    def page_has_loaded():
        new_page = browser.find_element_by_tag_name('html')
        return new_page.id != old_page.id

    wait_for(page_has_loaded)

Et ensuite vous pouvez l'utiliser sur à peu près n'importe quelle interaction avec le sélénium :

with wait_for_page_load(browser):
    browser.find_element_by_link_text('my link').click()

Je pense que c'est à l'épreuve des balles ! Et toi, qu'en penses-tu ?

Plus d'informations dans un article de blog à ce sujet ici .

7voto

Rubanov Points 1922

J'ai eu un problème similaire. Je devais attendre que mon document soit prêt mais aussi que tous les appels Ajax soient terminés. La deuxième condition s'est avérée difficile à détecter. Finalement, j'ai vérifié les appels Ajax actifs et cela a fonctionné.

Javascript :

return (document.readyState == 'complete' && jQuery.active == 0)

Méthode C# complète :

private void WaitUntilDocumentIsReady(TimeSpan timeout)
{
    var javaScriptExecutor = WebDriver as IJavaScriptExecutor;
    var wait = new WebDriverWait(WebDriver, timeout);            

    // Check if document is ready
    Func<IWebDriver, bool> readyCondition = webDriver => javaScriptExecutor
        .ExecuteScript("return (document.readyState == 'complete' && jQuery.active == 0)");
    wait.Until(readyCondition);
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X