Javascript WebDriver executeAsyncScript 与 executeScript

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/13452822/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-24 12:08:08  来源:igfitidea点击:

WebDriver executeAsyncScript vs executeScript

javascripttestingseleniumwebdriverqa

提问by vispart

What is the difference between executeAsyncScript and executeScript? How can i use event such as window.onload? I tried something like this

executeAsyncScript 和 executeScript 有什么区别?我如何使用诸如 window.onload 之类的事件?我试过这样的事情

((JavascriptExecutor) driver).executeAsyncScript("window.onload = function() {alert('Hello')}"); 

But of course it did not work... So if anyone knows how it works please write an example

但当然它不起作用......所以如果有人知道它是如何工作的,请写一个例子

回答by user2864740

(Keeping it simple, and correct.)

(保持简单正确。)

The relevant difference between execteScriptand executeAsyncScriptis this:

execteScript和之间的相关区别executeAsyncScript是:

The function invoked with executeAsyncScripttakes a 'done callback' as the last argument, which mustbe called to signal that the script is done executing.

调用的函数executeAsyncScript将“完成回调”作为最后一个参数,必须调用该参数以表示脚本已完成执行。

This allows it to be used with code that only 'finishes' when a callback is used - eg. setTimeout or asynchronous XHR. If the 'done callback' is not called within the timeout limits the returned promise will be rejected.

这允许它与仅在使用回调时“完成”的代码一起使用 - 例如。setTimeout 或异步 XHR。如果在超时限制内未调用“完成回调”,则返回的承诺将被拒绝。

Per the webdriver.WebDriver.executeAsyncScriptdocumentation:

根据webdriver.WebDriver.executeAsyncScript文档:

Unlike executing synchronous JavaScript with #executeScript, scripts executed with [#executeAsyncScript] must explicitly signal they are finished by invoking the provided callback. This callback will always be injected into the executed function as the last argument..

与使用 #executeScript 执行同步 JavaScript 不同,使用 [#executeAsyncScript] 执行的脚本必须通过调用提供的回调显式表示它们已完成。此回调将始终作为最后一个参数注入到执行的函数中。

That is, both functions block the WebDriver control flowuntil they complete - either running off the end of the code for executeScriptor when calling the 'done callback' with executeAsyncScript: "async" in the name signifies the signal mechanism used and does not mean/imply that the JavaScript code is actually executed asynchronously with respect to the WebDriver.

也就是说,这两个函数都会阻塞 WebDriver 控制流,直到它们完成 - 要么在代码末尾运行,executeScript要么在调用“完成回调”时使用executeAsyncScript:名称中的“async”表示使用的信号机制,并不意味着/暗示JavaScript 代码实际上是相对于 WebDriver 异步执行的。

回答by eugene.polschikov

I use executeScript. Example provided:

我用executeScript. 提供的示例:

String cssSelector="...blablabla...";
JavascriptExecutor js = (JavascriptExecutor) driver;
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("document.getElementById(\'"+cssSelector +"\').click();");
js.executeScript(stringBuilder.toString());

Concerning details on alerts there is known issue. you can get details here

关于警报的详细信息,存在已知问题。你可以在这里获得详细信息

In accordance with documentation difference is:

按照文档区别是:

executeScript

public java.lang.Object executeScript(java.lang.String script,
                             java.lang.Object... args)

Description copied from interface: JavascriptExecutor Executes JavaScript in the context of the currently selected frame or window. The script fragment provided will be executed as the body of an anonymous function. Within the script, use document to refer to the current document. Note that local variables will not be available once the script has finished executing, though global variables will persist. If the script has a return value (i.e. if the script contains a return statement), then the following steps will be taken:

  • For an HTML element, this method returns a WebElement
  • For a decimal, a Double is returned
  • For a non-decimal number, a Long is returned
  • For a boolean, a Boolean is returned
  • For all other cases, a String is returned.
  • For an array, return a List with each object following the rules above. We support nested lists.
  • Unless the value is null or there is no return value, in which null is returned

