I am using Webdriver in Java and I encountered an issue repeatedly that I can't find a proper solution yet.
It is to do with doing actions on a page that will cause this page DOM to change (for example, Javascript lightbox), then my JUnit test is expecting new elements after the DOM change but my test is getting the old DOM element.
To give you an example, I have a scenario as below.
First of all click “Add item” button in the below image and the light box appears:
Then fill in all the item details and click "Add & Close". You will see the screen below:
Notice that now there is an info message Your item ... has been added
.
Now I put keywords in the Search text box and hit enter and the info message will be changed to below:
In my JUnit test, the flow is like below:
....
itemDetailsPage.clickAddAndClose();
itemDetailsPage.searchItemBy("Electricity");
assertEquals("Your search for 'electricity' returned 2 results.",
itemDetailsPage.getInfoMsg());
....
Now this test is not very robust, because if the network is slow, most of the times, getInfoMsg()
will return the previous info message Your item ... has been added
instead of the latest info message, which causes the test to fail. Just a side note that these two info message have share the same html element id.
The solution I am trying to implement here are:
add explicit wait in clickAddAndClose() So it looks something like:
public void clickAddAndClose() { ... clickWhenReady(driver, By.id(addAndCloseButtonId)); ... waitForElementByLocator(driver,By.id(itemInfoMsgId),10); }
The second wait proves to be useless because,
itemInfoMsgId
already exist when the user added the item from the add item lightbox.add
waitForPageLoaded()
method at the end ofclickAddAndClose()
to try to wait for the page to finish reloading. The generic method forwaitForPageLoaded()
below:public void waitForPageLoaded(WebDriver driver) { ExpectedCondition<Boolean> expectation = new ExpectedCondition<Boolean>() { public Boolean apply(WebDriver driver) { return ((JavascriptExecutor) driver).executeScript( "return document.readyState").equals("complete"); } }; Wait<WebDriver> wait = new WebDriverWait(driver, 30); try { wait.until(expectation); } catch (Throwable error) { assertFalse("Timeout waiting for Page Load Request to complete.", true); } }
I am expect at the end of clickAddAndClose()
, it will see this page is still being updated so it will wait until the info message has been updated. But this does not seem to work either.
That leaves me to the last choice will is to add a thread sleep at the end of clickAddAndClose()
. I want to avoid using it.
Is there a generic way of solving this kind of problem? How do I detect that the page DOM is still changing and tell Webdriver to wait until it finishes refreshing?