一组逻辑相关的 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 ofFluentWait
) instead ofFluentWait
, unless you have a very specific requirement. E.g.,WebDriverWait
ignoresNotFoundException
(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.javaScriptThrowsNoExceptions
和 ExpectedConditions.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/