javascript - Java - 使用 Selenium 等待 JavaScript 事件(例如 onchange)完成

标签 javascript java selenium events onchange

一组逻辑相关的 input 字段有一个 onchange 事件。在遍历字段并修改它们的值后,由于 onchange 事件所做的事情,一些字段得到正确更新,而另一些则没有正确更新。

onchange 事件在字段上触发的那一刻,它开始一些处理(涉及其他相关字段),将值存储在某处并清除其他相关字段(如果它们之前未被自己处理) onchange 事件。

我可以让线程 hibernate 任意时间,但这看起来不太好。它只是猜测处理需要多少时间,然后选择是在充足的 sleep 中浪费时间还是拥有一个可以中止超时的脚本。

有没有办法知道 JavaScript 代码(由 onchange 事件调用)何时完成其工作?

原始代码

Wait<WebDriver> wait = new WebDriverWait(driver, 25, 500);
for(int i = 1; i <= fieldCount; i++) {
    elementId = "field$" + i;
    wait.until(ExpectedConditions.elementToBeClickable(By.id(elementId)));
    driver.findElementById(elementId).sendKeys(data);
    //The mess happens if I don't sleep
    Thread.sleep(3000);
}

输出

sleep 时:Field1:_w_ ... Field2:_x_ ... Field3 :_y_ ... FieldN:_z_

没有 sleep :Field1:_w_ ... Field2:___ ... Field3 :_y_ ... FieldN:___

注意事项:

我遇到了一些问题,所以我认为值得一提的是在简短的笔记中吸取的教训:

WARNING: Do not mix implicit and explicit waits.

Use WebDriverWait (specialization of FluentWait) instead of FluentWait, unless you have a very specific requirement. E.g., WebDriverWait ignores NotFoundException (NoSuchElementException's superclass) by default. See recomendation.

最佳答案

经过认真的重构和一些研究,我终于做到了。 onchange 事件在 input 字段的值发生变化且元素失去焦点时触发。使用 WebElement(例如 sendKeys())操作字段不是一种选择,因为您无法控制后台处理,因此使用 JavascriptExecutor是选择。首先,我使用 JavaScript(不会触发事件)更新字段的值,然后,我触发了 onchange 事件,同样使用 JavaScript:

//Setting implicit wait to 0 to avoid mess with explicit waits
driver.manage().timeouts().implicitlyWait(0, TimeUnit.SECONDS);
//Use WebDriverWait instead of FluentWait (it's superclass)
Wait<WebDriver> wait = new WebDriverWait(driver, 25, 500);
for(int i = 1; i <= fieldCount; i++) {
    String elementId = "field$" + i;
    String javaScript = String.format("document.getElementById('%s').value='%s';", elementId , myValue);
    Object jsResult = wait.until(ExpectedConditions.javaScriptThrowsNoExceptions(javaScript));
    javaScript = String.format("return document.getElementById('%s').dispatchEvent(new Event('change'));", elementId);
    jsResult = wait.until(ExpectedConditions.jsReturnsValue(javaScript));
}

这里有一些关键方面。

  • 不要混用隐式和显式等待(我从惨痛的教训中学到的),这会导致意想不到的结果。
  • 使用 WebDriverWait(FluentWait 的特化)而不是它的父类(super class),除非您有非常具体的要求。如果您使用 FluentWait,请确保忽略适当的异常;否则你将开始收到 NoSuchElementException
  • onchange 事件在 input 字段的值更改且元素失去焦点时触发。
  • > dispatchEvent()在指定的 EventTarget ( synchronously ) 处分派(dispatch)一个 Event,以适当的顺序调用受影响的 EventListener。这适用于 custom events以及。这是 very nice post用于 Activity 。

我使用以下代码来更好地掌握 ExpectedConditions.javaScriptThrowsNoExceptionsExpectedConditions.jsReturnsValue .这是一个 JavaScript 函数调用,只会让引擎忙几秒钟。这样您就可以看到显式等待与 JavaScript 的交互并检查返回值。请注意,每个 ExpectedCondition 的 JS 代码都略有不同:

//ExpectedConditions.jsReturnsValue
String javaScript = "(function watcher(ms){var start=new Date().getTime();var end = start;while(end<start+ms){end=new Date().getTime();};return 'complete';})(5000);return 'success';";
log.trace("javaScript={}", javaScript);
Object jsResult = wait.until(ExpectedConditions.jsReturnsValue(javaScript));
log.trace("jsResult={}", jsResult);

//ExpectedConditions.javaScriptThrowsNoExceptions
javaScript = "(function watcher(ms){var start=new Date().getTime();var end = start;while(end<start+ms){end=new Date().getTime();};return 'complete';})(5000);";
log.trace("javaScript={}", javaScript);
jsResult = wait.until(ExpectedConditions.javaScriptThrowsNoExceptions(javaScript));
log.trace("jsResult={}", jsResult);

关于javascript - Java - 使用 Selenium 等待 JavaScript 事件(例如 onchange)完成,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53199159/

相关文章:

java - 无法定位元素 : error when executing code through POM, 通过单个 main() 程序执行时,相同的定位器工作正常

javascript - Jquery 脚本与按钮 div 冲突

java - Selenium try/catch 点击似乎需要很长时间?

javascript - 仅使用 JavaScript 的 CORS

java - Iterables.transform 没有迭代我的列表

java - 使用 .hasNext() 循环输入对

java - 如何防止模型映射器在 spring data jpa 中急切加载关联集合?

selenium - 使用 Proguard 混淆基于 Appium 的 jar 时重复类定义

javascript - 仅在 Safari 中 : ReferenceError Can't find variable

javascript - 通过亚马逊S3的间接ajax请求