2012-11-19 13 views
27

Qual è la differenza tra executeAsyncScript ed executeScript? Come posso usare eventi come window.onload? Ho provato qualcosa di simileWebDriver executeAsyncScript vs executeScript

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

Ma ovviamente non ha funzionato ... Quindi, se qualcuno sa come funziona si prega di scrivere un esempio

+6

La differenza principale tra questi è che gli script eseguiti con async devono segnalare esplicitamente che sono stati terminati invocando il callback fornito. Questo callback è sempre iniettato nella funzione eseguita come ultimo argomento. – sphair

+0

Grazie per il tuo feedback! – vispart

+0

@sphair dovresti aver inviato una risposta, la sua concisa e corretta, setacciare alcuni dei rifiuti in basso era difficile. – Pykler

risposta

21

io uso executeScript. Esempio fornito:

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

Per quanto riguarda i dettagli sugli avvisi, è noto il problema. è possibile ottenere informazioni here

In conformità con la differenza documentazione è:

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.

documentazione dettagliata è here

+5

La "descrizione" sopra (copiata dalla documentazione dell'interfaccia) E la documentazione collegata non sono aggiornate. Un elenco di "oggetti" verrà restituito come Elenco >. Dove, ogni chiave è una proprietà dell'oggetto. Non so come ottenere dettagli di questo, ma mi sono appena bruciato dopo aver letto questo, quindi ho pensato di contribuire. – dmansfield

+0

@ eugene.polschikov Sto riferendo il tuo esempio 3 e quando eseguo la linea in console sto ricevendo 'Uncaught ReferenceError: argomenti non sono definiti allo : 1: 16'. Sono completamente nuovo per JS e il tuo aiuto è apprezzato. –

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

mostrerà l'avviso:

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

window.onload si assicura la JS viene eseguito quando la pagina viene caricata completamente.

5

La differenza principale tra questi è che gli script eseguiti con async devono segnalare esplicitamente che sono stati terminati invocando il callback fornito. Questo callback è sempre iniettato nella funzione eseguita come ultimo argomento.

+0

Perché la scarsa documentazione non lo dice? La documentazione dice solo: "Esegue JavaScript in modo asincrono nel contesto del frame o della finestra attualmente selezionata." – Elmue

13

(. Tenendolo semplice, e corretta)

La differenza rilevante tra execteScript e executeAsyncScript è questa:

La funzione invocato con executeAsyncScript prende un 'callback fatto' come ultimo argomento , che deve chiamare per segnalare che lo script è stato eseguito.

Ciò consente di utilizzarlo con un codice che "termina" solo quando viene utilizzata una richiamata, ad es. setTimeout o XHR asincrono. Se il 'callback fatto' non viene chiamato entro i limiti di timeout, la promessa restituita verrà respinta.

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..

Cioè, entrambe le funzioni bloccare il flusso del controllo WebDriver fino al compimento - o scappare alla fine del codice per executeScript o quando si chiama il 'callback fatto' con executeAsyncScript: "async" in il nome indica il meccanismo del segnale utilizzato e non significa/implica che il codice JavaScript sia effettivamente eseguito in modo asincrono rispetto al WebDriver.

1

Ho usato molto tempo per sottolineare questa funzione e finalmente l'ho capito. il seguente codice aiuterà molto:

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

}