셀레늄 C # 웹 드라이버 : 요소가 나타날 때까지 기다립니다


185

웹 드라이버가 작업을 시작하기 전에 요소가 있는지 확인하고 싶습니다.

다음과 같이 작동하려고합니다.

WebDriverWait wait = new WebDriverWait(driver, new TimeSpan(0,0,5));
wait.Until(By.Id("login"));

나는 주로 임의의 기능을 설정하는 방법을 고심하고 있습니다.


3
참고로-이와 같이 시간 범위를 구축하는 것이 더 깨끗합니다 TimeSpan.FromSeconds(5). 보다 분명한 IMO
Kolob Canyon

답변:


159

또는 암시 적 대기를 사용할 수 있습니다.

driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(10);

암시 적 대기는 요소를 즉시 사용할 수없는 경우 요소를 찾으려고 할 때 WebDriver에 일정 시간 동안 DOM을 폴링하도록 지시하는 것입니다. 기본 설정은 0입니다. 일단 설정된 후 내재 된 대기는 WebDriver 오브젝트 인스턴스의 수명 동안 설정됩니다.


5
감사합니다. 새 구문은 다음과 같습니다. driver.manage (). timeouts (). implicitlyWait (10, TimeUnit.SECONDS);
Reda

20
@ RedaBalkouch, Mike가 그의 답변에 사용한 구문이 정확합니다. C #
Diemo

3
암시 적 대기를 사용하도록 선택한 경우 명시 적 대기를 사용하지 않도록주의하십시오. 이로 인해 예기치 않은 동작이 발생하여 테스트 결과가 나빠질 수 있습니다. 일반적으로 암시 적 대기에 대해 명시 적 대기를 사용하는 것이 좋습니다.
mrfreester

7
이 방법은 더 이상 사용되지 않으며 대신 ImplicitWait 속성을 사용해야합니다.Driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(10);
Samuel Rondeau-Millaire

1
나는 제공된 접근 방식을 사용했으며 사무엘이 지적한대로 그 방법이 더 이상 사용되지 않는다는 것을 알았습니다. 아이템의 존재를 확인하면 지정된 시간까지 기다립니다.
Jim Scott

279

암시 적 대기는 모든 FindElement 호출에 사용되므로 Mike Kwan이 제공 한 솔루션을 사용하면 전체 테스트 성능에 영향을 줄 수 있습니다. 요소가 존재하지 않을 때 (잘못된 페이지, 누락 된 요소 등을 테스트하는 경우) FindElement가 즉시 실패하기를 원하는 경우가 많습니다. 암시 적 대기를 사용하면 이러한 작업은 예외가 발생하기 전에 전체 시간 초과가 만료 될 때까지 기다립니다. 기본 암시 적 대기는 0 초로 설정됩니다.

메소드에 시간 초과 (초) 매개 변수를 추가하는 IWebDriver에 약간의 확장 메소드를 작성했습니다 FindElement(). 매우 설명이 필요합니다.

public static class WebDriverExtensions
{
    public static IWebElement FindElement(this IWebDriver driver, By by, int timeoutInSeconds)
    {
        if (timeoutInSeconds > 0)
        {
            var wait = new WebDriverWait(driver, TimeSpan.FromSeconds(timeoutInSeconds));
            return wait.Until(drv => drv.FindElement(by));
        }
        return driver.FindElement(by);
    }
}

WebDriverWait 객체는 생성 비용이 매우 저렴하므로 캐시하지 않았으며이 확장은 다른 WebDriver 객체에 동시에 사용될 수 있으며 궁극적으로 필요할 때만 최적화를 수행합니다.

사용법은 간단합니다.

var driver = new FirefoxDriver();
driver.Navigate().GoToUrl("http://localhost/mypage");
var btn = driver.FindElement(By.CssSelector("#login_button"));
btn.Click();
var employeeLabel = driver.FindElement(By.CssSelector("#VCC_VSL"), 10);
Assert.AreEqual("Employee", employeeLabel.Text);
driver.Close();

