WebDriver Wait '.until(ExpectedConditions.elementToBeClickable' 仅在我将 Thread.sleep(500) 添加到代码时才有效?
Posted
技术标签:
【中文标题】WebDriver Wait \'.until(ExpectedConditions.elementToBeClickable\' 仅在我将 Thread.sleep(500) 添加到代码时才有效?【英文标题】:WebDriver Wait '.until(ExpectedConditions.elementToBeClickable' only works when i add Thread.sleep(500) to the Code?WebDriver Wait '.until(ExpectedConditions.elementToBeClickable' 仅在我将 Thread.sleep(500) 添加到代码时才有效? 【发布时间】:2016-11-26 12:05:00 【问题描述】:我正在尝试使用 webdriver wait 单击页面上可见的按钮,但 webdriver 只有在我将 Thread.sleep
添加到代码后才能单击该按钮。
在执行我的代码之前,我还检查了按钮是否可见 (True),而它又是 returns = true
。
//按钮可见性检查:
List<WebElement> signOutList = driver.findElements(.xpath(".//*[starts-with(@id,'fulfillment-time-type-section-')]/div[2]//button"));
Assert.assertTrue(signOutList.size() > 0);
//下面的代码没有点击按钮
By timeDropdownButton = By.xpath(".//*[starts-with(@id,'fulfillment-time-type-section-')]/div[2]//button");
WebElement myDynamicElement = (new WebDriverWait(driver, 10))
.until(ExpectedConditions.elementToBeClickable(timeDropdownButton));
myDynamicElement.click();
//下面的代码是否点击了按钮:
Thread.sleep(500);
By timeDropdownButton = By.xpath(".//*[starts-with(@id,'fulfillment-time-type-section-')]/div[2]//button");
WebElement myDynamicElement = (new WebDriverWait(driver, 10))
.until(ExpectedConditions.elementToBeClickable(timeDropdownButton));
myDynamicElement.click();
请注意,我还尝试使用 JS 代码和 WebDriver 操作等单击按钮
我不知道为什么“Wait Clickable”只有在与“Thread.sleep”结合使用时才有效?
The button I'm trying to click
【问题讨论】:
您是否尝试过将时间从 10 秒增加到更多..??? 嗨 Saurabh,我尝试了以下代码,但仍然无法正常工作(从 10 更改为 1000):WebElement myDynamicElement = (new WebDriverWait(driver, 1000)) 尝试使用ExpectedConditions.visibilityOfElementLocated
..告诉我..
感谢您帮助 Saurabh,恐怕即使尝试 ExpectedConditions.visibilityOfElementLocated 它仍然不起作用
你能分享一下发生了什么异常吗??
【参考方案1】:
您希望在测试中尽可能避免Thread.sleep
。仅仅通过几个测试它可能看起来并不那么重要,但它们的使用存在很多固有的问题。首先,如果你有一堆测试,测试套件的运行时间可能会变得难以管理。其次,它们有时还不够。例如,对于一般的生产机器,等待 500 毫秒可能就足够了,但如果 Web 服务器处于高负载或测试环境中,则可能需要 750 毫秒才能准备好。然后,您正在处理非确定性故障。最好使用WebDriverWait
之类的构造,并给它们一个合理(但过于慷慨)的最大值,这样您就不必等待比必要的时间更长,但如果它失败了,则意味着下面的环境存在严重问题测试。
这里的必胜客网站也大量使用异步 java 脚本和浮动面板等。所有这些都需要在使用 Selenium 时更加小心,因为元素需要在与它们交互之前准备好,但它们通常是已经在 DOM 中了。这意味着默认情况下,Selenium 可能会在 javascript 完成之前快速找到它们,并且它们实际上并未处于准备使用状态。您将希望像您已经尝试做的那样使用 ExpectedConditions。您遇到问题的按钮需要等待 JavaScript 完成,这是已经建议的,但它不需要在页面加载时,而是在单击按钮之前。在我的机器上运行的示例:
@Test
public void foo()
WebDriver driver = new FirefoxDriver();
driver.manage()
.window()
.maximize();
// Move through the page to the point you are interested in
driver.get("https://www.pizzahut.co.uk/");
waitForElement(driver, By.cssSelector(".hidden-xs [title='Pizza']")).click();
waitForElement(driver, By.cssSelector("form[action='/menu/startyourorder']")).submit();
WebElement postElement = waitForElement(driver, By.id("ajax-postcode-txt"));
postElement.sendKeys("TS1 4AG" + Keys.ENTER);
// Wait for the java script to finish executing
waitForJavaScript(driver);
// Finally you should be able to click on the link
waitForElement(driver, By.partialLinkText("Start Your Order")).click();
// continue on ... then quit the driver
driver.quit();
private WebElement waitForElement(WebDriver driver, By locator)
return new WebDriverWait(driver, 10).until(ExpectedConditions.elementToBeClickable(locator));
private void waitForJavaScript(WebDriver driver)
new WebDriverWait(driver, 10).until(new Predicate<WebDriver>()
public boolean apply(WebDriver driver)
return ((JavascriptExecutor) driver).executeScript("return document.readyState")
.equals("complete");
);
在 WebDriverWait 中,给定的 int 参数是它将继续尝试给定检查的秒数。如果达到设定的数量(上例中为10
秒),它将抛出TimeoutException
。
【讨论】:
【参考方案2】:页面上可能仍在执行活动的 Javascript。在第一瞬间,它可能会以ExpectedCondition
无法分辨的方式对其进行修改。当我遇到意外行为问题时,我发现等待页面加载(包括 JavaScript 脚本)通常可以解决大部分问题。
要等待页面加载,您可以调用您的一些 Javascript 来检查文档的readyState
。尝试等待页面加载,然后等待元素可点击。
快速搜索返回此 (code taken from here):
wait.until( new Predicate<WebDriver>()
public boolean apply(WebDriver driver)
return ((JavascriptExecutor)driver).executeScript("return document.readyState").equals("complete");
);
【讨论】:
感谢@Parker 的帮助,我在上面的代码中试过了,但还是不行 【参考方案3】:以下方法似乎可以正常工作:
public void waitForPageLoad()
ExpectedCondition<Boolean> expectation = new
ExpectedCondition<Boolean>()
public Boolean apply(WebDriver driver)
return ((JavascriptExecutor) driver).executeScript("return document.readyState").toString().equals("complete");
;
try
Thread.sleep(1000);
WebDriverWait wait = new WebDriverWait(driver, 30);
wait.until(expectation);
catch (Throwable error)
Assert.fail("Timeout waiting for Page Load Request to complete.");
【讨论】:
【参考方案4】:尝试使用 PageFactory 实现,看看 selenium API 是否为您解决了问题。
public class OrderMyPizzaPage
@FindBy(css="form[action='/menu/startyourorder']")
WebElement startMyOrder;
public void startOrder()
startMyOrder.click();
太好了,现在如果我们假设其他所有事情都已成功完成,并且我们可以点击“开始您的订单”
public void myExecutingMethod(WebDriver driver)
//previous steps occur and we've just performed interactions which should cause the 'start your order' button to be on the dom
OrderMyPizzaPage orderPage = PageFactory.initElements(driver, OrderMyPizzaPage.class);
orderPage.startOrder();
//And now maybe it worked?
如果这不起作用,请尝试更强力的方法。为您的 WebDriverWait 创建一个自定义谓词,在发布前检查点击后条件是否为真。如果不正确,则让谓词重新执行点击!
由于时区问题,我无法查找 成功的点击后内容,因此在 sn-p。它被标记为 FIXME
public void startOrder(WebDriver driver)
WebDriverWait wait = new WebDriverWait(driver, 30);
//Throttle the polling!
wait.pollingEvery(1500, TimeUnit.MILLISECONDS);
wait.until(new Predicate<WebDriver>()
public boolean apply(WebDriver input)
boolean successfulClick = false;
//FIXME: Need to check for something that should occur after the click happens successfully
By lookupAfterClick = By.cssSelector("");
WebElement nextElement = ExpectedConditions.visibilityOfElementLocated(lookupAfterClick).apply(input);
if (nextElement == null)
System.out.println("Not there yet, Keep trying!");
By startOrderLookup = By.cssSelector("form[action='/menu/startyourorder']");
WebElement startOrder =ExpectedConditions.visibilityOfElementLocated(startOrderLookup).apply(input);
if (startOrder != null)
System.out.println("Clicking Start Order!");
startOrder.click();
else
System.out.println("Start Order isn't visible!");
else
System.out.println("Hey, That worked!");
successfulClick = true;
return successfulClick;
);
【讨论】:
【参考方案5】:您是否尝试过使用 urlContains ?我遇到了你问的同样的问题,不知何故线程睡眠正常
详情如下
(new WebDriverWait(driver, 50)).until(ExpectedConditions.urlContains("/completing-profile?step=skin_type"));
【讨论】:
以上是关于WebDriver Wait '.until(ExpectedConditions.elementToBeClickable' 仅在我将 Thread.sleep(500) 添加到代码时才有效?的主要内容,如果未能解决你的问题,请参考以下文章