1 回答
TA贡献1786条经验 获得超13个赞
您提到的有关 JS 调用 Java 的链接是针对特定应用程序的,旨在做到这一点。不是说这是不可能的(我根据类似的原理编写了 FF 插件),但它不适用于这种情况。它还需要特殊的应用程序支持(默认情况下,在浏览器中执行的 Javascript 是严重沙盒化的 - 它无法访问其自身范围之外的任何内容。单独调用其他应用程序是一个很大的问题。)。
您注入的脚本始终是客户端,它们仅在浏览器中执行,与 java 代码本身隔离。话虽如此,没有什么是不可能的。
想提一下 Selenium 库的两个有趣的功能,它们可以为您提供方便。
您多次提到了一个神奇的术语“异步 Javascript 执行” - 正如我所看到的,您正在实现自己的executeAsyncScript. Webdriver 确实提供了这种开箱即用的方法,几乎是为了您想要使用它的目的。
当您使用 时executeScript,它会在完成后立即返回 - 在您的情况下,它只会将您的代码注入您的侦听器,然后返回。使用executeAsyncScript您可以获得回调 - 正是您正在做的事情。调用时executeAsyncScript,默认callback方法会作为最后一个参数添加到您的代码中,该方法需要由您的 JS 代码调用才能返回。
一个简单的例子:
String script = "var callback = arguments[arguments.length - 1];" + //the last argument is the callback function
"var classToCall = 'SeleniumTest.IsPageReloaded';" + //the classname you want to return to call from Java in case of success)
"window.addEventListener('onload', callback(classToCall));";
//you can give any supported return value to the callback function. Here I assume that you want to call a static method. This is the class name that can be used later.
try {
JavascriptExecutor js = (JavascriptExecutor)driver;
//classToCall has the value we passed to the callback function
String classToCall = js.executeAsyncScript(script);
} catch (ScriptTimeoutException e) {
System.err.println("Uhhh... this failed I guess");
e.printStackTrace();
}
在调用回调之前 executeAsyncScript 不会返回 - 为避免无限挂起,您可以设置WebDriver.Timeouts.setScriptTimeout属性来控制它。如果脚本需要更长的时间,JavascriptExecutor 将抛出异常。返回后,您可以实例化返回的类,并像这样打印
Class clazz = Class.forName(classToCall); //it is only necessary if the classname is dynamic. If it is the same always, you can just go ahead with that.
((IsPageReloaded)clazz.newInstance()).JavascriptWorking();
当然,您也可以从 JS 中返回更复杂的数据结构,您也可以在其中指定方法名称,但在这里使用反射确实是题外话。
看看EventFiringWebdriver。这是一个有用的类,WebDriverEventListener用于创建自定义 Webdriver 包装器,在许多事件上带有钩子,允许您在单击之前/之后、页面加载之前/之后……以及在执行 javascript 之前/之后执行其他一些更重要的代码在网络驱动程序中。您可以利用它始终围绕 javascript 执行调用相同的代码 - 只需创建您自己的WebDriverEventListener.
你可以找到的JS执行更多的信息在这里,并在WebDriverEventListener这里。
添加回答
举报