I am a beginner for Selenium Webdriver, I have written a script in Java to test a functionality, and it is working fine. Sometimes I faces an issue.
Suppose I just click on create button to create something (let suppose customer) and after this I need to do some work with a screen which comes after create successfully customer. Sometimes due to slow response from server, my script get failed due to search a DOM element which comes after create customer.
If response come with in predefined time in my code, no issue, if not come then script failed (it search a element which has not rendered yet).
1) click on button
try{
// let suppose creatButtonElement is the web element of Create Button.
createButtonElement.click();
}catch(Exception e){
throw new Exception("Unable To Click on element [ " + element + " ] , plz see screenshot [ UnableToClick_" + element);
}
Expecting: after click on create button my script is expecting success message for assertion.
I had faced this issue once but I had handled this manually. This will work if after click button loader is appearing. It waits for one minute.
Please use the following code to wait manually to get response of server. It check the visibility of loader to know the response each second.
public static void loading_wait() throws Throwable {
int i = 0;
int maxloopDependOnBrowser = 60;
int totalSecond=0;
boolean loadinImageTakingMuchTime=false;
try{
while (true) {
i++;
if( !(loaderDisplayed(APP_LoadingImage_xpath)) ){
totalSecond+=i;
break;
}
if (i > maxloopDependOnBrowser) {
totalSecond=maxloopDependOnBrowser + 1;
loadinImageTakingMuchTime=true;
break;
} else {
totalSecond=i;
Thread.sleep(1000);
}
}
Thread.sleep(1000);
if(loadinImageTakingMuchTime){
throw new Throwable();
}
}catch (Throwable t) {
throw new Exception("FAILED:>>> Loading image is taking too much time :>>"+Throwables.getStackTraceAsString(t));
}
}
XpathKey :- to find the loader element
public static boolean loaderDisplayed(String XpathKey) {
int i = 0;
try {
driver.manage().timeouts().implicitlyWait(5, TimeUnit.MILLISECONDS);
List<WebElement> elementList = getORObject_list(XpathKey/*, 0, 500*/);
for (Iterator<WebElement> iterator = elementList.iterator(); iterator.hasNext();) {
WebElement webElement = (WebElement) iterator.next();
if (webElement.isDisplayed()) {
i = 1;
break;
}
}
} catch (Throwable t) {
}
finally {
driver.manage().timeouts().implicitlyWait(Long.parseLong(1), TimeUnit.SECONDS);
}
if (i == 0) {
return
} else {
return true;
}
}
You can join waiting
WebDriverWait wait = new NWebDriverWait(driver, 10); //10 second
wait.until(ExpectedConditions.presenceOfElementLocated(By.id("btn1")));
wait.until(ExpectedConditions.visibilityOfElementLocated(By.id("btn1")));
wait.until(ExpectedConditions.elementToBeClickable(By.id("btn1")));
I made a testcase in selenium which repeats perfectly and then exported it to JAVA /JUnit4 / Webdriver :
public void emailInvalid() throws Exception {
driver.get(baseUrl + "/test/contacts.html");
driver.findElement(By.name("companyName")).clear();
driver.findElement(By.name("companyName")).sendKeys("testcomp");
driver.findElement(By.name("phone")).clear();
driver.findElement(By.name("phone")).sendKeys("45454545");
driver.findElement(By.name("email")).clear();
driver.findElement(By.name("email")).sendKeys("test.ee");
driver.findElement(By.name("message")).clear();
driver.findElement(By.name("message")).sendKeys("qwerty");
driver.findElement(By.cssSelector("button.submit")).click();
assertEquals("Not valid email.", driver.findElement(By.cssSelector("span.error.notValidEmail")).getText());
}
The test fails in Java because assertEquals can't get the text its looking for. The error message is
org.junit.ComparisonFailure: expected:<[Not valid email]> but was:<[]>
In most cases your problem would be bad synchronization.
Your element is found but its text is empty.
You can try touse webDriverWait with expecting the stalenessOf, you can change the way an element is located by using its expected text in the locator or you can add very short sleep
Apparently the element cannot be found by the css selector and thereby the assertion fails.
Maybe the element is loaded after the assertion is executed or the element is not loaded at all.
Try to wait for the element to be loaded before the assertion using the following code:
WebDriverWait wait = new WebDriverWait(driver, 10);
wait.until(ExpectedConditions.elementToBeClickable(By.cssSelector("span.error.notValidEmail")));
assertEquals("Not valid email.", driver.findElement(By.cssSelector("span.error.notValidEmail")).getText());
If this is not the case then check again if the selector is correct.
Also check what getText() returns by printing the actual string.
Try waiting for the text present and use an assert if the text is located within the specified time interval.
Also be sure to check the uniqueness of the element using your css locator.
public void emailInvalid() throws Exception {
driver.get(baseUrl + "/test/contacts.html");
driver.findElement(By.name("companyName")).clear();
driver.findElement(By.name("companyName")).sendKeys("testcomp");
driver.findElement(By.name("phone")).clear();
driver.findElement(By.name("phone")).sendKeys("45454545");
driver.findElement(By.name("email")).clear();
driver.findElement(By.name("email")).sendKeys("test.ee");
driver.findElement(By.name("message")).clear();
driver.findElement(By.name("message")).sendKeys("qwerty");
driver.findElement(By.cssSelector("button.submit")).click();
WebDriverWait wait = new WebDriverWait(driver, 10);
wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("span.error.notValidEmail")));
assertTrue(waitForTextPresent(driver, By.cssSelector("span.error.notValidEmail"), "Not valid email.", 20));
}
public static boolean waitForTextPresent(WebDriver driver, By locator, String text, int timeOut) {
int i = 0;
int WAIT_SLEEP_INTERVAL = 500;
boolean isTextPresent = false;
while (!isTextPresent) {
i = i + 1;
try{
Thread.sleep(WAIT_SLEEP_INTERVAL);
} catch(Exception e) {
//do nothing
}
isTextPresent = driver.findElement(locator).getText().contains(text);
if (i * WAIT_SLEEP_INTERVAL >= timeOut) {
return false;
}
}
return true;
}
Actually you can also do a get text after the line:
wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("span.error.notValidEmail")));
System.out.println(driver.findElement(By.cssSelector("span.error.notValidEmail")).getText());
And see if you are getting the text that you are looking for. You may not need to use the method waitForTextPresent in that case.
Try to check what value of baseUrl. Is it equals "http://yousite" or just ".." or so on? Try to debug this method may be Java didn't found correct url. Or use logging and logging baseUrl + "/test/contacts.html". It look like problem with baseUrl.
I have issue keep throw error of unable to find the xpath , as i set the loop for opening this xpath to insert data . Although i set the time wait for existance to 60secound but it still couldn't find it. I been trying alot method calling this by using title or status hence it still not working . Kindly advise
HTML :
91.14
CODE :
public void clickOnItemTax () {
By xPath = By.xpath("//a[contains(#href,'edit_total_amt')]");
this.sleep(3);
if (this.waitForExistence(xPath,60)) {
WebElement domLink = linkGet(xPath);
domLink.click();
} else {
JLog.fail("Unable to find a writable item taxdialog!");
}
}
-waitforExistence
public boolean waitForExistence(By by, int timeoutSeconds){
boolean exists = false;
Long polling_interval = (long) 250;
Long timeout = (long) timeoutSeconds * 1000; // in seconds
Long elapsed = (long) 0;
while (elapsed <= (timeout)) {
if (exists(by)) {
exists = true;
break;
}
try {
Thread.sleep(polling_interval);
} catch (InterruptedException e) {
JLog.warning(JLog.getStackTraceAsString(e));
break;
}
elapsed += polling_interval;
}
if (elapsed >= timeout) {
JLog.warning("waitForExistence waited for " + timeout/1000 + " seconds, but unable to find: " + by.toString());
}
return exists;
}
Thanks you
If it's an internal company webpage could I suggest that you give the an 'id' to make your life easier. If not you can do this. I'm always surprised by people writing their own wait method when you could use either the implicit or explicit wait time in Selenium.
The former is as follows, the only thing to be aware using this method is that when looking for an element it will always wait this long. It is however a much safer way to write your scripts looking for elements and doesn't bloat your code:
driver.manage().timeouts().implicitlyWait(6, TimeUnit.SECONDS);
if (driver.findElements(By.cssSelector("//*[#title=\"Override total tax amount\"]")).size()!=0)
{
driver.findElement(By.cssSelector("//*[#title=\"Override total tax amount\"]")).click();
}
else
{
JLog.fail("Unable to find a writable item taxdialog!");
}
The explicit way to do it would be as follows where 10 is your seconds:
WebElement myDynamicElement = (new WebDriverWait(driver, 10))
.until(ExpectedConditions.presenceOfElementLocated(By.cssSelector("//*[#title=\"Override total tax amount\"]")));
See the following link for more on this.
http://docs.seleniumhq.org/docs/04_webdriver_advanced.jsp
I am getting a StateElementReferenceException when I try to perform a drag-and-drop action, see the code snippets below. Can anyone please help to solve this with appropriate suggestions and explanations?
#Test(priority=4)
public void addUserBySearch() {
driver.findElement(By.xpath(OR.getProperty("btnUserGroup"))).click();
driver.findElement(By.xpath(OR.getProperty("btnCreateUG"))).click();
driver.findElement(By.xpath(OR.getProperty("textUGName"))).sendKeys("UserGroup:" + Utils.randGen());
driver.findElement(By.xpath(OR.getProperty("userSearchField"))).sendKeys("testuser2", Keys.ENTER);
source = driver.findElement(By.xpath(OR.getProperty("searchedUserSource")));
destination = driver.findElement(By.xpath(OR.getProperty("userDestination")));
waitUntilElementVisible(30, source);
dragAndDrop(source, destination);
driver.findElement(By.xpath(OR.getProperty("btnScheduleNow"))).click();
}
public void waitUntilElementVisible(int seconds, WebElement element) {
WebDriverWait explicitWait = new WebDriverWait(driver, seconds);
explicitWait.until(ExpectedConditions.visibilityOf(element));
}
public void dragAndDrop(WebElement sourceElement, WebElement destinationElement){
try {
if (sourceElement.isDisplayed() && destinationElement.isDisplayed()) {
Actions action = new Actions(driver);
action.dragAndDrop(sourceElement, destinationElement).build().perform();
}
else {
System.out.println("Element not found to drag and drop");
}
}
catch (StaleElementReferenceException exc) {
exc.printStackTrace();
}
catch (NoSuchElementException exc) {
exc.printStackTrace();
}
}
btnUserGroup = //*[text()='User Groups']
btnCreateUG = //*[#id='stage']/div/div[2]/div/div/div[2]/div[3]/a
textUGName = //input[#id='user_group_name']
btnScheduleNow = //*[text()='Schedule Now']
userDestination = //*[#class='ConnectedList ConnectedListAdded']/div[2]/ul
userSearchField = //div[#class='ConnectedListConnectedListSelect']/div[2]/div[1]/ul/li[1]/input
searchedUserSource = //div[#class='ConnectedList ConnectedListSelect']/div[2]/ul/li/span[5]
Exception:
org.openqa.selenium.StaleElementReferenceException: Element not found in the cache - perhaps the page has changed since it was looked up
Command duration or timeout: 10.28 seconds
A StaleReferenceException occurs for mainly one of two reasons:
The element has been deleted entirely.
The element is no longer attached to the DOM.
One possible solution to your problem is to surround dragAndDrop() in a while loop, and continually try and dragAndDrop() until you succeed. So something like the following:
boolean draggedAndDropped = false;
while(!draggedAndDropped ) {
try{
source = driver.findElement(By.xpath(OR.getProperty("searchedUserSource")));
destination = driver.findElement(By.xpath(OR.getProperty("userDestination")));
dragAndDrop(source, destination);
draggedAndDropped = true;
} catch(StaleElementReferenceException e) {
System.out.println("StaleElementReferenceException caught, trying again");
}
}
Of course its never a good idea idea to give allow a loop to loop infinitely, so you will want to incorporate a max attempts into the while loop.
As stated by the Selenium project's documentation, a StaleElementReferenceException can be thrown for two reasons:
The element has been deleted entirely.
The element is no longer attached to the DOM.
As such, I suspect that a race condition is occurring at this point:
driver.findElement(By.xpath(OR.getProperty("userSearchField"))).sendKeys("testuser2", Keys.ENTER);
source = driver.findElement(By.xpath(OR.getProperty("searchedUserSource")));
After you've entered "testuser2" in the "userSearchField" WebElement you've used Keys.ENTER to presumably submit the search query - the problem may be occurring because WebDriver is retrieving a reference to the "searchedUserSource" WebElement before the page has fully refreshed.
To get around this, you could try using the WebElement.submit() method to submit the search as it blocks the WebDriver's execution until the page has finished changing (i.e. finished displaying the search result).
Below is an example of how you could implement this:
driver.findElement(By.xpath(OR.getProperty("userSearchField"))).sendKeys("testuser2").submit();
source = driver.findElement(By.xpath(OR.getProperty("searchedUserSource")));
In tests that I write, if I want to assert a WebElement is present on the page, I can do a simple:
driver.findElement(By.linkText("Test Search"));
This will pass if it exists and it will bomb out if it does not exist. But now I want to assert that a link does not exist. I am unclear how to do this since the code above does not return a boolean.
EDIT This is how I came up with my own fix, I'm wondering if there's a better way out there still.
public static void assertLinkNotPresent (WebDriver driver, String text) throws Exception {
List<WebElement> bob = driver.findElements(By.linkText(text));
if (bob.isEmpty() == false) {
throw new Exception (text + " (Link is present)");
}
}
It's easier to do this:
driver.findElements(By.linkText("myLinkText")).size() < 1
I think that you can just catch org.openqa.selenium.NoSuchElementException that will be thrown by driver.findElement if there's no such element:
import org.openqa.selenium.NoSuchElementException;
....
public static void assertLinkNotPresent(WebDriver driver, String text) {
try {
driver.findElement(By.linkText(text));
fail("Link with text <" + text + "> is present");
} catch (NoSuchElementException ex) {
/* do nothing, link is not present, assert is passed */
}
}
Not Sure which version of selenium you are referring to, however some commands in selenium * can now do this:
http://release.seleniumhq.org/selenium-core/0.8.0/reference.html
assertNotSomethingSelected
assertTextNotPresent
Etc..
There is an Class called ExpectedConditions:
By loc = ...
Boolean notPresent = ExpectedConditions.not(ExpectedConditions.presenceOfElementLocated(loc)).apply(getDriver());
Assert.assertTrue(notPresent);
Try this -
private boolean verifyElementAbsent(String locator) throws Exception {
try {
driver.findElement(By.xpath(locator));
System.out.println("Element Present");
return false;
} catch (NoSuchElementException e) {
System.out.println("Element absent");
return true;
}
}
With Selenium Webdriver would be something like this:
assertTrue(!isElementPresent(By.linkText("Empresas en MisiĆ³n")));
boolean titleTextfield = driver.findElement(By.id("widget_polarisCommunityInput_113_title")).isDisplayed();
assertFalse(titleTextfield, "Title text field present which is not expected");
It looks like findElements() only returns quickly if it finds at least one element. Otherwise it waits for the implicit wait timeout, before returning zero elements - just like findElement().
To keep the speed of the test good, this example temporarily shortens the implicit wait, while waiting for the element to disappear:
static final int TIMEOUT = 10;
public void checkGone(String id) {
FluentWait<WebDriver> wait = new WebDriverWait(driver, TIMEOUT)
.ignoring(StaleElementReferenceException.class);
driver.manage().timeouts().implicitlyWait(1, TimeUnit.SECONDS);
try {
wait.until(ExpectedConditions.numberOfElementsToBe(By.id(id), 0));
} finally {
resetTimeout();
}
}
void resetTimeout() {
driver.manage().timeouts().implicitlyWait(TIMEOUT, TimeUnit.SECONDS);
}
Still looking for a way to avoid the timeout completely though...
You can utlilize Arquillian Graphene framework for this. So example for your case could be
Graphene.element(By.linkText(text)).isPresent().apply(driver));
Is also provides you bunch of nice API's for working with Ajax, fluent waits, page objects, fragments and so on. It definitely eases a Selenium based test development a lot.
For node.js I've found the following to be effective way to wait for an element to no longer be present:
// variable to hold loop limit
var limit = 5;
// variable to hold the loop count
var tries = 0;
var retry = driver.findElements(By.xpath(selector));
while(retry.size > 0 && tries < limit){
driver.sleep(timeout / 10)
tries++;
retry = driver.findElements(By.xpath(selector))
}
Not an answer to the very question but perhaps an idea for the underlying task:
When your site logic should not show a certain element, you could insert an invisible "flag" element that you check for.
if condition
renderElement()
else
renderElementNotShownFlag() // used by Selenium test
Please find below example using Selenium "until.stalenessOf" and Jasmine assertion.
It returns true when element is no longer attached to the DOM.
const { Builder, By, Key, until } = require('selenium-webdriver');
it('should not find element', async () => {
const waitTime = 10000;
const el = await driver.wait( until.elementLocated(By.css('#my-id')), waitTime);
const isRemoved = await driver.wait(until.stalenessOf(el), waitTime);
expect(isRemoved).toBe(true);
});
For ref.: Selenium:Until Doc
The way that I have found best - and also to show in Allure report as fail - is to try-catch the findelement and in the catch block, set the assertTrue to false, like this:
try {
element = driver.findElement(By.linkText("Test Search"));
}catch(Exception e) {
assertTrue(false, "Test Search link was not displayed");
}
This is the best approach for me
public boolean isElementVisible(WebElement element) {
try { return element.isDisplayed(); } catch (Exception ignored) { return false; }
}
For a JavaScript (with TypeScript support) implementation I came up with something, not very pretty, that works:
async elementNotExistsByCss(cssSelector: string, timeout=100) {
try {
// Assume that at this time the element should be on page
await this.getFieldByCss(cssSelector, timeout);
// Throw custom error if element s found
throw new Error("Element found");
} catch (e) {
// If element is not found then we silently catch the error
if (!(e instanceof TimeoutError)) {
throw e;
}
// If other errors appear from Selenium it will be thrown
}
}
P.S: I am using "selenium-webdriver": "^4.1.1"
findElement will check the html source and will return true even if the element is not displayed. To check whether an element is displayed or not use -
private boolean verifyElementAbsent(String locator) throws Exception {
boolean visible = driver.findElement(By.xpath(locator)).isDisplayed();
boolean result = !visible;
System.out.println(result);
return result;
}
For appium 1.6.0 and above
WebElement button = (new WebDriverWait(driver, 10).until(ExpectedConditions.presenceOfElementLocated(By.xpath("//XCUIElementTypeButton[#name='your button']"))));
button.click();
Assert.assertTrue(!button.isDisplayed());