繁体   English   中英

WebDriver executeAsyncScript 与 executeScript

[英]WebDriver executeAsyncScript vs executeScript

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

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

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

(保持简单正确。)

execteScriptexecuteAsyncScript之间的相关区别是:

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

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

根据webdriver.WebDriver.executeAsyncScript文档:

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

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

我使用executeScript 提供的示例:

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

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

按照文档区别是:

执行脚本

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("bog@example.com");

示例 #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 之一。

详细文档在这里

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

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

将显示警报:

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

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

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

/**
 * 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);
    });

}

这个简单的异步脚本监听 DOM 上点击的元素并通过回调解析executeAsyncScript

  var clicked_element = await driver.executeAsyncScript('var callback=arguments[arguments.length - 1]; window.document.addEventListener("click", function(e){ var element = event.srcElement ||event.target; callback(element); });'); 

您可以执行以下操作:

JavascriptExecutor js=(JavascriptExecutor)driver;
String javascript="window.location='https://google.com';window.onload=alert('hello'); var callback=arguments[arguments.length-1]; callback();";
        js.executeAsyncScript(javascript);
    

正如其他人所说,executeAsyncScript() 使用一种称为回调的信号机制来通知主函数/代码,executeAsyncScript 中的 javascript 已经完成。 回调被称为参数[arguments.length-1]。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM