为了账号安全,请及时绑定邮箱和手机立即绑定

当我的 Javascript 回调(在 Selenium 中制作)返回时写入 Java 控制台

当我的 Javascript 回调(在 Selenium 中制作)返回时写入 Java 控制台

RISEBY 2021-10-13 13:51:53
我已经学会了如何创建 Javascript 回调函数,并且我对“函数式编程”有基本的了解,因为它看起来很简单。然而,我是 javascript 的新手,它的语法我找不到在我的 IntelliJ IDE 中测试所述语法的好方法。你在做什么?我正在创建一个基于 Selenium 的工具来点击一个 webelement,等待它重新加载页面,变得陈旧或等待超时。我这样做的原因是将 webelements 分为三类:导致页面重新加载,变得陈旧,不会改变。为此,我使用 Java 附带的 JavascriptExecutor 制作了一个简单的 javascript 脚本。我的大部分代码都是用 java 编写的,这是我精通的语言。我想学习如何使用 javascript 和 java 来做我想要用网页做的事情。好的,但具体是什么问题?我有一个 javascript 回调函数:function test(callback) {callback();} function Return() {SeleniumTest.isPageReloaded.JavascriptWorking} window.addEventListener('onload', test(Return));它在 Javascript Executor 中执行,如下所示:System.setProperty("webdriver.chrome.driver", "C:\\chromedriver_win32\\chromedriver.exe");WebDriver driver = new ChromeDriver();String script = "function test(callback) {callback();}" +                    "function Return()" +                     "{SeleniumTest.isPageReloaded.JavascriptWorking}" +                    "window.addEventListener('onload', test(Return));";JavascriptExecutor js = (JavascriptExecutor)driver;js.executeScript(script);这基本上是之前的 Javascript 脚本,作为字符串执行。如您所见,我正在尝试调用 Java 类。SeleniumTest 是我的包,isPageReloaded 是当前类,JavascriptWorking 是该类中的静态方法。该静态方法如下所示:public static void JavascriptWorking(){    System.out.println("Javascript ran here");}它意味着是一种从 javascript 获取某些内容到我的 java 代码的简单方法。我以这种方式尝试的原因是因为我阅读了以下内容:https://documentation.progress.com/output/ua/OpenEdge_latest/index.html#page/bpm-appdev/invoking-java-methods-in-javascript.html但后来我意识到它行不通,我挖得更深。我读到 Javascript 和 Java 是由服务器和客户端分开的,我从这个问题中获得了一些见解:在javascript代码中调用java方法但是,我不是 100% 确定这对我的情况是准确的,因为我正在执行的 Javascript 不是来自我正在测试的网页,而是我自己在 java 代码中将其作为字符串制作的。此外,我仍然对这个问题的答案是否真的适用于我感到非常困惑。只有一个,它基本上只是说,“安装一些东西,因为 java 是客户端而 javascript 是服务器端”。我(有点)理解这些术语的含义,但我不确定我在课堂上制作的 javascript 是否会被视为“服务器端”,实际上似乎并非如此。我需要的是澄清 A: 我在我的 Java 代码中运行/创建的 javascript 实际上是服务器端吗?乙:如果是,那么有人可以给我一个关于如何从服务器调用 java 代码的基本概要吗?这需要权限吗?我假设我必须与所述服务器通信,这是否意味着我使用 GET 和 POST 请求?C:如果 Javascript 不是服务器端,那么它必须是客户端,我应该可以很容易地调用它,对吗?我该怎么做呢?
查看完整描述

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这里。


查看完整回答
反对 回复 2021-10-13
  • 1 回答
  • 0 关注
  • 276 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信