114
궁금한 WebDriverWait점이 있다면 OpenQA.Selenium.Support.UI네임 스페이스에서 왔으며 Selenium WebDriver Support ClassesNuGet 이라는 별도의 패키지로 제공됩니다.
Andy

5
@Ved 나는 당신에게 키스 할 수 있습니다 <3 다른 dll에서 그것을 찾고있었습니다 : D
Adween

1
@Loudenvier 첫 줄을 굵게 표시하여 눈에 잘 띄도록하십시오. 특히 더 나은 접근 방식이지만 대답이 받아 들여지지 않기 때문입니다.
Rick

5
Selenium WebDriver Support Classes은 NuGet에 "Selenium.Support" 로 나타나며 현재 버전은 3.4.0입니다.
Eric F.

1
이 줄을 사용할 때까지 여전히 많은 오류가 있었고 return wait.Until(ExpectedConditions.ElementToBeClickable(by));지금은 잘 작동합니다. 다른 사람이 여전히 발견되지 않은 임의의 요소를 얻는 경우를 대비하여 진행합니다.
광부

84

당신은 또한 사용할 수 있습니다

예상되는 조건. 요소

그래서 당신은 그런 요소 가용성을 검색 할 것입니다

new WebDriverWait(driver, TimeSpan.FromSeconds(timeOut)).Until(ExpectedConditions.ElementExists((By.Id(login))));

출처


1
동의, 이것은 단순히 시간 초과 (객체를 동적으로로드하는 경우)보다 훨씬 유용합니다.
keithl8041

5
이것이 작동하는 동안. 이제 더 이상 사용되지 않는 것으로 표시되므로 피해야합니다.
Adam Garner

3
다음은 새로운 접근 방식입니다 (더 이상 사용되지 않음). stackoverflow.com/a/49867605/331281
Dejan

1
현재 DotNetSeleniumExtras.WaitHelpers(위의 @Dejan에 의해 언급 됨) "유지되지 않으며, 문제가 해결되지 않으며, PR은 수락되지 않습니다." (출처 : github.com/SeleniumHQ/selenium/issues/… ). 그 출판사는 그에게서 그것을 인수하기 위해 관리자를 찾고 있습니다.
urig

30

다음은 여러 요소를 가져 오는 데 사용되는 @Loudenvier 솔루션의 변형입니다.

public static class WebDriverExtensions
{
    public static IWebElement FindElement(this IWebDriver driver, By by, int timeoutInSeconds)
    {
        if (timeoutInSeconds > 0)
        {
            var wait = new WebDriverWait(driver, TimeSpan.FromSeconds(timeoutInSeconds));
            return wait.Until(drv => drv.FindElement(by));
        }
        return driver.FindElement(by);
    }

    public static ReadOnlyCollection<IWebElement> FindElements(this IWebDriver driver, By by, int timeoutInSeconds)
    {
        if (timeoutInSeconds > 0)
        {
            var wait = new WebDriverWait(driver, TimeSpan.FromSeconds(timeoutInSeconds));
            return wait.Until(drv => (drv.FindElements(by).Count > 0) ? drv.FindElements(by) : null);
        }
        return driver.FindElements(by);
    }
}

7
좋은! 방금 이것을 내 라이브러리에 추가했습니다! 이것이 코드 공유의 아름다움입니다 !!!
Loudenvier

1
나는 그것에 한 가지 추가를 제안 할 것입니다. NoSuchElement 솔루션을 잡아 해당 인스턴스에서 null을 반환 할 수 있습니다. 그런 다음 IWebElement가 null이 아닌 경우 true를 반환하는 .exists라는 확장 메서드를 만들 수 있습니다.
Brantley Blanchard

17

