如何让 webDriver 等待页面加载(C# Selenium 项目)
How to get webDriver to wait for page to load (C# Selenium project)
我用 C# 启动了一个 Selenium 项目。正在尝试等待页面加载完成,然后才进行下一步操作。
我的代码如下所示:
loginPage.GoToLoginPage();
loginPage.LoginAs(TestCase.Username, TestCase.Password);
loginPage.SelectRole(TestCase.Orgunit);
loginPage.AcceptRole();
里面 loginPage.SelectRole(TestCase.Orgunit):
RoleHierachyLabel = CommonsBasePage.Driver.FindElement(By.XPath("//span[contains(text(), " + role + ")]"));
RoleHierachyLabel.Click();
RoleLoginButton.Click();
我搜索元素 RoleHierachyLabel。我一直在尝试使用多种方式来等待页面加载或搜索元素 属性 允许一些超时:
1. _browserInstance.Manage().Timeouts().ImplicitlyWait(TimeSpan.FromSeconds(5));
2. public static bool WaitUntilElementIsPresent(RemoteWebDriver driver, By by, int timeout = 5)
{
for (var i = 0; i < timeout; i++)
{
if (driver.ElementExists(by)) return true;
}
return false;
}
你会如何克服这个障碍?
我通常对此使用显式等待,等待元素可见,然后进行下一步操作。这应该是这样的:
WebDriverWait waitForElement = new WebDriverWait(driver, TimeSpan.FromSeconds(5));
waitForElement.Until(ExpectedConditions.ElementIsVisible(By.Id("yourIDHere")));
更多关于显式等待的信息:Explicit waits Selenium C# and here WebDriver Explicit waits
driver.Manage().Timeouts().PageLoad = TimeSpan.FromSeconds(5);
另外,参见 this answer
我一直在寻找替代品,我已经选择了以下版本。所有都使用具有定义超时的显式等待,并且在第一种情况下基于元素属性,在第二种情况下基于元素过时。
首选 将检查元素属性,直到达到超时。我已经到达以下属性,确认它在页面上可用:
Existence - 检查元素是否存在于页面的 DOM 上的期望。这并不一定意味着该元素是可见的。
//this will not wait for page to load
Assert.True(Driver.FindElement(By elementLocator).Enabled)
//this will search for the element until a timeout is reached
public static IWebElement WaitUntilElementExists(By elementLocator, int timeout = 10)
{
try
{
var wait = new WebDriverWait(Driver, TimeSpan.FromSeconds(timeout));
return wait.Until(ExpectedConditions.ElementExists(elementLocator));
}
catch (NoSuchElementException)
{
Console.WriteLine("Element with locator: '" + elementLocator + "' was not found in current context page.");
throw;
}
}
Visibility - 期望检查元素是否出现在页面的 DOM 上并且可见。可见性是指该元素不仅显示而且高度和宽度都大于0。
//this will not wait for page to load
Assert.True(Driver.FindElement(By elementLocator).Displayed)
//this will search for the element until a timeout is reached
public static IWebElement WaitUntilElementVisible(By elementLocator, int timeout = 10)
{
try
{
var wait = new WebDriverWait(Driver, TimeSpan.FromSeconds(timeout));
return wait.Until(ExpectedConditions.ElementIsVisible(elementLocator));
}
catch (NoSuchElementException)
{
Console.WriteLine("Element with locator: '" + elementLocator + "' was not found.");
throw;
}
}
可点击 - 检查元素是否可见并启用以便您可以单击它的期望。
//this will not wait for page to load
//both properties need to be true in order for element to be clickable
Assert.True(Driver.FindElement(By elementLocator).Enabled)
Assert.True(Driver.FindElement(By elementLocator).Displayed)
//this will search for the element until a timeout is reached
public static IWebElement WaitUntilElementClickable(By elementLocator, int timeout = 10)
{
try
{
var wait = new WebDriverWait(Driver, TimeSpan.FromSeconds(timeout));
return wait.Until(ExpectedConditions.ElementToBeClickable(elementLocator));
}
catch (NoSuchElementException)
{
Console.WriteLine("Element with locator: '" + elementLocator + "' was not found in current context page.");
throw;
}
}
第二种选择适用于触发器对象(例如菜单项)在单击后不再附加到 DOM 的情况。当元素上的单击操作将触发重定向到另一个页面时,通常就是这种情况。在这种情况下,检查 StalenessOf(element) 很有用,其中元素是被点击以触发重定向到新页面的项目。
public static void ClickAndWaitForPageToLoad(By elementLocator, int timeout = 10)
{
try
{
var wait = new WebDriverWait(Driver, TimeSpan.FromSeconds(timeout));
var element = Driver.FindElement(elementLocator);
element.Click();
wait.Until(ExpectedConditions.StalenessOf(element));
}
catch (NoSuchElementException)
{
Console.WriteLine("Element with locator: '" + elementLocator + "' was not found in current context page.");
throw;
}
}
我这样做是为了解决这类问题。它是定时器和循环的组合,它们正在寻找一个特定的元素,直到它在一定的毫秒数后超时。
private IWebElement FindElementById(string id, int timeout = 1000)
{
IWebElement element = null;
var s = new Stopwatch();
s.Start();
while (s.Elapsed < TimeSpan.FromMilliseconds(timeout))
{
try
{
element = _driver.FindElementById(id);
break;
}
catch (NoSuchElementException)
{
}
}
s.Stop();
return element;
}
我也做了一个元素启用
private IWebElement ElementEnabled(IWebElement element, int timeout = 1000)
{
var s = new Stopwatch();
s.Start();
while (s.Elapsed < TimeSpan.FromMilliseconds(timeout))
{
if (element.Enabled)
{
return element;
}
}
s.Stop();
return null;
}
如Wait for page load in Selenium中所述:
In general, with Selenium 2.0 the web driver should only return
control to the calling code once it has determined that the page has
loaded. If it does not, you can call waitforelemement
, which cycles
round calling findelement
until it is found or times out (time out
can be set).
因为它的简单性,我喜欢这个解决方案。此外,它还具有避免过度等待和从可能的等待上限中进行猜测的好处:
public bool WaitToLoad(By by)
{
int i = 0;
while (i < 600)
{
i++;
Thread.Sleep(100); // sleep 100 ms
try
{
driver.FindElement(by);
break;
}
catch { }
}
if (i == 600) return false; // page load failed in 1 min
else return true;
}
如果需要监控页面加载延迟,可以将其修改为还包括 "timer":
public int WaitToLoad(By by)
{
int i = 0;
while (i < 600)
{
i++;
Thread.Sleep(100); // sleep 100 ms
try
{
driver.FindElement(by);
break;
}
catch { }
}
return i; // page load latency in 1/10 secs
}
刚遇到同样的问题。
使用以下方法,我等待页面完全加载,而不是依赖于 JavaScript、单击或输入元素上的操作导致页面加载。
private void WaitForPageToLoad(Action doing)
{
IWebElement oldPage = _driver.FindElement(By.TagName("html"));
doing();
WebDriverWait wait = new WebDriverWait(_driver, new TimeSpan(0, 0, Timeout));
try
{
wait.Until(driver => ExpectedConditions.StalenessOf(oldPage)(_driver) &&
((IJavaScriptExecutor)driver).ExecuteScript("return document.readyState").Equals("complete"));
}
catch (Exception pageLoadWaitError)
{
throw new TimeoutException("Timeout during page load", pageLoadWaitError);
}
}
如下调用
WaitForPageToLoad(() => _driver.FindElement(By.Id("button1")).Click());
所有没有任何意义的答案。
页面可以包含所有控件。但是你改变了一些东西,控件中的数据发生了变化,页面进入了重新加载状态。所以如果你继续使用这个页面,你会得到一堆错误。
真的,我没有看到比 Thread.Sleep()
更好的解决方案
你只需要通过 NuGet 导入 SeleniumExtras 包,然后像下面这样使用它:
var e = new WebDriverWait(driver, new TimeSpan(0, 0, 60)).Until(SeleniumExtras.WaitHelpers.ExpectedConditions.ElementIsVisible(By.Id("--id")));
我用 C# 启动了一个 Selenium 项目。正在尝试等待页面加载完成,然后才进行下一步操作。
我的代码如下所示:
loginPage.GoToLoginPage();
loginPage.LoginAs(TestCase.Username, TestCase.Password);
loginPage.SelectRole(TestCase.Orgunit);
loginPage.AcceptRole();
里面 loginPage.SelectRole(TestCase.Orgunit):
RoleHierachyLabel = CommonsBasePage.Driver.FindElement(By.XPath("//span[contains(text(), " + role + ")]"));
RoleHierachyLabel.Click();
RoleLoginButton.Click();
我搜索元素 RoleHierachyLabel。我一直在尝试使用多种方式来等待页面加载或搜索元素 属性 允许一些超时:
1. _browserInstance.Manage().Timeouts().ImplicitlyWait(TimeSpan.FromSeconds(5));
2. public static bool WaitUntilElementIsPresent(RemoteWebDriver driver, By by, int timeout = 5)
{
for (var i = 0; i < timeout; i++)
{
if (driver.ElementExists(by)) return true;
}
return false;
}
你会如何克服这个障碍?
我通常对此使用显式等待,等待元素可见,然后进行下一步操作。这应该是这样的:
WebDriverWait waitForElement = new WebDriverWait(driver, TimeSpan.FromSeconds(5));
waitForElement.Until(ExpectedConditions.ElementIsVisible(By.Id("yourIDHere")));
更多关于显式等待的信息:Explicit waits Selenium C# and here WebDriver Explicit waits
driver.Manage().Timeouts().PageLoad = TimeSpan.FromSeconds(5);
另外,参见 this answer
我一直在寻找替代品,我已经选择了以下版本。所有都使用具有定义超时的显式等待,并且在第一种情况下基于元素属性,在第二种情况下基于元素过时。
首选 将检查元素属性,直到达到超时。我已经到达以下属性,确认它在页面上可用:
Existence - 检查元素是否存在于页面的 DOM 上的期望。这并不一定意味着该元素是可见的。
//this will not wait for page to load
Assert.True(Driver.FindElement(By elementLocator).Enabled)
//this will search for the element until a timeout is reached
public static IWebElement WaitUntilElementExists(By elementLocator, int timeout = 10)
{
try
{
var wait = new WebDriverWait(Driver, TimeSpan.FromSeconds(timeout));
return wait.Until(ExpectedConditions.ElementExists(elementLocator));
}
catch (NoSuchElementException)
{
Console.WriteLine("Element with locator: '" + elementLocator + "' was not found in current context page.");
throw;
}
}
Visibility - 期望检查元素是否出现在页面的 DOM 上并且可见。可见性是指该元素不仅显示而且高度和宽度都大于0。
//this will not wait for page to load
Assert.True(Driver.FindElement(By elementLocator).Displayed)
//this will search for the element until a timeout is reached
public static IWebElement WaitUntilElementVisible(By elementLocator, int timeout = 10)
{
try
{
var wait = new WebDriverWait(Driver, TimeSpan.FromSeconds(timeout));
return wait.Until(ExpectedConditions.ElementIsVisible(elementLocator));
}
catch (NoSuchElementException)
{
Console.WriteLine("Element with locator: '" + elementLocator + "' was not found.");
throw;
}
}
可点击 - 检查元素是否可见并启用以便您可以单击它的期望。
//this will not wait for page to load
//both properties need to be true in order for element to be clickable
Assert.True(Driver.FindElement(By elementLocator).Enabled)
Assert.True(Driver.FindElement(By elementLocator).Displayed)
//this will search for the element until a timeout is reached
public static IWebElement WaitUntilElementClickable(By elementLocator, int timeout = 10)
{
try
{
var wait = new WebDriverWait(Driver, TimeSpan.FromSeconds(timeout));
return wait.Until(ExpectedConditions.ElementToBeClickable(elementLocator));
}
catch (NoSuchElementException)
{
Console.WriteLine("Element with locator: '" + elementLocator + "' was not found in current context page.");
throw;
}
}
第二种选择适用于触发器对象(例如菜单项)在单击后不再附加到 DOM 的情况。当元素上的单击操作将触发重定向到另一个页面时,通常就是这种情况。在这种情况下,检查 StalenessOf(element) 很有用,其中元素是被点击以触发重定向到新页面的项目。
public static void ClickAndWaitForPageToLoad(By elementLocator, int timeout = 10)
{
try
{
var wait = new WebDriverWait(Driver, TimeSpan.FromSeconds(timeout));
var element = Driver.FindElement(elementLocator);
element.Click();
wait.Until(ExpectedConditions.StalenessOf(element));
}
catch (NoSuchElementException)
{
Console.WriteLine("Element with locator: '" + elementLocator + "' was not found in current context page.");
throw;
}
}
我这样做是为了解决这类问题。它是定时器和循环的组合,它们正在寻找一个特定的元素,直到它在一定的毫秒数后超时。
private IWebElement FindElementById(string id, int timeout = 1000)
{
IWebElement element = null;
var s = new Stopwatch();
s.Start();
while (s.Elapsed < TimeSpan.FromMilliseconds(timeout))
{
try
{
element = _driver.FindElementById(id);
break;
}
catch (NoSuchElementException)
{
}
}
s.Stop();
return element;
}
我也做了一个元素启用
private IWebElement ElementEnabled(IWebElement element, int timeout = 1000)
{
var s = new Stopwatch();
s.Start();
while (s.Elapsed < TimeSpan.FromMilliseconds(timeout))
{
if (element.Enabled)
{
return element;
}
}
s.Stop();
return null;
}
如Wait for page load in Selenium中所述:
In general, with Selenium 2.0 the web driver should only return control to the calling code once it has determined that the page has loaded. If it does not, you can call
waitforelemement
, which cycles round callingfindelement
until it is found or times out (time out can be set).
因为它的简单性,我喜欢这个解决方案。此外,它还具有避免过度等待和从可能的等待上限中进行猜测的好处:
public bool WaitToLoad(By by)
{
int i = 0;
while (i < 600)
{
i++;
Thread.Sleep(100); // sleep 100 ms
try
{
driver.FindElement(by);
break;
}
catch { }
}
if (i == 600) return false; // page load failed in 1 min
else return true;
}
如果需要监控页面加载延迟,可以将其修改为还包括 "timer":
public int WaitToLoad(By by)
{
int i = 0;
while (i < 600)
{
i++;
Thread.Sleep(100); // sleep 100 ms
try
{
driver.FindElement(by);
break;
}
catch { }
}
return i; // page load latency in 1/10 secs
}
刚遇到同样的问题。 使用以下方法,我等待页面完全加载,而不是依赖于 JavaScript、单击或输入元素上的操作导致页面加载。
private void WaitForPageToLoad(Action doing)
{
IWebElement oldPage = _driver.FindElement(By.TagName("html"));
doing();
WebDriverWait wait = new WebDriverWait(_driver, new TimeSpan(0, 0, Timeout));
try
{
wait.Until(driver => ExpectedConditions.StalenessOf(oldPage)(_driver) &&
((IJavaScriptExecutor)driver).ExecuteScript("return document.readyState").Equals("complete"));
}
catch (Exception pageLoadWaitError)
{
throw new TimeoutException("Timeout during page load", pageLoadWaitError);
}
}
如下调用
WaitForPageToLoad(() => _driver.FindElement(By.Id("button1")).Click());
所有没有任何意义的答案。 页面可以包含所有控件。但是你改变了一些东西,控件中的数据发生了变化,页面进入了重新加载状态。所以如果你继续使用这个页面,你会得到一堆错误。 真的,我没有看到比 Thread.Sleep()
更好的解决方案你只需要通过 NuGet 导入 SeleniumExtras 包,然后像下面这样使用它:
var e = new WebDriverWait(driver, new TimeSpan(0, 0, 60)).Until(SeleniumExtras.WaitHelpers.ExpectedConditions.ElementIsVisible(By.Id("--id")));