Does Selenium wait for JavaScript to complete?
You can easily ask Selenium to wait until a particular condition is true; in exactly what you have, one alternative would be:
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're basically testing exactly what you just coded, and that has the disadvantage that if name
were set before you called setName
, you haven't necessarily waited setName
to finish. One thing I've done in the past for similar things is this:
In my testing library (which replaces real async calls with setTimeout
shims), 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
whenever I need to set something up to happen later. Then, in my selenium test, I do something like this:
// First, this routine is in a library somewherepublic 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 you can call waitForTest
multiple times if needed, any time you need that test to pause until all async operations are finished.
I doubt selenium does. It only waits for page to be completely loaded, but not a script to finish. You may wish to define your own 'test step' for waiting for result (and constantly polling the page contents/script state), but be sure to setup reasonable timout not to male your tests hang forever on script error.