C#Selenium WebDriverWait.IgnoreExceptionTypes不起作用

时间:2017-11-06 19:33:46

标签: c# selenium-webdriver webdriver selenium-chromedriver

我正在尝试使用Selenium WebDriverWait类型在检查元素是否存在之前等待页面完全加载。我尝试过两种不同的方式。

First Method使用IgnoreExceptionTypes,然后在Until Method中调用FindElement。这会立即抛出NoSuchElementException而不等待。我预计这会继续尝试在超时之前找到该元素,同时忽略NoSuchElementException。它似乎不是这样工作的。为什么Method1不起作用?

第二种方法使用ExpectedConditions.ElementExists,似乎正确等待。

driver.Navigate().GoToUrl("http://www.google.com");
var myId = "myId";

//Method 1
var wait1 = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
wait1.IgnoreExceptionTypes(typeof(NoSuchElementException));

//Does not wait. Immediately throws NoSuchElementException
var result1 = wait1.Until(x => x.FindElement(By.Id(myId)));

//Method 2    - works as expected
var wait2= new WebDriverWait(driver,TimeSpan.FromSeconds(10))
    .Until(ExpectedConditions.ElementExists(By.Id(myId)));

1 个答案:

答案 0 :(得分:1)

回答新重新提出的问题...

所以我一直这样做。我使用页面对象模型来编写自动化,这样就可以很好地工作了,但即使你没有使用页面对象模型,你仍然可以使用它。

基本概念就是这样......你找到一个最后加载的元素并等待该元素。此时,您知道页面已完成加载,您的脚本可以继续,而不必担心与未完成加载的页面上的某些元素进行交互。

警告......我怎么知道哪个元素是最后加载的?我不知道。你基本上猜测(希望有教育的猜测)并使用它直到它失败。如果您的页面不是非常动态,那么只需选择任何元素即可。如果页面的一部分加载较晚,请在页面的该部分内选择一个元素。

这就是我通常的情况。我为某个页面编写了一个页面对象。我在页面上选择一个唯一元素并将其声明为By waitForLocator。现在,当我想等待页面完成加载时,我打电话

By waitForLocator = By.Id("myId");
new WebDriverWait(Driver, TimeSpan.FromSeconds(10)).Until(ExpectedConditions.ElementIsVisible(waitForLocator));

现在我(相当)确信页面已完成加载,我将继续为页面对象编写方法,依此类推。我编写了一个脚本,它使用该页面对象并根据我的测试用例与页面进行交互,然后运行脚本。希望我选好了waitForLocator。如果我没有,在脚本运行期间的某个时刻我会得到一些异常,因为某些元素没有完全加载(它在我选择的元素之后加载)。所以,我将waitForElement更改为我刚刚与之交互的元素抛出异常,现在我应该更好地猜测最后一个加载元素。你基本上重复这个过程,直到你不再有例外。

你可能会说,这是一种非常随意的方法。它看起来真的比实际上更随意。如果您了解自己的网站和网页,那么您首先会做出相当不错的猜测。我不得不一次改变这种猜测,而且我不得不多次更改它是非常罕见的。也就是说,改变它真的很容易。您已经拥有了抛出异常的元素的定位器,您只需将其粘贴到waitForLocator的声明中即可。

您可能遇到的一个例外情况是,如果您在页面加载后正确选择了waitForLocator,则单击页面上的某个动态加载某些元素的元素页面的其他部分。此方案超出了等待页面加载的范围。在这种情况下,您必须构建另一个等待页面的新加载部分在执行单击后完成加载的等待。它不会影响页面加载机制。

补充意见

回过头来阅读你的问题后,这里有一些额外的信息可以让你的生活更轻松。

您的原始问题有一个我在下面简化/修改的方法来演示这个原则

public void ClickElementById(RemoteWebDriver driver, string id)
{
    driver.FindElement(By.Id(id)).Click();
}

编写此方法的方式,您强制自己为每个定位器类型,ID,名称,CSS选择器,XPath等创建方法。而不是传入字符串,传入By定位器。

public void ClickElement(RemoteWebDriver driver, By locator)
{
    driver.FindElement(locator).Click();
}

现在使用这种新方法,它非常灵活。您可以传入任何定位器类型,它将起作用。要调用它,你可以使用

之类的东西
ClickElement(driver, By.Id("someId"));