Selenium-WebDriver'dan Java'da birkaç saniye beklemesini nasıl isteyebilirim?


100

Java Selenium-WebDriver üzerinde çalışıyorum. ekledim

driver.manage().timeouts().implicitlyWait(2, TimeUnit.SECONDS);

ve

WebElement textbox = driver.findElement(By.id("textbox"));

çünkü Uygulamalarımın Kullanıcı Arayüzünü yüklemesi birkaç saniye sürüyor. Bu yüzden 2 saniye örtük bekleme ayarladım. ancak öğe metin kutusunu bulamadım

Sonra eklerim Thread.sleep(2000);

Şimdi iyi çalışıyor. Hangisi daha iyi bir yol?


Yanıtlar:


123

İki tür bekleme vardır: açık ve örtük bekleme. Açık bekleme fikri şudur:

WebDriverWait.until(condition-that-finds-the-element);

Örtülü bekleme kavramı

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

Burada detaylarda farklılık elde edebilirsiniz .

Bu tür durumlarda açık beklemeyi tercih ederim ( fluentWaitözellikle):

public WebElement fluentWait(final By locator) {
    Wait<WebDriver> wait = new FluentWait<WebDriver>(driver)
            .withTimeout(30, TimeUnit.SECONDS)
            .pollingEvery(5, TimeUnit.SECONDS)
            .ignoring(NoSuchElementException.class);

    WebElement foo = wait.until(new Function<WebDriver, WebElement>() {
        public WebElement apply(WebDriver driver) {
            return driver.findElement(locator);
        }
    });

    return  foo;
};

fluentWaitişlevi bulunan web öğenizi döndürür. Dokümantasyondan fluentWait: Zaman aşımı ve yoklama aralığı anında yapılandırılmış olabilen Bekle arayüzünün bir uygulaması. Her FluentWait örneği, bir koşul için beklenecek maksimum süreyi ve ayrıca durumu kontrol etme sıklığını tanımlar. Ayrıca kullanıcı, sayfada bir öğe ararken NoSuchElementExceptions gibi belirli istisna türlerini beklerken göz ardı etmek için beklemeyi yapılandırabilir. Buradan alabileceğiniz detaylar

Kullanımı fluentWaitsizin durumunuzda aşağıdaki gibi:

WebElement textbox = fluentWait(By.id("textbox"));

Bu yaklaşım IMHO'dan daha iyi, çünkü ne kadar bekleyeceğinizi tam olarak bilmiyorsunuz ve sorgulama aralığında, hangi element varlığının doğrulanacağını keyfi zaman değerini ayarlayabilirsiniz. Saygılarımızla.


3
Bu import com.google.common.base.Function;, değilimport java.util.function.Function;
2016

haventchecked, aslında geliştirme için intelij IDEA kullanıyor, otomatik içe aktarmalara yardımcı oluyor (maven tabanlı projede çalışırken)
eugene.polschikov

1
Sadece hangisinin Functionkullanıldığını merak eden diğerlerine sesleniyordum . İlk başta bana açık değildi. Cevap için teşekkürler.
2016

1
Ya da sadece bir lambda ifade kullanabilirsiniz: driver -> driver.findElement(locator). Bunu kullanırken bir ithalat ifadesine hiç ihtiyacınız olmayacak.
Thibstars

2
Şimdi sıra: .withTimeout(Duration.ofSeconds(30)).pollingEvery(Duration.ofSeconds(5))yerine: .withTimeout(30, TimeUnit.SECONDS).pollingEvery(5, TimeUnit.SECONDS)
SuperRetro

16

Bu ileti dizisi biraz daha eski, ancak şu anda yaptığım şeyi göndereceğimi düşündüm (devam eden çalışma).

Hala sistemin ağır yük altında olduğu ve bir gönder düğmesine tıkladığımda true(örneğin, login.jsp) durumlara çarpıyor olsam da, üç koşulun tümü (aşağıya bakın) geri dönüyor ancak sonraki sayfa (örneğin, home.jsp) hasn ' henüz yüklenmeye başlamadı.

Bu, ExpectedConditions listesini alan genel bir bekleme yöntemidir.

public boolean waitForPageLoad(int waitTimeInSec, ExpectedCondition<Boolean>... conditions) {
    boolean isLoaded = false;
    Wait<WebDriver> wait = new FluentWait<>(driver)
            .withTimeout(waitTimeInSec, TimeUnit.SECONDS)
            .ignoring(StaleElementReferenceException.class)
            .pollingEvery(2, TimeUnit.SECONDS);
    for (ExpectedCondition<Boolean> condition : conditions) {
        isLoaded = wait.until(condition);
        if (isLoaded == false) {
            //Stop checking on first condition returning false.
            break;
        }
    }
    return isLoaded;
}

