当我的Javascript回调(在Selenium中生成)返回时写入Java控制台
我已经学习了如何创建Javascript回调函数,并且我对“函数编程”有了基本的理解,因为它看起来很简单。然而,我对javascript和它的语法还不熟悉,在我的IntelliJ IDE中,我找不到一个好的方法来测试所说的语法 你在干什么? 我正在创建一个基于Selenium的工具来点击一个webelement,等待它重新加载页面,变得陈旧或等待超时。我这样做的原因是将webelements分为三类:导致页面重新加载、变得陈旧、不变。为此,我使用Java附带的JavascriptExecutor制作了一个简单的javascript脚本。我的大部分代码都是用java编写的,这是我所精通的语言。我想学习如何将javascript与java结合使用,以实现我对网页的要求 好的,但具体问题是什么? 我有一个javascript回调函数:当我的Javascript回调(在Selenium中生成)返回时写入Java控制台,javascript,java,selenium,asynchronous,callback,Javascript,Java,Selenium,Asynchronous,Callback,我已经学习了如何创建Javascript回调函数,并且我对“函数编程”有了基本的理解,因为它看起来很简单。然而,我对javascript和它的语法还不熟悉,在我的IntelliJ IDE中,我找不到一个好的方法来测试所说的语法 你在干什么? 我正在创建一个基于Selenium的工具来点击一个webelement,等待它重新加载页面,变得陈旧或等待超时。我这样做的原因是将webelements分为三类:导致页面重新加载、变得陈旧、不变。为此,我使用Java附带的JavascriptExecutor
function test(callback) {callback();}
function Return() {SeleniumTest.isPageReloaded.JavascriptWorking}
window.addEventListener('onload', test(Return));
在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是我的包,IsPagerLoaded是当前类,JavascriptWorking是该类中的静态方法。该静态方法如下所示:
public static void JavascriptWorking(){
System.out.println("Javascript ran here");
}
这意味着它是一种从javascript到java代码的简单方式。我之所以这样做是因为我读到:
但后来我意识到这是行不通的,于是我深入挖掘。我读到Javascript和Java是按服务器和客户端分开的,我从这个问题中获得了一些见解:
但是,我不能100%确定这是否准确,因为我正在执行的Javascript不是来自我正在测试的网页,而是我自己在java代码中作为字符串创建的。此外,我仍然很困惑这个问题的答案是否适用于我。只有一个,它基本上只是说,‘安装一些东西,因为java是客户端,javascript是服务器端’。我(有点)理解这些术语的含义,但我不确定我在我的类中制作的javascript是否会被视为“服务器端”,事实上似乎不是这样。我需要澄清的是:我在java代码中运行/创建的javascript实际上是服务器端的吗?
B:如果是的话,那么有人能给我一个关于如何从服务器调用java代码的基本概述吗?这需要权限吗?我假设我必须与上述服务器通信,那么这是否意味着我使用GET和POSt请求?
C:如果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代码链接到java代码。例如,如果我插入了正确的代码来调用我的静态方法:
SeleniumTest.IsPageReloaded.JavascriptWorking
(看起来也是这样):
然后我想在我的java控制台上看到“Javascript在这里运行”。正在使用的驱动程序是可互换的,我只是先使用chrome,因为它速度快。这只需要一个封闭的主类,它((应该))是可运行的,但没有承诺
目的是在java中获得一些东西,然后我可以将其用作标志,以知道异步javascript是在java中完成的,并且我可以继续执行程序。我可以得到异步javascript部分,我理解它,我只需要一个指向java代码的链接
可能的解决方案
有人告诉我,为java代码提供标志的常用方法是使用javascript在页面上创建一个特定的webelement,并用java对其进行测试(因此是链接)。我不想添加到我测试的网页中,因为我想在不实际编辑/更改它们的情况下测试它们。我通常对其他简单的解决方案持开放态度,但我最需要的是澄清整个客户端服务器端问题,因为它特定于我的设置(Selenium java->javascript->java),其中大多数问题只涉及(javascript->java)反之亦然。您提到的关于JS调用Java的链接是针对一个特定的应用程序的,就是为了这样做。并不是说这是不可能的(我基于类似的原理编写了FF插件),但它不适用于这种情况。它还需要特殊的应用程序支持(默认情况下,浏览器中执行的Javascript被严重沙盒化——它无法访问自己范围之外的任何内容。单独调用其他应用程序是一个很大的障碍) 注入的脚本总是客户端的,它们只在浏览器中执行,浏览器与java代码本身是隔离的。说到这里,没有什么是不可能的 我想提到Selenium库的两个有趣的特性,它们可以方便您使用
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将抛出异常。O
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();
}
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();