WebElement.clear()触发javascript更改事件 - 替代品?

时间:2013-11-07 10:38:48

标签: java selenium webdriver selenium-webdriver

我使用selenium IDE来初始记录测试并将它们保存为Java WebDriver测试。

当我进入输入字段时,删除所有文本并输入新值,它将其记录为2个命令:

driver.findElement(By.id("username")).clear();
driver.findElement(By.id("username")).sendKeys("johnnyleitrim");

对我来说,一个问题是clear()事件会触发“username”字段的Javascript更改事件。当我使用浏览器本身时不会发生这种情况 - 它会等到字段在触发更改javascript事件之前失去焦点,这就是我想在Selenium中模拟的内容。

我需要这个的原因是我对change()事件进行了验证,并且当使用空值调用change时,它会显示一条警告,告诉用户信息无效 - 此警报会停止Selenium

那么如何在不使用WebElement.clear()的情况下清除字段?

3 个答案:

答案 0 :(得分:8)

您可以避免使用clear()方法并使用Actions类一次清除和设置文本,因此只有在设置文本后才会触发onchange()事件。

请调用以下方法:

ClearAndSetText(By.id("username"),"johnnyleitrim");

该方法单击元素,使用shift + home键选择现有文本,使用退格键清除,然后键入新文本 - 就像用户的行为一样。

public void ClearAndSetText(By by, string text)
{
    WebElement element = driver.findElement(by);
    Actions navigator = new Actions(driver);
    navigator.click(element)
        .sendKeys(Keys.END)
        .keyDown(Keys.SHIFT)
        .sendKeys(Keys.HOME)
        .keyUp(Keys.SHIFT)
        .sendKeys(Keys.BACK_SPACE)
        .sendKeys(text)
        .perform();
}

答案 1 :(得分:1)

您可以使用JavaScriptExecutor进行尝试(虽然我尚未对其进行测试)。

JavaScriptExecutor js = (JavaScriptExecutor) driver;
js.executeScript("document.querySelector(\"input[id='username']\").value = ''");

答案 2 :(得分:0)

好像是known Selenium bug。在bug页面上提到的解决方法有一些选项,但它们都意味着必须“大量”修改从Selenium IDE返回的代码。相反,我决定创建一个代理,它可以为我完成工作,而无需对IDE生成的代码进行太多修改:

protected WebElement findElement(By criteria) {
    try {
        WebElementHandler webElementHander = new WebElementHandler(seleniumWebDriver.findElement(criteria));
        return (WebElement) Proxy.newProxyInstance(getClass().getClassLoader(), new Class[]{WebElement.class}, webElementHander);
    } catch (NoSuchElementException e) {
        logger.error("Could not find " + criteria + " on page " + seleniumWebDriver.getCurrentUrl());
        throw e;
    }
}

private class WebElementHandler implements InvocationHandler {
    private WebElement proxiedElement;

    private WebElementHandler(WebElement proxiedElement) {
        this.proxiedElement = proxiedElement;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if (method.getName().equals("clear")) {
            Keys[] keys = new Keys[proxiedElement.getAttribute("value").length()];
            for (int i = 0; i < keys.length; i++)
                keys[i] = Keys.BACK_SPACE;

            proxiedElement.sendKeys(Keys.chord(keys));
            return null;
        }
        return method.invoke(proxiedElement, args);
    }
}