Arguments must be a number, a boolean, a String, WebElement, or a List of any combination of the above. An exception will be thrown if the arguments do not meet these criteria. The arguments will be made available to the JavaScript via the "arguments" magic variable, as if the function were called via "Function.apply"

Specified by: executeScript in interface JavascriptExecutor Parameters: script - The JavaScript to execute args - The arguments to the script. May be empty Returns: One of Boolean, Long, String, List or WebElement. Or null.

executeAsyncScript

public java.lang.Object executeAsyncScript(java.lang.String script,
                                  java.lang.Object... args)

Description copied from interface: JavascriptExecutor Execute an asynchronous piece of JavaScript in the context of the currently selected frame or window. Unlike executing synchronous JavaScript, scripts executed with this method must explicitly signal they are finished by invoking the provided callback. This callback is always injected into the executed function as the last argument.The first argument passed to the callback function will be used as the script's result. This value will be handled in the same way as the synchronous case.

Example #1: Performing a sleep in the browser under test.

 long start = System.currentTimeMillis();
   ((JavascriptExecutor) driver).executeAsyncScript(
       "window.setTimeout(arguments[arguments.length - 1], 500);");
   System.out.println(
       "Elapsed time: " + (System.currentTimeMillis() - start));  

Example #2: Synchronizing a test with an AJAX application:

 WebElement composeButton = driver.findElement(By.id("compose-button"));
   composeButton.click();
   ((JavascriptExecutor) driver).executeAsyncScript(
       "var callback = arguments[arguments.length - 1];" +
       "mailClient.getComposeWindowWidget().onload(callback);");
   driver.switchTo().frame("composeWidget");
   driver.findElement(By.id("to")).sendKeys("[email protected]");

Example #3: Injecting a XMLHttpRequest and waiting for the result:

 Object response = ((JavascriptExecutor) driver).executeAsyncScript(
       "var callback = arguments[arguments.length - 1];" +
       "var xhr = new XMLHttpRequest();" +
       "xhr.open('GET', '/resource/data.json', true);" +
       "xhr.onreadystatechange = function() {" +
       "  if (xhr.readyState == 4) {" +
       "    callback(xhr.responseText);" +
       "  }" +
       "}" +
       "xhr.send();");
   JSONObject json = new JSONObject((String) response);
   assertEquals("cheese", json.getString("food"));

Script arguments must be a number, a boolean, a String, WebElement, or a List of any combination of the above. An exception will be thrown if the arguments do not meet these criteria. The arguments will be made available to the JavaScript via the "arguments" variable.

Specified by: executeAsyncScript in interface JavascriptExecutor Parameters: script - The JavaScript to execute. args - The arguments to the script. May be empty. Returns: One of Boolean, Long, String, List, WebElement, or null.

执行脚本

public java.lang.Object executeScript(java.lang.String script,
                             java.lang.Object... args)

从接口复制的描述:JavascriptExecutor 在当前选定的框架或窗口的上下文中执行 JavaScript。提供的脚本片段将作为匿名函数的主体执行。在脚本中,使用 document 来引用当前文档。请注意,一旦脚本完成执行,局部变量将不可用,但全局变量将持续存在。如果脚本有返回值(即如果脚本包含返回语句),则将采取以下步骤:

  • 对于 HTML 元素,此方法返回一个 WebElement
  • 对于小数,返回一个 Double
  • 对于非十进制数,返回一个 Long
  • 对于布尔值,返回一个布尔值
  • 对于所有其他情况,返回一个字符串。
  • 对于数组,按照上述规则返回包含每个对象的 List。我们支持嵌套列表。
  • 除非值为null或者没有返回值,其中返回null

参数必须是数字、布尔值、字符串、WebElement 或上述任意组合的列表。如果参数不满足这些条件,则会抛出异常。参数将通过“arguments”魔法变量提供给 JavaScript,就像通过“Function.apply”调用函数一样

指定者:接口 JavascriptExecutor 中的 executeScript 参数: script - 要执行的 JavaScript args - 脚本的参数。可能为空返回:Boolean、Long、String、List 或 WebElement 之一。或为空。