Çeşitli yeniden kullanılabilir Beklenen Koşullar tanımladım (üçü aşağıdadır). Bu örnekte, beklenen üç koşul arasında document.readyState = 'complete', "wait_dialog" mevcut değil ve "döndürücü" (eşzamansız verilerin talep edildiğini gösteren öğeler) yer almıyor.

Tüm web sayfalarına genel olarak yalnızca birincisi uygulanabilir.

/**
 * Returns 'true' if the value of the 'window.document.readyState' via
 * JavaScript is 'complete'
 */
public static final ExpectedCondition<Boolean> EXPECT_DOC_READY_STATE = new ExpectedCondition<Boolean>() {
    @Override
    public Boolean apply(WebDriver driver) {
        String script = "if (typeof window != 'undefined' && window.document) { return window.document.readyState; } else { return 'notready'; }";
        Boolean result;
        try {
            result = ((JavascriptExecutor) driver).executeScript(script).equals("complete");
        } catch (Exception ex) {
            result = Boolean.FALSE;
        }
        return result;
    }
};
/**
 * Returns 'true' if there is no 'wait_dialog' element present on the page.
 */
public static final ExpectedCondition<Boolean> EXPECT_NOT_WAITING = new ExpectedCondition<Boolean>() {
    @Override
    public Boolean apply(WebDriver driver) {
        Boolean loaded = true;
        try {
            WebElement wait = driver.findElement(By.id("F"));
            if (wait.isDisplayed()) {
                loaded = false;
            }
        } catch (StaleElementReferenceException serex) {
            loaded = false;
        } catch (NoSuchElementException nseex) {
            loaded = true;
        } catch (Exception ex) {
            loaded = false;
            System.out.println("EXPECTED_NOT_WAITING: UNEXPECTED EXCEPTION: " + ex.getMessage());
        }
        return loaded;
    }
};
/**
 * Returns true if there are no elements with the 'spinner' class name.
 */
public static final ExpectedCondition<Boolean> EXPECT_NO_SPINNERS = new ExpectedCondition<Boolean>() {
    @Override
    public Boolean apply(WebDriver driver) {
        Boolean loaded = true;
        try {
        List<WebElement> spinners = driver.findElements(By.className("spinner"));
        for (WebElement spinner : spinners) {
            if (spinner.isDisplayed()) {
                loaded = false;
                break;
            }
        }
        }catch (Exception ex) {
            loaded = false;
        }
        return loaded;
    }
};

Sayfaya bağlı olarak, birini veya tümünü kullanabilirim:

waitForPageLoad(timeoutInSec,
            EXPECT_DOC_READY_STATE,
            EXPECT_NOT_WAITING,
            EXPECT_NO_SPINNERS
    );

Aşağıdaki sınıfta önceden tanımlanmış ExpectedConditions da vardır: org.openqa.selenium.support.ui.ExpectedConditions


1
Mükemmel cevap! Birinin ExpectedCondition öğesini yöntem yapıcısı aracılığıyla geçirdiğini hiç görmedim. Ne kadar güzel bir fikir. +1
djangofan

Jeff Vincent, lütfen bana sayfanın 5 dakika beklemesini söyler misin, evet ise, sonra lütfen hangi yer parametresinin gönderilmesi gerektiğini önerebilir misin?
khanam

Bu harika bir cevap. Buna benzer bir işleve sahibim, ancak onu her işlevde çağırmalıyım, böylece betiğim sayfa yüklenene kadar bekler (döndürücü). Bu waitForSpinner işlevini sessizce ImplicitWait'e bağlamanın bir yolu var mı, böylece işlevimde her seferinde çağırmam gerekmiyor mu? İşlevi tanımlamak gibi, sürücüye bir kez bağlayın ve bum.
Bhuvanesh Mani

13

WebdriverJs (node.js) kullanıyorsanız,

driver.findElement(webdriver.By.name('btnCalculate')).click().then(function() {
    driver.sleep(5000);
});

Yukarıdaki kod, tarayıcının düğmeye tıkladıktan sonra 5 saniye beklemesini sağlar.


18
Soru node / JavaScript değil, özellikle Java ile ilgiliyken neden bunu gönderiyorsunuz? Ruby'de nasıl yapılacağını cevaplamak kadar konu dışı.
Thor84no

1
uykuyu kullanma tavsiyesi kesinlikle iyi bir çözüm değil
Kiril S.