Loudenvier의 솔루션에서 영감을 얻은 다음은 전자를 전문으로하는 IWebDriver뿐만 아니라 모든 ISearchContext 객체에서 작동하는 확장 메서드입니다. 이 방법은 요소가 표시 될 때까지 대기하는 것도 지원합니다.

static class WebDriverExtensions
{
    /// <summary>
    /// Find an element, waiting until a timeout is reached if necessary.
    /// </summary>
    /// <param name="context">The search context.</param>
    /// <param name="by">Method to find elements.</param>
    /// <param name="timeout">How many seconds to wait.</param>
    /// <param name="displayed">Require the element to be displayed?</param>
    /// <returns>The found element.</returns>
    public static IWebElement FindElement(this ISearchContext context, By by, uint timeout, bool displayed=false)
    {
        var wait = new DefaultWait<ISearchContext>(context);
        wait.Timeout = TimeSpan.FromSeconds(timeout);
        wait.IgnoreExceptionTypes(typeof(NoSuchElementException));
        return wait.Until(ctx => {
            var elem = ctx.FindElement(by);
            if (displayed && !elem.Displayed)
                return null;

            return elem;
        });
    }
}

사용법 예 :

var driver = new FirefoxDriver();
driver.Navigate().GoToUrl("http://localhost");
var main = driver.FindElement(By.Id("main"));
var btn = main.FindElement(By.Id("button"));
btn.Click();
var dialog = main.FindElement(By.Id("dialog"), 5, displayed: true);
Assert.AreEqual("My Dialog", dialog.Text);
driver.Close();

1
이와 같은 암시 적 대기 _webDriver.Manage().Timeouts().ImplicitlyWait(Timeout);를 설정 한 경우 여기에서 설정 한 시간 초과 값보다 우선합니다.
howcheng

이것은 나를 위해 작동하지 않는 것 같습니다 ...? Stopwatch확장 메서드에 대한 호출 주위를 추가하고 에 Console.WriteLine()람다를 보냈습니다 Until(). 스톱워치는 거의 정확히 60 초를 측정했으며 하나의 메시지 만 기록되었습니다 Console. 여기에 뭔가 빠졌습니까?
urig

10

임의의 기능을 술어와 혼동했습니다. 다음은 약간의 도우미 방법입니다.

   WebDriverWait wait;
    private void waitForById(string id) 
    {
        if (wait == null)            
            wait = new WebDriverWait(driver, new TimeSpan(0,0,5));

        //wait.Until(driver);
        wait.Until(d => d.FindElement(By.Id(id)));
    }

5

C #에서 이와 같은 것을 찾을 수 있습니다.

이것이 내가 JUnit에서 사용한 것입니다-Selenium

WebDriverWait wait = new WebDriverWait(driver, 100);
WebElement element = wait.until(ExpectedConditions.elementToBeClickable(By.id("submit")));

관련 패키지 가져 오기


1
오늘 이것을 사용하려고 시도했지만 VS.net에서 경고를 표시합니다. OpenQA.Selenium.Support.UI.ExpectedConditions 클래스가 "더 이상 사용되지 않음"으로 표시되었으며 github.com/DotNetSeleniumTools
Jeff Mergler

3
//wait up to 5 seconds with no minimum for a UI element to be found
WebDriverWait wait = new WebDriverWait(_pagedriver, TimeSpan.FromSeconds(5));
IWebElement title = wait.Until<IWebElement>((d) =>
{
    return d.FindElement(By.ClassName("MainContentHeader"));
});

3
public bool doesWebElementExist(string linkexist)
{
     try
     {
        driver.FindElement(By.XPath(linkexist));
        return true;
     }
     catch (NoSuchElementException e)
     {
        return false;
     }
}

위의 코드는 특정 요소가 있는지 여부를 확인하는 것입니다.
Madhu

2

