web-dev-qa-db-ja.com

WebDriver executeAsyncScript vs executeScript

ExecuteAsyncScriptとexecuteScriptの違いは何ですか? window.onloadなどのイベントを使用するにはどうすればよいですか?私はこのようなものを試しました

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

しかし、もちろんうまくいきませんでした...だから誰かがそれがどのように機能するかを知っているなら、例を書いてください

34
vispart

executeScriptを使用します。提供された例:

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

アラートの詳細に関しては、既知の問題があります。詳細を取得できます こちら

ドキュメントの違いによると:

executeScript

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

インターフェイスからコピーされた説明:JavascriptExecutor現在選択されているフレームまたはウィンドウのコンテキストでJavaScriptを実行します。指定されたスクリプトフラグメントは、匿名関数の本体として実行されます。スクリプト内で、documentを使用して現在のドキュメントを参照します。グローバル変数は保持されますが、スクリプトの実行が終了すると、ローカル変数は使用できなくなります。スクリプトに戻り値がある場合(つまり、スクリプトにreturnステートメントが含まれている場合)、次の手順が実行されます:

  • HTML要素の場合、このメソッドはWebElementを返します
  • 小数の場合、Doubleが返されます
  • 10進数以外の場合、Longが返されます
  • ブール値の場合、ブール値が返されます
  • 他のすべての場合、文字列が返されます。
  • 配列の場合、上記の規則に従って各オブジェクトを含むリストを返します。ネストされたリストをサポートしています。
  • 値がnullであるか、nullが返される戻り値がない場合を除く

引数は、数値、ブール値、文字列、WebElement、または上記の任意の組み合わせのリストである必要があります。引数がこれらの基準を満たさない場合、例外がスローされます。引数は、関数が「Function.apply」を介して呼び出されたかのように、「arguments」マジック変数を介してJavaScriptで使用可能になります。

定義:インタフェースJavascriptExecutorのexecuteScriptパラメータ:script-実行するJavaScript args-スクリプトへの引数。空の場合があります戻り値:ブール、Long、String、List、またはWebElementのいずれか。またはヌル。

executeAsyncScript

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 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]");

例#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、または上記の任意の組み合わせのリストである必要があります。引数がこれらの基準を満たさない場合、例外がスローされます。引数は、「arguments」変数を介してJavaScriptで使用可能になります。

定義:インタフェースJavascriptExecutorのexecuteAsyncScriptパラメータ:script-実行するJavaScript。 args-スクリプトへの引数。空の場合があります。戻り値:ブール、Long、String、List、WebElement、またはnullのいずれか。

詳細なドキュメントは here です

24

simpleを維持し、correctを保持します。)

execteScriptexecuteAsyncScriptの関連する違いは次のとおりです。

executeAsyncScriptで呼び出された関数は、最後の引数として「完了コールバック」を取ります。これは、mustを呼び出して、スクリプトが完了したことを通知します実行中。

これにより、コールバックが使用されるときにのみ「終了」するコードで使用できます。 setTimeoutまたは非同期XHR。タイムアウト制限内に「完了コールバック」が呼び出されない場合、返されたプロミスは拒否されます。

#executeScriptで同期JavaScriptを実行するのとは異なり、[#executeAsyncScript]で実行されたスクリプトは、提供されたコールバックを呼び出して終了を明示的に通知する必要があります。このコールバックは、常に最後の引数として実行された関数に注入されます。

つまり、両方の関数は、完了するまでWebDriver制御フローをブロックします-executeScriptまたはexecuteAsyncScriptで 'doneコールバック'を呼び出すとき:名前の「async」は使用されるシグナルメカニズムを示し、JavaScriptコードが実際にWebDriverに対して非同期に実行されることを意味/意味するものではありません。

22
user2864740

これらの主な違いは、asyncで実行されるスクリプトは、提供されたコールバックを呼び出すことで終了したことを明示的に通知する必要があることです。このコールバックは、常に最後の引数として実行された関数に注入されます。

8
sphair

私はこの機能を理解するために多くの時間を費やし、ついにそれを手に入れました。次のコードは非常に役立ちます:

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

}
2
truetime
((JavascriptExecutor) driver).executeScript("alert('Hello');"); 

アラートが表示されます:

((JavascriptExecutor)ドライバー).executeAsyncScript()は、JSがWebサービス呼び出しなどで実行するのに時間がかかる場合に使用されます。

window.onloadは、ページが完全にロードされたときにJSが実行されるようにします。

2
Ishank