@ Thor84no Temel olarak bazılarımız web çözümünü ararken bu cevabı
bulduk

10

Kullanmak Thread.sleep(2000);koşulsuz bir beklemedir. Testiniz daha hızlı yüklenirse, yine de beklemeniz gerekecektir. Yani prensipte kullanmak implicitlyWaitdaha iyi bir çözümdür.

Ancak, implicitlyWaitsizin durumunuzda neden işe yaramadığını anlamıyorum . findElementBir istisna atmadan önce aslında iki saniye sürüp sürmediğini ölçtünüz mü? Öyleyse, WebDriver'ın bu yanıtta açıklandığı gibi koşullu beklemesini kullanmayı deneyebilir misiniz ?


3

Özel koşulları kullanmayı seviyorum. Python'da bazı kodlar:

def conditions(driver):
    flag = True
    ticker = driver.find_elements_by_id("textbox")
    if not ticker:
        flag = False
    return flag

... click something to load ...
self.wait = WebDriverWait(driver, timeout)
self.wait.until(conditions)

Ne zaman beklemeniz gerekiyorsa, belirli bir öğenin varlığını kontrol ederek bunu açıkça yapabilirsiniz (bu öğe sayfadan sayfaya değişebilir). find_elements_by_iddöner liste - boş olsun ya da olmasın, sadece kontrol etmeniz gerekiyor.


2

tıklama engelliyor mu? - WebDriverJS kullanıyorsanız beklemenin başka bir yolu:

driver.findElement(webdriver.By.name('mybutton')).click().then(function(){
  driver.getPageSource().then(function(source) {
    console.log(source);
  });
});

Yukarıdaki kod, buton tıklandıktan sonra bir sonraki sayfanın yüklenmesi için bekler ve ardından sonraki sayfanın kaynağını alır.


1
Kodun sonraki sayfanın yüklenmesini beklemesine neden olan nedir? Geri aramadaki ilk çağrı getPageSource mudur?
Isochronous

1

Örtük olarak wait ve Thread.sleep Her ikisi de yalnızca senkronizasyon için kullanılır ... ancak aradaki fark, tüm programı örtük olarak bekleyebiliriz, ancak Thread.sleep yalnızca bu tek kod için çalışır ... Burada önerim, programda bir kez örtük olarak bekle kullanılmasıdır. Web sayfanız her yenilendiğinde, o anda Thread.sleep kullanılması anlamına gelir ... Çok daha iyi olacak :)

İşte Kodum:

package beckyOwnProjects;

import java.util.concurrent.TimeUnit;

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.interactions.Actions;

public class Flip {

    public static void main(String[] args) throws InterruptedException {
        WebDriver driver=new FirefoxDriver();
        driver.manage().window().maximize();
        driver.manage().timeouts().implicitlyWait(2, TimeUnit.MINUTES);
        driver.get("https://www.flipkart.com");
    WebElement ele=driver.findElement(By.cssSelector(".menu-text.fk-inline-block"));
    Actions act=new Actions(driver);
    Thread.sleep(5000);
    act.moveToElement(ele).perform();
    }

}

0

Bazen örtük bekleme geçersiz kılınır ve bekleme süresi kısalır. [@ eugene.polschikov] nedenlerle ilgili iyi belgelere sahipti. Selenium 2 ile yaptığım test ve kodlamalarımda örtük beklemelerin iyi olduğunu ancak bazen açıkça beklemeniz gerektiğini öğrendim.

Doğrudan uyku ipliği istemekten kaçınmak daha iyidir, ancak bazen bunun iyi bir yolu yoktur. Ancak, yardımcı olan başka Selenium bekleme seçenekleri de vardır. waitForPageToLoad ve waitForFrameToLoad'un özellikle yararlı olduğu kanıtlanmıştır.


0

Örtülü Bekleme: Örtük bekleme sırasında, Web Sürücüsü kullanılabilirliği nedeniyle hemen bulamazsa, WebDriver belirtilen süreyi bekleyecek ve belirtilen süre boyunca öğeyi tekrar bulmaya çalışmayacaktır. Belirtilen süre sona erdiğinde, istisna atmadan önce son kez öğeyi bir kez daha aramaya çalışacaktır. Varsayılan ayar sıfırdır. Bir zaman belirlediğimizde, Web Sürücüsü WebDriver nesne örneğinin süresini bekler.

