You can easily ask Selenium to wait until a specific condition is met; in what you have, one of the options:
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());"); } });
However, then you basically test exactly what you just encoded, and this has the disadvantage that if name were set before you called setName , you did not have to wait for setName to complete. One thing I did in the past for such things is this:
In my test library (which replaces real asynchronous calls with setTimeout plugins), I have this:
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 the rest of my library, I use _setTimeout_ instead of window.setTimeout when I need to install something that happens later. Then, in my test for selenium, I do something like this:
// 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 }
Note that if necessary, you can call waitForTest several times, anytime you need this test to pause the action until all async operations are complete.
Daniel Martin
source share