Selenium-WebDriver에 Java에서 몇 초 동안 기다리도록 어떻게 요청할 수 있습니까?


100

Java Selenium-WebDriver에서 일하고 있습니다. 나는 추가했다

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

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

내 응용 프로그램이 사용자 인터페이스를로드하는 데 몇 초가 걸리기 때문입니다. 그래서 2 초를 implicitwait로 설정했습니다. 하지만 요소 텍스트 상자를 찾을 수 없습니다.

그런 다음 추가 Thread.sleep(2000);

이제 잘 작동합니다. 어느 것이 더 좋은 방법입니까?


답변:


123

음, 대기에는 명시 적 대기와 암시 적 대기라는 두 가지 유형이 있습니다. 명시 적 대기의 개념은

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

암시 적 대기의 개념은

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

자세한 내용은 여기 에서 확인할 수 있습니다 .

이러한 상황에서는 명시 적 대기 ( fluentWait특히)를 사용하는 것을 선호합니다 .

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;
};

fluentWait함수는 찾은 웹 요소를 반환합니다. 에 대한 설명서에서 fluentWait: 시간 초과 및 폴링 간격을 즉시 구성 할 수있는 Wait 인터페이스의 구현입니다. 각 FluentWait 인스턴스는 조건을 확인하는 빈도뿐 아니라 조건을 기다리는 최대 시간을 정의합니다. 또한 사용자는 페이지의 요소를 검색 할 때 NoSuchElementExceptions와 같이 대기하는 동안 특정 유형의 예외를 무시하도록 대기를 구성 할 수 있습니다.여기에서 얻을 수있는 세부 정보

fluentWait귀하의 경우 사용은 다음과 같습니다.

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

이 접근법은 얼마나 많은 시간을 기다려야하는지 정확히 알지 못하기 때문에 IMHO가 더 좋습니다. 폴링 간격에서 요소 존재를 확인할 임의의 시간 값을 설정할 수 있습니다. 문안 인사.


3
그건 import com.google.common.base.Function;, 아닙니다import java.util.function.Function;
haventchecked

실제로 (Maven을 기반 프로젝트에서 작업 할 때)는 자동 수입으로 돕고, 개발을위한 intelij의 IDEA를 사용하여, haventchecked
eugene.polschikov

1
나는 어떤 Function것이 사용되고 있는지 궁금해하는 다른 사람들을 위해 그것을 부르고 있었습니다. 처음에는 분명하지 않았습니다. 답변 해주셔서 감사합니다.
haventchecked

1
또는 람다 식을 사용할 수 있습니다 driver -> driver.findElement(locator).. 이것을 사용하면 import 문이 전혀 필요하지 않습니다.
Thibstars 2010 년

2
이제는 다음 .withTimeout(Duration.ofSeconds(30)).pollingEvery(Duration.ofSeconds(5))과 같습니다. .withTimeout(30, TimeUnit.SECONDS).pollingEvery(5, TimeUnit.SECONDS)
SuperRetro

16

이 스레드는 조금 오래되었지만 현재 수행중인 작업 (진행중인 작업)을 게시 할 것이라고 생각했습니다.

여전히 시스템 부하가 true높고 제출 버튼 (예 : login.jsp)을 클릭하면 세 가지 조건 (아래 참조)이 모두 반환 되지만 다음 페이지 (예 : home.jsp)는 반환 되지 않습니다. t는 아직로드를 시작했습니다.

ExpectedConditions 목록을 사용하는 일반 대기 메서드입니다.

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;
}

재사용 가능한 다양한 ExpectedConditions를 정의했습니다 (아래에 3 개). 이 예에서 예상되는 세 가지 조건에는 document.readyState = 'complete', "wait_dialog"없음 및 'spinners'없음 (비동기 데이터가 요청됨을 나타내는 요소)가 포함됩니다.

일반적으로 모든 웹 페이지에 첫 번째 항목 만 적용 할 수 있습니다.