Açık Bekleme: Belirli bir öğenin yüklenmesinin bir dakikadan uzun sürdüğü durumlar olabilir. Bu durumda, Örtük bekleme için çok uzun bir süre belirlemekten kesinlikle hoşlanmayacaksınız, sanki bunu yaparsanız tarayıcınız her öğe için aynı süreyi bekleyecektir. Bu durumdan kaçınmak için yalnızca gerekli öğeye ayrı bir zaman koyabilirsiniz. Bunu izleyerek tarayıcınızın örtük bekleme süresi her öğe için kısa olacak ve belirli öğe için büyük olacaktır.


0

Bazen örtük bekleme başarısız olur, bir öğenin var olduğunu ancak gerçekten olmadığını söyler.

Çözüm, driver.findElement'i kullanmaktan kaçınmak ve bunu örtük olarak Explicit Wait kullanan özel bir yöntemle değiştirmektir. Örneğin:

import org.openqa.selenium.NoSuchElementException;


public WebElement element(By locator){
    Integer timeoutLimitSeconds = 20;
    WebDriverWait wait = new WebDriverWait(driver, timeoutLimitSeconds);
    try {
        wait.until(ExpectedConditions.presenceOfElementLocated(locator));
    }
    catch(TimeoutException e){
        throw new NoSuchElementException(locator.toString());
    }
    WebElement element = driver.findElement(locator);
    return element;
}

Ara sıra meydana gelen arızalar dışında örtük beklemeyi önlemek için ek nedenler vardır (bu bağlantıya bakın ).

Bu "element" yöntemini, driver.findElement ile aynı şekilde kullanabilirsiniz. Örneğin:

    driver.get("http://yoursite.html");
    element(By.cssSelector("h1.logo")).click();

Sorun giderme veya başka nadir durumlar için gerçekten sadece birkaç saniye beklemek istiyorsanız, selenyum IDE'nin sunduğuna benzer bir duraklama yöntemi oluşturabilirsiniz:

    public void pause(Integer milliseconds){
    try {
        TimeUnit.MILLISECONDS.sleep(milliseconds);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

0

Cevap : Selenium WebDriver kullanarak eleman görünürlüğünün aşağıdaki yöntemlerden geçmesi için birkaç saniye bekleyin.

implicitlyWait () : WebDriver örneği tam sayfa yüklenene kadar bekler. Tam sayfanın yüklenmesini beklemek için 30 ila 60 saniye kullanın.

driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);

ExplicitlyWait WebDriverWait () : WebDriver örneği tam sayfa yüklenene kadar bekleyin.

WebDriverWait wait = new WebDriverWait(driver, 60);

wait.until(ExpectedConditions.visibilityOf(textbox));

driver.findElement(By.id("Year")).sendKeys(allKeys);

Not : Herhangi bir WebElement'i işlemek için lütfen ExplicitlyWait WebDriverWait () kullanın.



-1

Aşağıdaki kodun 2 saniye beklemesini tercih ederim.

for(int i=0; i<2 && driver.findElements(By.id("textbox")).size()==0 ; i++){
   Thread.sleep(1000);
}

-1
Thread.sleep(1000);

daha da kötüsü: statik bir bekleme olması, test komut dosyasını yavaşlatır.

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

bu dinamik bir beklemedir

  • web sürücüsü varlığına kadar geçerlidir veya sürücü ömrüne kadar bir kapsamı vardır
  • örtük olarak da bekleyebiliriz.

Son olarak önerdiğim şey

WebDriverWait wait = new WebDriverWait(driver,20);
wait.until(ExpectedConditions.<different canned or predefined conditions are there>);

önceden tanımlanmış bazı koşullarla:

isAlertPresent();
elementToBeSelected();
visibilityOfElementLocated();
visibilityOfAllElementLocatedBy();
frameToBeAvailableAndSwitchToIt();
  • Aynı zamanda dinamik beklemedir
  • bunda bekleme sadece saniyeler içinde olacak
  • kullanmak istediğimiz belirli bir web öğesi için açık bekleme kullanmalıyız.

-4
Thread.Sleep(5000);

Bu bana yardımcı oldu ama InterruptedException istisnasının halledilmesi gerekiyor. Bu yüzden onu dene ve yakala ile daha iyi çevreleyin:

try {
    Thread.Sleep(5000);
} catch (InterruptedException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
}

VEYA

Atar beyanı ekleyin:

public class myClass {
    public static void main(String[] args) throws InterruptedException
    { ... }

İkincisini tercih ederim, çünkü sleep()o zaman istediği kadar kullanabilir tryve catchher nerede sleep()kullanılırsa kullanılsın , tekrarlanmasını ve bloke edilmesini önleyebilir .

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.