如何用WebDriverWait替换Thread.sleep以避免StaleElementReferenceException

问题描述 投票:0回答:1

问题1:我正在使用https://candymapper.com/演示页面来练习自动化测试,我遇到了以下问题。当我使用 Javascript Executor .scrollIntoView 时,之后我的元素变得陈旧并且测试中断。

  1. 由于使用 Thread.sleep 不是一个好的做法,有没有其他方法可以使用 wdwait 解决该问题?
  2. 另外,是否有另一种方法可以在不使用 Javascript Executor 的情况下滚动到元素?

这是我的代码:

@Test
    public void candyMapperTest() throws InterruptedException {
        driver.get("https://candymapper.com/");
        wdwait.until(ExpectedConditions.presenceOfElementLocated(By.id("popup-widget37723-close-icon")));
        driver.findElement(By.id("popup-widget37723-close-icon")).click();
        wdwait.until(ExpectedConditions.elementToBeClickable(driver.findElement(By.cssSelector("input[data-aid=\"CONTACT_FORM_EMAIL\"]"))));
        jse.executeScript("arguments[0].scrollIntoView(true)", driver.findElement(By.cssSelector("input[data-aid=\"CONTACT_FORM_EMAIL\"]")));
        //Thread.sleep(3000);
        //wdwait.until(ExpectedConditions.refreshed(ExpectedConditions.elementToBeClickable(By.cssSelector("input[data-aid=\"CONTACT_FORM_EMAIL\"]"))));
        //wdwait.until(ExpectedConditions.elementToBeClickable(By.cssSelector("input[data-aid=\"CONTACT_FORM_EMAIL\"]")));
        wdwait.until(ExpectedConditions.elementToBeClickable(driver.findElement(By.cssSelector("input[data-aid=\"CONTACT_FORM_EMAIL\"]"))));
        driver.findElement(By.cssSelector("input[data-aid=\"CONTACT_FORM_EMAIL\"]")).sendKeys("[email protected]");
        wdwait.until(ExpectedConditions.elementToBeClickable(By.cssSelector("button[data-aid=\"CONTACT_SUBMIT_BUTTON_REND\"]")));
        driver.findElement(By.cssSelector("button[data-aid=\"CONTACT_SUBMIT_BUTTON_REND\"]")).click();
        wdwait.until(ExpectedConditions.elementToBeClickable(By.xpath("//span[contains(text(), \"inquiry\")]")));
        Assert.assertEquals("Thank you for your inquiry! We will get back to you within 48 hours.", driver.findElement(By.xpath("//span[contains(text(), \"inquiry\")]")).getText());

问题2:我在本页的另一个测试中遇到了类似的问题:(https://demoqa.com/automation-practice-form)。我想断言输入字段边框颜色更改为红色。 Selenium 速度太快,并且在边框颜色更改之前进行断言,因此测试因 rbg 颜色不匹配而中断。另外,我正在使用 Javascript Executor 单击“提交”按钮,因为有一个无法关闭或最小化的谷歌广告横幅(仅在 Chrome 上显示)。

Submit button hiden behind the ad image

  1. 由于使用 Thread.sleep 不是一个好的做法,有没有其他方法可以使用 wdwait 解决该问题?
  2. 此外,在这种情况下,是否有另一种方法可以在不使用 Javascript Executor 的情况下单击元素?

我的问题2代码:

@Test
    public void demoQANegativeRegistrationTest() throws InterruptedException {
        driver.get("https://demoqa.com/automation-practice-form");
        driver.findElement(By.id("userNumber")).sendKeys("12345");
        jse.executeScript("arguments[0].click();", driver.findElement(By.id("submit")));
        Thread.sleep(2000);
        //wdwait.until(ExpectedConditions.elementToBeClickable(By.xpath("//*[@class=\"was-validated\"]")));
        WebElement icon = driver.findElement(By.id("userNumber"));
        String userNumberBorderColor = icon.getCssValue("border-color");
        Assert.assertEquals("rgb(220, 53, 69)", userNumberBorderColor);

问题1:我尝试引入几个不同的WebDriverWaits,比如presenceOfElement、elementToBeClickable、refreshed,但是每次结果都是一样的(其中一些在上面的代码中有注释)。如果我在 jse 之后添加 Thread.sleep,测试将完美运行。

问题2:我发现边框颜色更改为红色后出现了值“was-validated”的类元素,因此我尝试在执行断言之前等待,但每次测试都会得到错误的rbg颜色(默认为灰色)。你可以在代码中找到它的注释。当我在断言之前引入一个简短的 Thread.sleep 时,测试每次都能完美运行。

为了点击“提交”按钮,我尝试全屏显示并使用 actions.moveToElement,但在这两种情况下,点击都会被谷歌广告横幅拦截。我只能通过 jse 脚本执行点击。

java selenium-webdriver selenium-chromedriver webdriverwait thread-sleep
1个回答
0
投票

在第一种情况下,只要输入在加载后重新渲染,您就会得到

StaleElementReferenceException
。为了避免它,你应该等待它的可见性。

对于滚动,您可以使用 Selenium 中的

moveToElement
Actions

Actions actions = new Actions(driver);
driver.findElement(By.id("popup-widget37723-close-icon")).click();
WebElement formEmail = wdwait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("input[data-aid=\"CONTACT_FORM_EMAIL\"]")));
actions.moveToElement(formEmail).click().sendKeys("[email protected]").perform();

第二种情况与第一种情况相同 - 你太早调用断言了。属性全部异步应用,因此在更改后进行断言无法工作/稳定,因为更改尚未应用。

这里的解决方案是等待属性相等或者等待属性在某个时间间隔内不发生变化。 在Java / JS中有很多方法可以做到这一点,我分享其中一种使用

ExpectedConditions
和JS函数的组合

JS 中的这个函数返回你的

border-color

return window.getComputedStyle(document.querySelector('#userNumber'))['border-color']

所以你可以在

jsReturnsValue
期望中调用它:

WebElement icon = driver.findElement(By.id("userNumber"));
wdwait.until(ExpectedConditions.jsReturnsValue("return window.getComputedStyle(document.querySelector('#userNumber'))['border-color'] ?? undefined"));
© www.soinside.com 2019 - 2024. All rights reserved.