2014-04-14 13 views
7

Ich teste eine JavaScript API mit Java/Selenium.Wartet Selenium auf JavaScript?

ich diese Befehle auf Java-Seite,

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

In JavaScript Seite, ist dies eine Asynchron-Funktion, so wird angenommen, einige Zeit in Anspruch nehmen und die Variable gesetzt.

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

Ich muss warten, diese Asynchron-Funktion in die nächste Zeile in Java, bevor er abgeschlossen ist, wo die assertEquals() ausgeführt wird.

Gibt es eine Möglichkeit, dies ohne Verwendung von Thread.sleep() auf der Java-Seite zu erreichen.

Dank

Antwort

2

Sie können Selen leicht bitten zu warten, bis eine bestimmte Bedingung erfüllt ist; in genau das, was Sie haben, wäre eine Alternative zu sein:

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());"); 
    } 
}); 

aber dann sind Testen Sie im Grunde genau das, was Sie gerade codiert, und das hat den Nachteil, dass, wenn name eingestellt wurden, bevor Sie setName genannt, Sie haven‘ t unbedingt warten setName zu beenden. Eine Sache, die ich für ähnliche Dinge in der Vergangenheit getan habe, ist dies:

In meinen Tests Bibliothek (die echte async ersetzt Anrufe mit setTimeout Unterlegscheiben), ich habe dies:

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; 
} 

In dem Rest meines Bibliothek verwende ich _setTimeout_ anstelle von window.setTimeout, wenn ich etwas später einrichten muss. Dann in meinem Selen Test, ich habe so etwas wie dies:

// 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 
} 

Beachten Sie, dass waitForTest mehrmals aufrufen kann, wenn nötig, jederzeit Sie diesen Test müssen innehalten, bis alle Asynchron-Operationen fertig sind.

0

Ich bezweifle Selen tut. Es wartet nur darauf, dass die Seite vollständig geladen ist, aber kein Skript zum Beenden. Vielleicht möchten Sie einen eigenen "Testschritt" definieren, um auf das Ergebnis zu warten (und den Seiteninhalt/Skriptstatus ständig abzufragen), aber stellen Sie sicher, dass Ihre Tests nicht für immer auf Skriptfehler hängen.

Verwandte Themen