首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >当我的Javascript回调(在Selenium中生成)返回时,写入Java控制台

当我的Javascript回调(在Selenium中生成)返回时,写入Java控制台
EN

Stack Overflow用户
提问于 2018-09-26 23:31:23
回答 1查看 1.3K关注 0票数 1

我已经学会了如何创建Javascript回调函数,并且我对“函数式编程”有了基本的了解,因为它看起来很简单。然而,我是一个新的javascript和它的语法,我找不到一个好的方法来测试在我的IntelliJ集成开发环境中所说的语法。

你在做什么?

我正在创建一个基于Selenium的工具,用于单击for元素,等待它重新加载页面,变得陈旧或等待超时。我这样做的原因是将webelements分为三类:导致页面重新加载,变得陈旧,不变。为此,我用Java附带的JavascriptExecutor创建了一个简单的javascript脚本。我的大部分代码都是用java编写的,这也是我精通的语言。我想学习如何使用javascript和java在网页上做我想做的事情。

好的,但是问题具体是什么呢?

我有一个javascript回调函数:

代码语言:javascript
复制
function test(callback) {callback();} 
function Return() {SeleniumTest.isPageReloaded.JavascriptWorking} 
window.addEventListener('onload', test(Return));

它在Javascript执行器中执行,如下所示:

代码语言:javascript
复制
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是该类中的静态方法。该静态方法如下所示:

代码语言:javascript
复制
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是由服务器和客户端分开的,我从这个问题中获得了一些见解:

calling java methods in javascript code

然而,我不能100%确定这是否符合我的情况,因为我正在执行的Javascript不是来自我正在测试的网页,而是我自己在java代码中以字符串形式编写的。此外,我仍然对这个问题的答案是否真的适用于我感到非常困惑。只有一个,基本上就是说,‘安装一些东西,因为java是客户端的,javascript是服务器端的’。我(有点)理解这些术语的含义,但我不确定我在我的类中制作的javascript是否会被认为是“服务器端”,事实上它似乎不是这样的。我需要澄清的是A:我在java代码中运行/创建的javascript实际上是服务器端的吗?B:如果是,那么谁能给我一个基本的概要,告诉我如何从服务器调用java代码?这需要权限吗?我假设我必须与所述服务器通信,那么这是否意味着我使用GET和POSt请求?C:如果Javascript不是服务器端的,那么它一定是客户端的,我应该可以很容易地调用它,对吧?我该怎么做呢?

告诉我们你到底想要什么

我希望能够运行:

代码语言:javascript
复制
System.setProperty("webdriver.chrome.driver", 
"C:\\chromedriver_win32\\chromedriver.exe");
WebDriver driver = new ChromeDriver();
String script = "function test(callback) {callback();}" +
                    "function Return()" + 
"{//insert callback code here}" +
                    "window.addEventListener('onload', test(Return));";
JavascriptExecutor js = (JavascriptExecutor)driver;
js.executeScript(script);

并运行静态java方法、打印到控制台或其他将javascript代码链接到javascript代码的方法。例如,如果我插入了正确的代码来调用我的静态方法:

SeleniumTest.IsPageReloaded.JavascriptWorking

(看起来又像这样):

代码语言:javascript
复制
public static void JavascriptWorking(){
    System.out.println("Javascript ran here");
}

然后我想在我的java控制台上看到"Javascript ran“。使用的驱动程序是interchangebale,我首先使用的是chrome,因为它速度很快。所有这一切需要的是一个封闭的主类,它((应该))是可运行的,但没有承诺。

目的是在java中获得一些东西,然后我可以将其用作一个标志,以知道我的异步javascript是在java中完成的,并且我可以继续执行程序。我可以得到异步javascript部分,我理解它,我只需要一个链接回到我的java代码。

可能的解决方案

有人告诉我,为java代码提供标志的常见方法是使用javascript在页面上创建一个特定的webelement,然后在java中对其进行测试(因此有了链接)。我不想添加到我测试的网页中,因为我想测试它们,而不是实际编辑/更改它们。我通常对其他简单的解决方案持开放态度,但我最需要的是澄清整个客户端服务器端问题,因为它特定于我的设置(Selenium java、->、javascript、-> ),其中大多数问题只涵盖(javascript、->、java),反之亦然。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-09-27 02:41:13

您提到的关于JS调用Java的链接是针对特定应用程序的,该应用程序就是这样做的。并不是说这是不可能的(我写的FF插件基于类似的原则),但它不适用于这种情况。它还需要特殊的应用程序支持(默认情况下,在浏览器中执行的Javascript是严重沙箱的-它不能访问自己作用域之外的任何东西。单独调用其他应用程序是一个很大的错误。)

您注入的脚本始终是客户端的,它们只在浏览器中执行,这与java代码本身是隔离的。如上所述,没有什么是不可能的。

我想提一下Selenium库的两个有趣的特性,它们可以为您提供方便。

  1. 你多次提到一个神奇的术语“异步Javascript执行”--正如我所看到的,你正在实现自己版本的executeAsyncScript。Webdriver确实提供了这种开箱即用的方法,很大程度上是为了您想要使用它的目的。

当您使用executeScript时,它几乎会在完成后立即返回-在本例中,它只是将您的代码注入您的侦听器,然后返回。使用executeAsyncScript,你可以得到一个回调--就是你正在做的事情。在调用executeAsyncScript时,默认的callback方法将作为最后一个参数添加到代码中,JS代码需要调用该方法才能返回该方法。

一个简单的例子:

代码语言:javascript
复制
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将抛出异常。返回后,您可以实例化返回的类,并像这样打印

代码语言:javascript
复制
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返回更复杂的数据结构,在JS中还可以指定方法名称,但在这里使用反射确实是离题的。

  1. 看看EventFiringWebdriver。这是一个有用的类,它利用WebDriverEventListener创建自定义的Webdriver包装器,在许多事件上有钩子,允许您在单击之前/之后,在页面加载之前/之后执行自定义代码...除此之外,还有一些更重要的在webdriver中执行javascript之前/之后的代码。您可以利用这一点在javascript执行过程中始终调用相同的代码-只需创建您自己的WebDriverEventListener.

您可以在js executor here和WebDriverEventListener here上找到更多信息。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/52521395

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档