Selenium IDE에서 웹 드라이버 형식을 선택하면 clickAndWait 명령이 변환되지 않습니다. 해결 방법은 다음과 같습니다. 아래에 대기 줄을 추가하십시오. 사실, 문제는 C # 코드에서 1 행 전에 발생한 클릭 또는 이벤트였습니다. 그러나 실제로는 "By"객체를 참조하는 작업 전에 WaitForElement가 있는지 확인하십시오.

HTML 코드 :

<a href="http://www.google.com">xxxxx</a>

C # / N 단위 코드 :

driver.FindElement(By.LinkText("z")).Click;
driver.WaitForElement(By.LinkText("xxxxx"));
driver.FindElement(By.LinkText("xxxxx")).Click();

2

파이썬 :

from selenium import webdriver
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By

driver.find_element_by_id('someId').click()

WebDriverWait(driver, timeout).until(EC.presence_of_element_located((By.ID, 'someAnotherId'))

EC에서 다른 조건을 선택할 수도 있습니다. http://selenium-python.readthedocs.org/api.html#module-selenium.webdriver.support.expected_conditions


이 질문은 Python이 아닌 C #으로 태그됩니다. 이 답변은 관련이 없습니다.
사용자

2

이 코드를 사용해보십시오 :

 New WebDriverWait(driver, TimeSpan.FromSeconds(10)).Until(Function(d) d.FindElement(By.Id("controlName")).Displayed)

4
당신이 한 일과 왜 이것이 문제를 해결하는지 설명해야합니다. 그리고 코드를 포맷하십시오.
hering her

1

명시 적 대기

public static  WebDriverWait wait = new WebDriverWait(driver, 60);

예:

wait.until(ExpectedConditions.visibilityOfElementLocated(UiprofileCre.UiaddChangeUserLink));

1

Rn222 및 Aknuds1을 사용하여 단일 요소 또는 목록을 반환하는 ISearchContext를 사용했습니다. 최소 요소 수를 지정할 수 있습니다.

public static class SearchContextExtensions
{
    /// <summary>
    ///     Method that finds an element based on the search parameters within a specified timeout.
    /// </summary>
    /// <param name="context">The context where this is searched. Required for extension methods</param>
    /// <param name="by">The search parameters that are used to identify the element</param>
    /// <param name="timeOutInSeconds">The time that the tool should wait before throwing an exception</param>
    /// <returns> The first element found that matches the condition specified</returns>
    public static IWebElement FindElement(this ISearchContext context, By by, uint timeOutInSeconds)
    {
        if (timeOutInSeconds > 0)
        {
            var wait = new DefaultWait<ISearchContext>(context);
            wait.Timeout = TimeSpan.FromSeconds(timeOutInSeconds);
            return wait.Until<IWebElement>(ctx => ctx.FindElement(by));
        }
        return context.FindElement(by);
    }
    /// <summary>
    ///     Method that finds a list of elements based on the search parameters within a specified timeout.
    /// </summary>
    /// <param name="context">The context where this is searched. Required for extension methods</param>
    /// <param name="by">The search parameters that are used to identify the element</param>
    /// <param name="timeoutInSeconds">The time that the tool should wait before throwing an exception</param>
    /// <returns>A list of all the web elements that match the condition specified</returns>
    public static IReadOnlyCollection<IWebElement> FindElements(this ISearchContext context, By by, uint timeoutInSeconds)
    {

        if (timeoutInSeconds > 0)
        {
            var wait = new DefaultWait<ISearchContext>(context);
            wait.Timeout = TimeSpan.FromSeconds(timeoutInSeconds);
            return wait.Until<IReadOnlyCollection<IWebElement>>(ctx => ctx.FindElements(by));
        }
        return context.FindElements(by);
    }
    /// <summary>
    ///     Method that finds a list of elements with the minimum amount specified based on the search parameters within a specified timeout.<br/>
    /// </summary>
    /// <param name="context">The context where this is searched. Required for extension methods</param>
    /// <param name="by">The search parameters that are used to identify the element</param>
    /// <param name="timeoutInSeconds">The time that the tool should wait before throwing an exception</param>
    /// <param name="minNumberOfElements">
    ///     The minimum number of elements that should meet the criteria before returning the list <para/>
    ///     If this number is not met, an exception will be thrown and no elements will be returned
    ///     even if some did meet the criteria
    /// </param>
    /// <returns>A list of all the web elements that match the condition specified</returns>
    public static IReadOnlyCollection<IWebElement> FindElements(this ISearchContext context, By by, uint timeoutInSeconds, int minNumberOfElements)
    {
        var wait = new DefaultWait<ISearchContext>(context);
        if (timeoutInSeconds > 0)
        {
            wait.Timeout = TimeSpan.FromSeconds(timeoutInSeconds);
        }

        // Wait until the current context found the minimum number of elements. If not found after timeout, an exception is thrown
        wait.Until<bool>(ctx => ctx.FindElements(by).Count >= minNumberOfElements);

        //If the elements were successfuly found, just return the list
        return context.FindElements(by);
    }

}

사용법 예 :

var driver = new FirefoxDriver();
driver.Navigate().GoToUrl("http://localhost");
var main = driver.FindElement(By.Id("main"));
// It can be now used to wait when using elements to search
var btn = main.FindElement(By.Id("button"),10);
btn.Click();
//This will wait up to 10 seconds until a button is found
var button = driver.FindElement(By.TagName("button"),10)
//This will wait up to 10 seconds until a button is found, and return all the buttons found
var buttonList = driver.FindElements(By.TagName("button"),10)
//This will wait for 10 seconds until we find at least 5 buttons
var buttonsMin= driver.FindElements(By.TagName("button"), 10, 5);
driver.Close();

1

요소가 변경되기 전에 너무 오래 기다리기를 원하지 않습니다. 이 코드에서 웹 드라이버는 최대 2 초 동안 기다렸다가 계속합니다.

WebDriverWait 대기 = 새로운 WebDriverWait (드라이버, TimeSpan.FromMilliseconds (2000));
wait.Until (예상되는 조건. 가시성 모든 요소로 케이드 dBy (By.Name ( "html-name")));


1

가시성을 위해 이미 찾은 IWebElement를 사용하여 페이지 요소 정의와 페이지 테스트 시나리오를 분리하므로 다음과 같이 수행 할 수 있습니다.

public static void WaitForElementToBecomeVisibleWithinTimeout(IWebDriver driver, IWebElement element, int timeout)
{
    new WebDriverWait(driver, TimeSpan.FromSeconds(timeout)).Until(ElementIsVisible(element));
}

private static Func<IWebDriver, bool> ElementIsVisible(IWebElement element)
{
    return driver => {
        try
        {
            return element.Displayed;              
        }
        catch(Exception)
        {
            // If element is null, stale or if it cannot be located
            return false;
        }
    };
}

1

이것은 명시 적 대기를 사용하여 DOM에 존재하는 요소를 기다리는 재사용 가능한 함수입니다.

public void WaitForElement(IWebElement element, int timeout = 2)
{
    WebDriverWait wait = new WebDriverWait(webDriver, TimeSpan.FromMinutes(timeout));
    wait.IgnoreExceptionTypes(typeof(NoSuchElementException));
    wait.IgnoreExceptionTypes(typeof(StaleElementReferenceException));
    wait.Until<bool>(driver =>
    {
        try
        {
            return element.Displayed;
        }
        catch (Exception)
        {
            return false;
        }
    });
}

스택 오버플로에 오신 것을 환영합니다. 코드 전용 답변을 게시하지 마십시오.
투명성 및 JJ JJ

0

우리는 이것을 다음과 같이 달성 할 수 있습니다 :

public static IWebElement WaitForObject(IWebDriver DriverObj, By by, int TimeOut = 30)
{
    try
    {
        WebDriverWait Wait1 = new WebDriverWait(DriverObj, TimeSpan.FromSeconds(TimeOut));
        var WaitS = Wait1.Until(SeleniumExtras.WaitHelpers.ExpectedConditions.PresenceOfAllElementsLocatedBy(by));
        return WaitS[0];
    }
    catch (NoSuchElementException)
    {
        Reports.TestStep("Wait for Element(s) with xPath was failed in current context page.");
        throw;
    }
}

0

WebDriverWait 적용되지 않습니다.

var driver = new FirefoxDriver(
    new FirefoxOptions().PageLoadStrategy = PageLoadStrategy.Eager
);
driver.Navigate().GoToUrl("xxx");
new WebDriverWait(driver, TimeSpan.FromSeconds(60))
    .Until(d => d.FindElement(By.Id("xxx"))); // a tag that close to the end

페이지가 "대화 형"이면 즉시 예외가 발생합니다. 이유를 모르지만 시간 초과는 존재하지 않는 것처럼 작동합니다.

아마도 SeleniumExtras.WaitHelpers효과가 있지만 시도하지 않았습니다. 공식이지만 다른 nuget 패키지로 분리되었습니다. C # Selenium 'ExpectedConditions is obsolete'를 참조 할 수 있습니다 .

내 자신이 사용 FindElements하고 있으며 Count == 0true 인 경우 사용 하는지 확인하십시오 await Task.Delay. 정말 효율적이지 않습니다.


0

다음을 사용할 수 있습니다

WebDriverWait wait = new WebDriverWait(driver, new TimeSpan(0,0,5));
wait.Until(ExpectedConditions.ElementToBeClickable((By.Id("login")));

-1

여러 솔루션이 이미 게시되어 효과적입니다. 그러나 누군가 다른 것이 필요한 경우를 대비하여 셀레늄 C #에서 개인적으로 사용하는 두 가지 솔루션을 게시하여 요소가 있는지 테스트한다고 생각했습니다! 도움이 되길 바랍니다.

public static class IsPresent
{
    public static bool isPresent(this IWebDriver driver, By bylocator)
    {

        bool variable = false;
        try
        {
            IWebElement element = driver.FindElement(bylocator);
            variable = element != null;
        }
       catch (NoSuchElementException){

       }
        return variable; 
    }

}

여기 두 번째입니다

    public static class IsPresent2
{
    public static bool isPresent2(this IWebDriver driver, By bylocator)
    {
        bool variable = true; 
        try
        {
            IWebElement element = driver.FindElement(bylocator);

        }
        catch (NoSuchElementException)
        {
            variable = false; 
        }
        return variable; 
    }

}

-1
 new WebDriverWait(driver, TimeSpan.FromSeconds(10)).
   Until(ExpectedConditions.PresenceOfAllElementsLocatedBy((By.Id("toast-container"))));

예상 조건은 더 이상 사용되지 않습니다
GELR

-1

첫 번째 대답은 훌륭합니다. 제 문제는 처리되지 않은 예외 로 인해 웹 드라이버가 제대로 닫히지 않았 으며 사용했던 첫 번째 값과 동일한 1 초를 유지한다는 것입니다.

같은 문제가 발생하면

restart you visual studio그 보장 all the exceptions are handled이 제대로.


지금까지 스택 오버플로에는 답변 순서가 없으므로 "첫 번째 답변"은 없습니다
Antti Haapala

-2

셀레늄에서 상태를 기다리는 방법을 찾고 있었고이 스레드에 착륙했으며 여기에 내가 사용하는 것이 있습니다.

    WebDriverWait wait = new WebDriverWait(m_driver, TimeSpan.FromSeconds(10));
    wait.Until(d => ReadCell(row, col) != "");

ReadCell(row, col) != ""어떤 조건이 될 수 있습니다. 다음과 같은 이유로 이런 식으로 :

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