/**
 * 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;
    }
};

페이지에 따라 하나 또는 모두를 사용할 수 있습니다.

waitForPageLoad(timeoutInSec,
            EXPECT_DOC_READY_STATE,
            EXPECT_NOT_WAITING,
            EXPECT_NO_SPINNERS
    );

다음 클래스에도 사전 정의 된 ExpectedConditions가 있습니다. org.openqa.selenium.support.ui.ExpectedConditions


1
좋은 대답입니다! 누군가 메서드 생성자를 통해 ExpectedCondition 항목을 전달하는 것을 본 적이 없습니다. 정말 좋은 생각입니다. +1
djangofan 2016-04-28

Jeff Vincent, 페이지가 5 분 동안 기다려야한다고 알려 주시면 어떤 장소 매개 변수를 보내야하는지 알려주세요.
khanam

이것은 훌륭한 대답입니다. 이와 비슷한 기능이 있지만 스크립트가 페이지로드 (스피너)까지 대기하도록 모든 함수에서 호출해야합니다. 이 waitForSpinner 함수를 ImplicitWait에 자동으로 연결하여 함수에서 매번 호출 할 필요가 없도록하는 방법이 있습니까? 기능을 정의하는 것처럼 운전자에게 한 번 연결하고 붐을 일으 킵니다.
Bhuvanesh Mani

13

webdriverJs (node.js)를 사용하는 경우

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

위의 코드는 브라우저가 버튼을 클릭 한 후 5 초 동안 기다리게합니다.


18
질문이 노드 / 자바 스크립트가 아니라 자바에 관한 것인데 왜이 글을 올릴까요? 루비로하는 방법에 대한 대답만큼 주제가 아닙니다.
Thor84no

1
사용 잠 추천은 확실히 좋은 해결책이 아니다
키릴 S.

@ Thor84no 주로 우리 중 일부가 웹 솔루션을 검색하기 때문에이 답변을 찾을 수 있습니다
Kitanga Nday

10

사용 Thread.sleep(2000);은 무조건 기다립니다. 테스트가 더 빨리로드 되더라도 기다려야합니다. 따라서 원칙적으로 사용 implicitlyWait하는 것이 더 나은 솔루션입니다.

그러나 implicitlyWait귀하의 경우에는 왜 작동하지 않는지 알 수 없습니다. findElement예외가 발생하기 전에 실제로 2 초가 걸리는지 측정 했습니까? 그렇다면 답변에 설명 된대로 WebDriver의 조건부 대기를 사용해 볼 수 있습니까?


3

사용자 지정 조건을 사용하고 싶습니다. 다음은 Python의 일부 코드입니다.

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)

기다려야 할 때마다 특정 요소의 존재 여부를 확인하여 명시 적으로 수행 할 수 있습니다 (이러한 요소는 페이지마다 다를 수 있음). find_elements_by_id목록을 반환합니다-비어 있는지 여부를 확인하기 만하면됩니다.


2

클릭이 차단되는 것처럼 보입니까? -WebDriverJS를 사용하는 경우 기다리는 또 다른 방법이 있습니다.

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

위의 코드는 버튼을 클릭 한 후 다음 페이지가로드 될 때까지 기다린 후 다음 페이지의 소스를 가져옵니다.


1
다음 페이지가로드 될 때까지 코드가 대기하는 이유는 무엇입니까? 콜백의 첫 번째 호출이 getPageSource입니까?
등시성

1

암시 적으로 대기 및 Thread.sleep 둘 다 동기화에만 사용됩니다. 그러나 차이점은 암시 적으로 전체 프로그램을 기다릴 수 있지만 Thread.sleep은 해당 단일 코드에서만 작동합니다. 여기에서 내 제안은 프로그램에서 암시 적으로 한 번 대기하는 것입니다. 웹 페이지가 새로 고쳐질 때마다 그 시간에 Thread.sleep을 사용하십시오. 훨씬 나아질 것입니다. :)

내 코드는 다음과 같습니다.

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

때때로 암시 적 대기가 무시되는 것처럼 보이고 대기 시간이 단축됩니다. [@ eugene.polschikov]는 그 이유에 대한 좋은 문서를 가지고있었습니다. Selenium 2를 사용한 테스트 및 코딩에서 암시 적 대기가 좋지만 때때로 명시 적으로 기다려야한다는 것을 발견했습니다.

스레드를 절전 모드로 직접 호출하는 것을 피하는 것이 좋지만 때로는 좋은 방법이 없습니다. 그러나 도움이되는 다른 Selenium 제공 대기 옵션이 있습니다. waitForPageToLoadwaitForFrameToLoad 는 특히 유용한 것으로 입증되었습니다.


0

암시 적 대기 : 웹 드라이버가 가용성으로 인해 즉시 찾을 수없는 경우 암시 적 대기 동안 WebDriver는 언급 된 시간 동안 대기하고 지정된 기간 동안 요소를 다시 찾으려고 시도하지 않습니다. 지정된 시간이 지나면 예외가 발생하기 전에 마지막으로 요소 검색을 다시 시도합니다. 기본 설정은 0입니다. 시간을 설정하면 웹 드라이버는 WebDriver 개체 인스턴스의 기간을 기다립니다.

명시 적 대기 : 특정 요소를로드하는 데 1 분 이상 걸리는 경우가있을 수 있습니다. 이 경우에는 브라우저가 모든 요소에 대해 동일한 시간을 기다릴 것이기 때문에 암시 적 대기에 엄청난 시간을 설정하고 싶지는 않습니다. 이러한 상황을 피하기 위해 필요한 요소에만 별도의 시간을 지정할 수 있습니다. 이를 따르면 브라우저의 암시 적 대기 시간은 모든 요소에 대해 짧고 특정 요소에 대해서는 커집니다.


0

때때로 암시 적 대기가 실패하여 요소가 존재하지만 실제로는 존재하지 않는다고 말합니다.

해결책은 driver.findElement를 사용하지 않고 명시 적 대기를 암시 적으로 사용하는 사용자 지정 메서드로 바꾸는 것입니다. 예를 들면 :

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;
}

산발적이고 간헐적 인 실패 외에 암시 적 대기를 피해야하는 추가 이유가 있습니다 (이 링크 참조 ).

이 "element"메소드를 driver.findElement와 동일한 방식으로 사용할 수 있습니다. 예를 들면 :

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

문제 해결 또는 기타 드문 경우를 위해 몇 초만 기다리려면 셀레늄 IDE가 제공하는 것과 유사한 일시 중지 방법을 만들 수 있습니다.

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

0

답변 : Selenium WebDriver를 사용하는 요소 가시성이 아래 방법을 거치기 전에 몇 초 동안 기다리십시오.

implicitlyWait () : WebDriver 인스턴스는 전체 페이지가로드 될 때까지 대기합니다. 전체 페이지로드를 기다리는 데 30 ~ 60 초를 사용합니다.

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

ExplicitlyWait WebDriverWait () : WebDriver 인스턴스는 전체 페이지가로드 될 때까지 대기합니다.

WebDriverWait wait = new WebDriverWait(driver, 60);

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

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

참고 : 특정 WebElement를 처리하려면 ExplicitlyWait WebDriverWait ()를 사용하십시오.



-1

2 초 동안 기다리려면 다음 코드를 선호합니다.

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

-1
Thread.sleep(1000);

더 나쁘다 : 정적 대기는 테스트 스크립트를 느리게 만듭니다.

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

이것은 역동적 인 기다림입니다

  • 웹 드라이버가 존재할 때까지 유효하거나 드라이버 수명까지 범위가 있습니다.
  • 암시 적 기다릴 수도 있습니다.

마지막으로 제가 제안하는 것은

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

일부 사전 정의 된 조건 :

isAlertPresent();
elementToBeSelected();
visibilityOfElementLocated();
visibilityOfAllElementLocatedBy();
frameToBeAvailableAndSwitchToIt();
  • 다이나믹 한 기다림
  • 이것에서 기다림은 단지 초입니다
  • 사용하려는 특정 웹 요소에 대해 명시 적 대기를 사용해야합니다.

-4
Thread.Sleep(5000);

이것은 나를 도왔지만 InterruptedException 예외를 처리해야합니다. 따라서 try and catch로 더 잘 둘러싸십시오.

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

또는

throws 선언 추가 :

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

나는 두 번째 것을 선호합니다. 원하는 sleep()만큼 여러 번 사용할 수 있고 사용 된 곳마다 반복 trycatch차단을 피할 수 있기 때문 sleep()입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.