我有一个带有按钮的网页,Selenium一直坚持这个按钮是不可见的,尽管它肯定是。
页面来源:
<button id="product-catalog-page_order-selected-button" class="btn btn-grey
mq-apla-button opens-overlay" data-bind="click: runOrderWizard, enable:
hasSelection"><span localize-me="">Order Selected</span></button>
<span localize-me="">Order Selected</span>
在此之下,有一个包含条目列表的动态表。条目在第一个单元格中有一个复选框。在选中此框之前,上面的按钮被禁用。但是,点击它后立即启用按钮。
我尝试使用ID和XPath访问(单击)此按钮。我已经为&lt; button和&lt; span元素尝试了XPath。每次我尝试,我都会收到此错误:
Result StackTrace:
at OpenQA.Selenium.Remote.RemoteWebDriver.UnpackAndThrowOnError(Response
errorResponse)
at OpenQA.Selenium.Remote.RemoteWebDriver.Execute(String
driverCommandToExecute, Dictionary`2 parameters)
at OpenQA.Selenium.Remote.RemoteWebElement.Click()
at Common.Navigation.Elements.Button.ClickById(String id) in d:\Source
\Workspaces\QA\NewMySite\Common\Elements\PageElements.cs:line 51
at MyAutomation.Pages.NewOrderPage.OrderSelected() in d:\Source
\Workspaces\QA\NewMySite\MyAutomation\Pages\NewOrderPage.cs:line 36
at Tests.RegressionTests.Ordering.Ordering.User_Order_New_Hardware() in
d:\Source\Workspaces\QA\NewMySite\Tests\RegressionTests\Ordering
\Ordering.cs:line 29
Result Message:
Test method
Tests.RegressionTests.Ordering.Ordering.User_Order_New_Hardware threw
exception:
OpenQA.Selenium.ElementNotVisibleException: **element not visible**
(Session info: chrome=62.0.3202.94)
(Driver info: chromedriver=2.33.506120
(e3e53437346286c0bc2d2dc9aa4915ba81d9023f),platform=Windows NT 10.0.15063
x86_64)
在单击复选框并单击按钮之前,我也立即停止了Selenium测试(等待3秒钟)。然后我手动尝试点击按钮,它运行正常。
也没有重复的ID;页面上只有一个元素具有此ID。
任何想法我在这里做错了什么,或者如果它的硒是愚蠢的,如何解决这个问题?
这是相关的程序/测试代码:
Button.ClickById("product-catalog-page_order-selected-button"));
public class Button {
public static void ClickById (string id) {
FindById(id).Click();
}
private static IWebElement FindById (string id) {
return GCDriver.Instance.FindElement(By.Id(id));
}
}
我还尝试使用此代码等待元素可见。没运气。等待时间过了。
Wait.WaitForVisibleId("product-catalog-page_order-selected-button");
public class Wait {
public static void WaitForVisibleId (string id) {
GCDriver.WaitForVisibleId(id);
}
}
public class GCDriver {
public static void WaitForVisibleId (string id) {
var wait = new WebDriverWait(GCDriver.Instance,
TimeSpan.FromSeconds(30));
wait.Until(driver => driver.FindElement(By.Id(id)).Displayed);
}
}
前段时间,我在这个网站上有另一个按钮,我无法通过Selenium访问。那是一个文件上传按钮。我不记得Exception,但是我用这段代码解决了这个问题:
public static void ActionsUploadButtonId (string id, string filepath) {
Actions actions = new Actions(GCDriver.Instance);
actions.MoveToElement(GCDriver.Instance.FindElement(By.Id(id)));
actions.Click();
actions.Build().Perform();
}
但是,这并不适用于此。但它似乎做了一些事情:当我将有问题的按钮的ID(&#34; product-catalog-page_order-selected-button&#34;)提供给该方法时,它会选择页面上非常第一个可点击的元素,这是Front Page链接,有自己唯一的ID,在元素上方有几百行HTML代码和实际ID。
如果问题中缺少任何相关信息,请告诉我而不是downvoting。
更新: 要进行故障排除,我按照我在StackOverflow上的另一个线程中找到的提示:使用Submit()而不是Clic()。但是,这导致了另一个(可能是逻辑的)异常:
OpenQA.Selenium.NoSuchElementException: no such element: Element was not in a form, so could not submit.
更新2: 我也尝试过上课时按钮。有两个按钮具有完全相同的类,但也许它会得到第一个?无论如何,这导致完全相同的ElementNotVisible异常。
更新3: 两者都在等待可见并等待可点击的时间。
wait.Until(driver => driver.FindElement(By.Id(id)).Displayed);
wait.Until(ExpectedConditions.ElementToBeClickable(By.Id(id)));
更新4: 复选框的html代码(在选中时启用按钮):
<td class="table-column-checkbox">
<input type="checkbox" data-bind="checked: $parent.selected, checkedValue: href" value="/Api/CatalogProducts/ProductOfferings/PO-6E32-CE4C-C169">
</td>
更新5: 该按钮对Selenium是不可见的,是否启用它是否已启用:
结果:OpenQA.Selenium.ElementNotVisibleException:元素不可见
选中复选框
更新6:
查看源代码,页面上没有任何元素设置为&#34;隐藏&#34;,因此应该消除任何不可见的父元素搞乱。
唯一不能找到的是,有两个HTML代码块,其中一个具有相同ID的按钮在页面上被注释掉。这些出现在相关按钮之前,但我不希望Selenium对注释掉的HTML代码感到烦恼吗?
答案 0 :(得分:1)
我从未发现Selenium对此类事情有误。我总是认为Selenium是正确的,你的定位器是关闭的,或者在你不知道的页面中发生了什么。
我找到定位器的第一种方法是在Chrome中使用开发控制台。我个人最喜欢Chrome开发工具,但这是个人偏好(大多数情况下)。使用$$(locator)
测试CSS选择器,使用$x(locator)
测试XPath。这些将返回由这些定位器找到的元素集合。您可以立即判断您是否找到了多个,如果您想要的不是第一个,等等。我通常只是通过浏览页面来做到这一点,但如果您仍然遇到问题,请设置断点并停止违规行,然后在浏览器中执行此操作。
如果仍然无效,我会添加一些调试命令来调查违规行之前的页面,例如
Console.WriteLine(Driver.FindElements(locator).Count);
并确保定位器找到正确的元素,找到预期的元素数量等
您还可以在导致问题的行上放置断点,在调试模式下运行脚本,然后使用“立即”窗口测试代码。
其他评论
我在评论中提到你应该传递By
个类而不是字符串,并且你要求一个例子。
public class Button
{
public static void Click(By locator)
{
Find(locator).Click();
}
private static IWebElement Find(By locator)
{
return GCDriver.Instance.FindElement(locator);
}
}
你会称之为
Button.Click(By.Id("id"));
您的WaitForVisible()
方法比它需要的更复杂。你应该阅读ExpectedConditions
。有许多已经可用的东西需要等待,这将照顾你需要的90%以上的等待时间。我也会传递一个TimeSpan
,这样你就可以控制等待时间,而不必总是等待硬编码的30秒。
public class GCDriver
{
public static void WaitForVisible(By locator, TimeSpan timeout)
{
new WebDriverWait(GCDriver.Instance, timeout).Until(ExpectedConditions.ElementIsVisible(locator));
}
}
你甚至可以更进一步传递Func
,这将允许你等待任何,而不仅仅是可见。
public class GCDriver
{
public static void Wait(Func<IWebDriver, IWebElement> func, TimeSpan timeout)
{
new WebDriverWait(GCDriver.Instance, timeout).Until(func);
}
}
并将其称为
GCDriver.Wait(ExpectedConditions.ElementIsVisible(locator), TimeSpan.FromSeconds(10));
答案 1 :(得分:0)
经过数小时的故障排除后,我找到了原因。或者,至少是其中的一部分。
当我使用FindElements而不是FindElement时,它会计算具有相同ID的两个元素。当我在单击按钮时拍摄页面源的快照时,这些不可见。
但是,原因是包含该按钮的页面有3个选项卡。所有标签的按钮应该相同,因为它是&#34;订购所选&#34;按钮和选项卡包含要订购的事物列表。但由于最近才实现了唯一ID,因此在创建此页面时并未考虑到这一点。
因此,DOM包含至少2个相同的ID,这些ID在页面源中不可见。但奇怪的是,FindElements应该返回3个元素而不是2.或者DOM可能更加混乱。
无论如何:当我告诉Selenium单击SECOND元素时,就像这样,
GCDriver.Instance.FindElements(By.Id(id))[1].Click();
它有效。