Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby-on-rails-4/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
当我的Javascript回调(在Selenium中生成)返回时写入Java控制台_Javascript_Java_Selenium_Asynchronous_Callback - Fatal编程技术网

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

当我的Javascript回调(在Selenium中生成)返回时写入Java控制台,javascript,java,selenium,asynchronous,callback,Javascript,Java,Selenium,Asynchronous,Callback,我已经学习了如何创建Javascript回调函数,并且我对“函数编程”有了基本的理解,因为它看起来很简单。然而,我对javascript和它的语法还不熟悉,在我的IntelliJ IDE中,我找不到一个好的方法来测试所说的语法 你在干什么? 我正在创建一个基于Selenium的工具来点击一个webelement,等待它重新加载页面,变得陈旧或等待超时。我这样做的原因是将webelements分为三类:导致页面重新加载、变得陈旧、不变。为此,我使用Java附带的JavascriptExecutor

我已经学习了如何创建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执行器中执行,如下所示:

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库的两个有趣的特性,它们可以方便您使用

  • 您多次提到一个神奇的术语“异步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将抛出异常。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();