WebDriver:更改事件未触发

12

我有一个使用KnockoutJS的应用程序,现在我正在尝试编写一些测试来测试一个表单。如果您不知道KnockoutJS,简单来说,它提供了从我的视图到数据模型的绑定。这意味着当我在输入字段中输入值时,我的底层对象会自动更新为该输入字段的值。默认情况下,这是通过更改事件完成的。

问题是,当我的WebDriver测试向字段键入时,更改事件没有触发,因此我的底层数据模型没有相应的值。这导致我的表单验证失败。

我已经尝试了网络上所有能找到的方法:

  1. 发送Tab键
  2. 点击表单字段外
  3. 发送JavaScript代码以触发focus和blur事件(验证发生在blur上)
  4. 在键入之前先点击表单字段
  5. 设置等待时间以防止时间问题
  6. 更改KnockoutJS以在afterkeydown上更新输入字段

但以上方法都没有解决我的问题。

此外,我已经验证过这不是事件冒泡的问题,因为我明确地删除了所有其他事件,只留下了KnockoutJS更改事件。

我要求的解决方案是适用于所有浏览器驱动程序(至少主要的驱动程序,例如IE,FF,Chrome,Safari),并且不需要使用jQuery。

如何解决这个问题?

这是我用来输入字段值的相关代码:

// find element
WebElement input = this.element.findElement(By.className("controls"))
                               .findElement(By.tagName("input"));

// to set focus?
input.click();

// erase any existing value (because clear does not send any events
for (int i = 0; i < input.getAttribute("value").length(); i++) {
    input.sendKeys(Keys.BACK_SPACE);
}

// type in value
input.sendKeys(text);

// to fire change & blur? (doesnt fire change)
//input.sendKeys(Keys.TAB);

// to fire change & blur? (doesnt fire change)
driver.findElement(By.tagName("body")).click();

所以,如果我理解正确,它会在每次按键时更新“输入”字段? - Brian
请原谅我问一个可能有些愚蠢的问题,但是当您在浏览器中手动与该页面交互时,该页面是否正常工作?例如,如果您在浏览器中查看该页面,输入文本字段并切换到其他字段,那么模型是否已更新? - RodneyTrotter
1
@Brian 用户更新了输入字段。当onchange事件触发时,底层数据模型将更新为输入字段中的值(至少应该是这样)。如果我更改数据模型中的基础值,则输入字段将自动更新为新值。这一切都由KnockoutJS提供。 - loesak
@RodneyTrotter 是的,在所有浏览器中都按预期工作。只是在使用WebDriver时不起作用。我已经通过一个临时解决方案解决了这个问题,我会发布它,但现在我不打算将其标记为答案,因为我认为应该有更好的方法。 - loesak
@loesak:你能发布一下你的Web应用程序的HTML吗?如果是onblur触发更新,那么当你使用JavaScript明确触发onblur事件时什么都没有发生似乎非常奇怪。 - Vince Bowdren
@vincebowdren 当更改事件触发时,更新会发生,当模糊事件触发时,我的验证会发生。为了缩小问题范围,我删除了模糊事件。问题在于更改事件不触发,无论是否存在模糊事件。我必须显式地触发更改事件才能进行更新。 - loesak
2个回答

5

我已经找到了一个解决这个问题的方法,但我并不认为这是正确的解决方案。这违反了我的规则,即不使用jQuery,但是由于KnockoutJS需要加载jQuery,所以我认为这对我来说是可以接受的。可能有纯JavaScript的方式来解决这个问题。我已经在FireFox、Safari和PhantomJS中进行了测试。我假设它在Chrome中也能正常工作。但我不能保证在Internet Explorer中也能正常工作。

不会将此答案标记为正确答案。正确的解决方案应该是通过WebDriver浏览器触发适当的事件。只有在我相信通过WebDriver无法实现时,我才会将其标记为正确答案。

// find element in question
WebElement input = this.element.findElement(By.className("controls"))
                               .findElement(By.tagName("input"));

// click it to fire focus event
input.click();

// erase any existing value
for (int i = 0; i < input.getAttribute("value").length(); i++) {
    input.sendKeys(Keys.BACK_SPACE);
}

// enter in desired text
input.sendKeys(text);

// fire on change event (WebDriver SHOULD DO THIS)
((JavascriptExecutor) driver).executeScript(
        "$(arguments[0]).change(); return true;"
    , input);

// click away to fire blur event
driver.findElement(By.tagName("body")).click();

如果您能提供可重现的场景并证明这是WebDriver的问题,请提交错误报告。 - Arran
所以我创建了一个项目来重现这个问题,在这个过程中我找到了问题所在。简而言之,这是一个新手错误。我想链接演示项目,但我的 Git 新手经验阻止了我提交该项目。 - loesak

4
所以我相信我已经找到了问题所在。我必须充分承认这是PEBKAC(Problem Exists Between Keyboard And Chair,即键盘和椅子之间存在问题)。我忘记了如果浏览器窗口不在机器上的活动焦点中,WebDriver会有问题(这对我来说仍然很奇怪)。当我调试问题时,我使用编辑器逐步执行代码。通过正常运行代码并且不将焦点从浏览器中移除,使用所有三种解决方案(选项卡、点击或JavaScript)预期地触发事件。

我有一个示例项目显示了所有三种方法,但我在使用git和github方面是个菜鸟,并且在交付项目方面遇到了问题。一旦我解决了这个问题,我就会与你们分享这个项目。

编辑: 在GitHub上放置了示例代码 (https://github.com/loesak/knockout.webdriver.change.event.test)。您可以将该项目作为Web应用程序在服务器上启动并手动运行测试,也可以通过maven运行测试 (mvn clean install)。 我没有花太多力气使其健壮工作,因此它假定您已安装Firefox并且端口 0808 8080 已打开。

编辑: 更正了状态端口号


恭喜你解决了这个问题,加一分。 - Brian

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接