2014-04-14 17 views
7

Sto testando un'API JavaScript utilizzando Java/Selenium.Il selenio attende il completamento di JavaScript?

ho questi comandi sul lato Java,

executor.executeScript("setName('Hello');"); 
// Thread.sleep(2000); 
String output = (String)executor.executeScript("return getName()"); 
assertEquals(output, "Hello"); 

In JavaScript lato, si tratta di una funzione asincrona, quindi si suppone di prendere un po 'di tempo e impostare la variabile.

function setName(msg) { 
    // simulate async call 
    setName(function(){name = msg;},1000); 
} 

ho bisogno di aspettare per questa funzione asincrona per completare prima di passare alla riga successiva in Java, in cui viene eseguito il assertEquals().

C'è un modo per farlo senza usare Thread.sleep() sul lato Java.

Grazie

risposta

2

Si può facilmente chiedere al selenio di attendere fino a quando una condizione particolare è vera; esattamente quello che hai, un alternativa sarebbe:

new FluentWait<JavascriptExecutor>(executor) { 
    protected RuntimeException timeoutException(
     String message, Throwable lastException) { 
    Assert.fail("name was never set"); 
    } 
}.withTimeout(10, SECONDS) 
.until(new Predicate<JavascriptExecutor>() { 
    public boolean apply(JavascriptExecutor e) { 
    return (Boolean)executor.executeScript("return ('Hello' === getName());"); 
    } 
}); 

Tuttavia, allora il gioco è fondamentalmente testare esattamente quello che hai appena codificata, e che ha lo svantaggio che se name sono stati fissati prima hai chiamato setName, si rifugio' t necessariamente aspettare setName per finire. Una cosa che ho fatto in passato per cose simili è questa:

Nella mia libreria di test (che sostituisce reale chiamate asincrone con setTimeout spessori), ho questo:

window._junit_testid_ = '*none*'; 
window._junit_async_calls_ = {}; 
function _setJunitTestid_(testId) { 
    window._junit_testid_ = testId; 
} 
function _setTimeout_(cont, timeout) { 
    var callId = Math.random().toString(36).substr(2); 
    var testId = window._junit_testid_; 
    window._junit_async_calls_[testId] |= {}; 
    window._junit_async_calls_[testId][callId] = 1; 
    window.setTimeout(function(){ 
    cont(); 
    delete(window._junit_async_calls_[testId][callId]); 
    }, timeout); 
} 
function _isTestDone_(testId) { 
    if (window._junit_async_calls_[testId]) { 
    var thing = window._junit_async_calls_[testId]; 
    for (var prop in thing) { 
     if (thing.hasOwnProperty(prop)) return false; 
    } 
    delete(window._junit_async_calls_[testId]); 
    } 
    return true; 
} 

Nel resto della mia libreria, io uso _setTimeout_ invece di window.setTimeout ogni volta che ho bisogno di impostare qualcosa per accadere in seguito. Poi, nel mio test selenio, faccio qualcosa di simile:

// First, this routine is in a library somewhere 
public void waitForTest(JavascriptExecutor executor, String testId) { 
    new FluentWait<JavascriptExecutor>(executor) { 
    protected RuntimeException timeoutException(
     String message, Throwable lastException) { 
     Assert.fail(testId + " did not finish async calls"); 
    } 
    }.withTimeout(10, SECONDS) 
    .until(new Predicate<JavascriptExecutor>() { 
    public boolean apply(JavascriptExecutor e) { 
     return (Boolean)executor.executeScript(
      "_isTestDone_('" + testId + "');"); 
    } 
    }); 
} 

// Inside an actual test: 
@Test public void serverPingTest() { 
    // Do stuff to grab my WebDriver instance 
    // Do this before any interaction with the app 
    driver.executeScript("_setJunitTestid_('MainAppTest.serverPingTest');"); 
    // Do other stuff including things that fire off what would be async calls 
    // but now call stuff in my testing library instead. 
    // ... 
    // Now I need to wait for all the async stuff to finish: 
    waitForTest(driver, "MainAppTest.serverPingTest"); 
    // Now query stuff about the app, assert things if needed 
} 

Si noti che è possibile chiamare waitForTest più volte, se necessario, in qualsiasi momento è necessario che prova a mettere in pausa fino a quando tutte le operazioni asincrone sono finiti.

0

dubito selenio fa. Aspetta solo che la pagina sia completamente caricata, ma non lo script per finire. Si potrebbe desiderare di definire il proprio "test step" per attendere il risultato (e il polling costante del contenuto della pagina/stato della scrittura), ma assicurarsi di impostare un timeout ragionevole per non mettere male i test per errore di script.

Problemi correlati