执行异步脚本

public java.lang.Object executeAsyncScript(java.lang.String script,
                                  java.lang.Object... args)

从接口复制的描述:JavascriptExecutor 在当前选定的框架或窗口的上下文中执行一段异步 JavaScript。与执行同步 JavaScript 不同,使用此方法执行的脚本必须通过调用提供的回调显式表示它们已完成。这个回调总是作为最后一个参数注入到执行的函数中。传递给回调函数的第一个参数将用作脚本的结果。该值的处理方式与同步情况相同。

示例 #1:在被测浏览器中执行睡眠。

 long start = System.currentTimeMillis();
   ((JavascriptExecutor) driver).executeAsyncScript(
       "window.setTimeout(arguments[arguments.length - 1], 500);");
   System.out.println(
       "Elapsed time: " + (System.currentTimeMillis() - start));  

示例 2:将测试与 AJAX 应用程序同步:

 WebElement composeButton = driver.findElement(By.id("compose-button"));
   composeButton.click();
   ((JavascriptExecutor) driver).executeAsyncScript(
       "var callback = arguments[arguments.length - 1];" +
       "mailClient.getComposeWindowWidget().onload(callback);");
   driver.switchTo().frame("composeWidget");
   driver.findElement(By.id("to")).sendKeys("[email protected]");

示例 #3:注入 XMLHttpRequest 并等待结果:

 Object response = ((JavascriptExecutor) driver).executeAsyncScript(
       "var callback = arguments[arguments.length - 1];" +
       "var xhr = new XMLHttpRequest();" +
       "xhr.open('GET', '/resource/data.json', true);" +
       "xhr.onreadystatechange = function() {" +
       "  if (xhr.readyState == 4) {" +
       "    callback(xhr.responseText);" +
       "  }" +
       "}" +
       "xhr.send();");
   JSONObject json = new JSONObject((String) response);
   assertEquals("cheese", json.getString("food"));

脚本参数必须是数字、布尔值、字符串、WebElement 或上述任意组合的列表。如果参数不满足这些条件,则会抛出异常。参数将通过“参数”变量提供给 JavaScript。

指定者: JavascriptExecutor 接口中的 executeAsyncScript 参数: script - 要执行的 JavaScript。args - 脚本的参数。可能是空的。返回: Boolean、Long、String、List、WebElement 或 null 之一。

Detailed documentation is here

详细文档在这里

回答by sphair

The main difference between those are that scripts executed with async must explicitly signal they are finished by invoking the provided callback. This callback is always injected into the executed function as the last argument.

它们之间的主要区别在于,使用 async 执行的脚本必须通过调用提供的回调显式表示它们已完成。这个回调总是作为最后一个参数注入到执行的函数中。

回答by Ishank

((JavascriptExecutor) driver).executeScript("alert('Hello');"); 

will show the alert:

将显示警报:

((JavascriptExecutor) driver).executeAsyncScript() is used when the JS takes time to execute e.g.in a Web Service call.

((JavascriptExecutor) driver).executeAsyncScript() 当 JS 需要时间来执行 egin 一个 Web 服务调用时使用。

window.onloadmakes sure the JS is executed when the page is loaded completely.

window.onload确保在页面完全加载时执行 JS。

回答by truetime

I used lots of time to undertand this function and finally I got it. follwing code will help a lot:

我花了很多时间来理解这个功能,最后我明白了。以下代码将有很大帮助:

/**
 * executeAsyncScript document mentioned callback is a browser intrinsic function for returning deferred value (e.g 123 in example) from
 * js environment to Java environment
 * 
 */
@Test
public void testAsyncScript() {
    webDriver.manage().timeouts().setScriptTimeout(1, TimeUnit.SECONDS);
    Integer a = 23;
    TestUtil.elapse("first", () -> {
        Object value = getJsExecutor().executeAsyncScript("window.setTimeout(arguments[arguments.length - 1](123), 500);", a);
        // following code should be executed after 500ms timeout
        System.out.println("a is " + a); // a has nothing to do with the documented "callback"
        assertEquals(123, value);
    });

}