How can I extract the text from a variable with Selenium WebDriver? - java

If I use "Inspect Element" on FireFox, I see this:
<span class="stock-number-value ng-binding">17109 </span>
When I use driver.getSource(), that 17109 is replaced by "vehicle.attributes.stockNumber".
My main goal is to use the driver to get whatever value is stored by vehicle.attributes.stockNumber, but I can't figure out how to get the contents of that variable using Selenium.

I suspect you are getting the source too early in the process while the angular is not yet ready and the bindings are not yet data-feeded. I'd use a custom wait condition function to wait for the "stock" to have a numeric value:
WebDriverWait wait = new WebDriverWait(webDriver, 510);
WebElement stock = wait.until(waitForStock(By.cssSelector(".stock-number-value")));
System.out.println(stock.getText());
where waitForStock is something along these lines:
public static ExpectedCondition<Boolean> waitForStock(final By locator) {
return new ExpectedCondition<Boolean>() {
#Override
public Boolean apply(WebDriver driver) {
try {
WebElement elm = driver.findElement(locator);
return elm.getText().trim().matches("[0-9]+");
} catch (NoSuchElementException e) {
return false;
} catch (StaleElementReferenceException e) {
return false;
}
}
#Override
public String toString() {
return "stock is not yet loaded";
}
};
}

Related

How to wait until an element no longer exists in Selenium

I am testing a UI in which the user clicks a delete button and a table entry disappears. As such, I want to be able to check that the table entry no longer exists.
I have tried using ExpectedConditions.not() to invert ExpectedConditions.presenceOfElementLocated(), hoping that it would mean "expect that there is not a presence of the specified element". My code is like so:
browser.navigate().to("http://stackoverflow.com");
new WebDriverWait(browser, 1).until(
ExpectedConditions.not(
ExpectedConditions.presenceOfElementLocated(By.id("foo"))));
However, I found that even doing this, I get a TimeoutExpcetion caused by a NoSuchElementException saying that the element "foo" does not exist. Of course, having no such element is what I want, but I don't want an exception to be thrown.
So how can I wait until an element no longer exists? I would prefer an example that does not rely on catching an exception if at all possible (as I understand it, exceptions should be thrown for exceptional behavior).
You can also use -
new WebDriverWait(driver, 10).until(ExpectedConditions.invisibilityOfElementLocated(locator));
If you go through the source of it you can see that both NoSuchElementException and staleElementReferenceException are handled.
/**
* An expectation for checking that an element is either invisible or not
* present on the DOM.
*
* #param locator used to find the element
*/
public static ExpectedCondition<Boolean> invisibilityOfElementLocated(
final By locator) {
return new ExpectedCondition<Boolean>() {
#Override
public Boolean apply(WebDriver driver) {
try {
return !(findElement(locator, driver).isDisplayed());
} catch (NoSuchElementException e) {
// Returns true because the element is not present in DOM. The
// try block checks if the element is present but is invisible.
return true;
} catch (StaleElementReferenceException e) {
// Returns true because stale element reference implies that element
// is no longer visible.
return true;
}
}
The solution would still rely on exception-handling. And this is pretty much ok, even standard Expected Conditions rely on exceptions being thrown by findElement().
The idea is to create a custom Expected Condition:
public static ExpectedCondition<Boolean> absenceOfElementLocated(
final By locator) {
return new ExpectedCondition<Boolean>() {
#Override
public Boolean apply(WebDriver driver) {
try {
driver.findElement(locator);
return false;
} catch (NoSuchElementException e) {
return true;
} catch (StaleElementReferenceException e) {
return true;
}
}
#Override
public String toString() {
return "element to not being present: " + locator;
}
};
}
Why don't you simply find the size of elements. We know the the collection of elements' size would be 0 if element does not exist.
if(driver.findElements(By.id("foo").size() > 0 ){
//It should fail
}else{
//pass
}
I don't know why but ExpectedConditions.invisibilityOf(element) is the only work for me while ExpectedConditions.invisibilityOfElementLocated(By), !ExpectedConditions.presenceOfElementLocated(By) ... not. Try it!
Hope this help!
// pseudo code
public Fun<driver,webelement> ElemtDisappear(locator)
{
webelement element=null;
iList<webelement> elemt =null;
return driver=>
{
try
{
elemt = driver.findelements(By.locator);
if(elemt.count!=0)
{
element=driver.findelement(By.locator);
}
}
catch(Exception e)
{
}
return(elemnt==0)?element:null;
};
// call function
public void waitforelemDiappear(driver,locator)
{
webdriverwaiter wait = new webdriverwaiter(driver,time);
try
{
wait.until(ElemtDisappear(locator));
}
catch(Exception e)
{
}
}
As findelement throws exception on element unaviability.so i implemented using findelements. please feel free to correct and use it as per your need.
I found a workaround to fix this for me in efficient way, used following C# code to handle this, you may convert it to Java
public bool WaitForElementDisapper(By element)
{
try
{
while (true)
{
try
{
if (driver.FindElement(element).Displayed)
Thread.Sleep(2000);
}
catch (NoSuchElementException)
{
break;
}
}
return true;
}
catch (Exception e)
{
logger.Error(e.Message);
return false;
}
}
Good news, it's built in now (I'm using Node.js in 2021)
It looks like elementIsNotVisible has been added to until after the previous answers were given. I'm using selenium webdriver 4.0.0-beta.3
Check it out:
const timeout = 60 * 1000; // 60 seconds
const element = await driver.findElement(By.id(elementId));
// this is the important line
await driver.wait(until.elementIsNotVisible(element), timeout);
You can use the following logic:
C# code sinppet:
//wait is the instance of WebDriverWait
wait.Until(driver => driver.FindElements(By.Xpath("your element expath")).Count == 0);
Notice how I use FindElements that does NOT throw NoSuchElementException which is swallowed by Until() function. So when element is gone collection size is zero.

function to check whether an element is present in the page

Created a function to check whether an element is present on a page or not. Intention is to wait for a specified period of time and then return false, if not present.
public boolean isElementPresent(final WebElement element) {
Wait<WebDriver> wait = new WebDriverWait(driver, 60);
return wait.until(new ExpectedCondition<Boolean>() {
public Boolean apply(WebDriver webDriver) {
return element.isDisplayed() != false;
}
});
}
But this is throwing exception in case of element not found
It is throwing exception because findElement will throw exception if no element is found. It is used in isDisplayed() method. You can 1st check, whether element is present on page then check whether it is displayed. Use following to make 1st check.
driver.findElements(byLocator).size>0
The following is a crude solution. But it works nevertheless :p
public boolean isElementPresent() {
try {
new WebDriverWait(driver, 10).until(ExpectedConditions.presenceOfElementLocatedBy(By.id(""));
return true;
} catch (TimeOutException e) {
return false;
}
}
When we use the WebDriverWait Class for waiting for a element to be present in the web page, a TimeOut Exception is thrown after the specified time. We catch it and return false. If no exception is thrown(if element is found), we return true.
If you are looking for checking whether the element is enabled or is displayed, explore the isDisplayed or isEnabled methods associated with WebElement. But please note that if the element is not physically present in the webpage, an exception is thrown.
Here is another less 'barbaric' method :-
public boolean isElementPresent() {
List<WebElement> elements = new WebDriverWait(driver, 10).until(ExpectedConditions.presenceOfElementsLocatedBy(By.id(""));
if (elements.isEmpty()) {
return false;
} else {
return true;
}
}
This will help you.
public boolean fncCheckElement() {
try {
WebElement element = (new WebDriverWait(driver,1)).until(ExpectedConditions.presenceOfElementLocated((By.id("ID"))));
system.out.println("Element is present in web page")
return true;
} catch (Throwable e) {
ex.printStackTrace();
system.out.println("Element is not present in web page")
return false;
}}
Enjoy!

Selenium webdriver explicit wait

I'm writing some automated tests for using the selenium chrome driver. I trying to write a reusable method that will explicitly wait for elements to appear and then call this method in other classes. Seems pretty straight forward but its not doing what I want it do. Here is the method that I have.
public String waitForElement(String item) {
WebDriverWait wait = new WebDriverWait(driver,30);
WebElement element = wait.until(
ExpectedConditions.elementToBeClickable(By.id(item)));
return item;
}
Then I call the method and pass it a parameter like this:
waitForElement("new-message-button");
That doesn't seem to become working, can someone give some insight?
You can use Explicit wait or Fluent Wait
Example of Explicit Wait -
WebDriverWait wait = new WebDriverWait(WebDriverRefrence,20);
WebElement aboutMe;
aboutMe= wait.until(ExpectedConditions.visibilityOfElementLocated(By.id("about_me")));
Example of Fluent Wait -
Wait<WebDriver> wait = new FluentWait<WebDriver>(driver)
.withTimeout(20, TimeUnit.SECONDS)
.pollingEvery(5, TimeUnit.SECONDS)
.ignoring(NoSuchElementException.class);
WebElement aboutMe= wait.until(new Function<WebDriver, WebElement>() {
public WebElement apply(WebDriver driver) {
return driver.findElement(By.id("about_me"));
}
});
Check this TUTORIAL for more details.
public static void clickOn(WebDriver driver, WebElement locator, int timeout)
{
new WebDriverWait(driver,timeout).ignoring(StaleElementReferenceException.class).until(ExpectedConditions.elementToBeClickable(locator));
locator.click();
}
Call the above method in the main method then we will get explicitly wait functionality.
Your problem is that you passed String to method parameter:
public String waitForElement(String item) {
You have to pass your WebElement, something like:
public boolean visibilityOfElementWait(WebElement webElement) {
if (webElement != null) {
try {
WebDriverWait wait = new WebDriverWait(Driver.getCurrentDriver(), 20);
wait.until(ExpectedConditions.visibilityOf(wrappedElement));
highlightElement(webElement);
return true;
} catch (Exception e) {
return false;
}
} else
Logger.logError("PageElement " + webElement.getText() + " not exist");
return false;
}
public void highlightElement(WebElement element) {
if (!Config.getProperty(Config.BROWSER).equalsIgnoreCase("ANDROIDHYBRID")) {
String bg = element.getCssValue("backgroundColor");
for (int i = 0; i < 4; i++) {
Driver.getDefault()
.executeScript("arguments[0].style.backgroundColor = 'red'", element);
Driver.getDefault()
.executeScript("arguments[0].style.backgroundColor = '" + bg + "'", element);
}
// String highlightElementScript = "arguments[0].style.backgroundColor = 'red';";
// Driver.getDefault().executeScript(highlightElementScript, element);
}
}
We can develop implicit wait on our own.
Use this code; it should also work the same as implicit wait.
//=== Start of Implicit Wait Statement ===
public void implicit_Wait_ID(String str) throws Exception{
for(int i=0;i<60;i++){
try{
driver.findElement(By.id(str)).isDisplayed();
break;
}catch(Exception e){Thread.sleep(2000);
}
}
}
//=== End of Implicit Wait Statement ===
Use this method by passing the ID value:
public void loginGmail() throws Exception
{
driver.findElement(By.id("Email")).sendKeys("Mail ID");
driver.findElement(By.id("next")).click();
implicit_Wait_ID("Passwd");
driver.findElement(By.id("Passwd")).sendKeys("Pwd value");
driver.findElement(By.id("signIn")).click();
}
If it is Xpath, LinkText, just create one of the above methods for all locator types and reuse it n number of times in your script.
Just use this method.I hope it will work perfectly.
public void waitForElement(String item) {
WebDriverWait wait = new WebDriverWait(driver,30);
WebElement element = wait.until(ExpectedConditions.visibilityOfElementLocated(By.id("item")));
}
Then call the method :
waitForElement("new-message-button");
I wrote an explicit wait for my selenium test in the following manner:
I declared my WebElement to be found with an #FindBy annotation added referencing the Id as follows:
#FindBy(how = How.ID, using = "home")
private WebElement home;
Then my method that waits for an element to load was written as follows:
public WebElement isElementLoaded(WebElement elementToBeLoaded) {
WebDriverWait wait = new WebDriverWait(driver, 15);
WebElement element = wait.until(ExpectedConditions.visibilityOf(elementToBeLoaded));
return element;
}
This allowed me to reference any element I was waiting for by name that I had annotated with a find by, regardless of the #FindBy method used.
I built a package using Selenium and waiting was one of the biggest issues I had. In the end, the methods as you described above wouldn't work. I had to resort to doing a simple implicit wait for any dynamic elements, as described below
An implicit wait is to tell WebDriver to poll the DOM for a certain amount of time when trying to find an element or elements if they are not immediately available. The default setting is 0. Once set, the implicit wait is set for the life of the WebDriver object instance.
Code:
WebDriver driver = new FirefoxDriver();
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
driver.get("http://somedomain/url_that_delays_loading");
WebElement myDynamicElement = driver.findElement(By.id("myDynamicElement"));
src
Hope that helps.

"Unable to locate element" exception with WebDriver

I'm getting an "Unable to locate element" exception while running the below code. My expected output is First Page of GoogleResults.
public static void main(String[] args) {
WebDriver driver;
driver = new FirefoxDriver();
driver.get("http://www.google.com");
driver.manage().timeouts().implicitlyWait(45, TimeUnit.SECONDS);
WebElement oSearchField = driver.findElement(By.name("q"));
oSearchField.sendKeys("Selenium");
WebElement oButton = driver.findElement(By.name("btnG"));
oButton.click();
//String oNext = "//td[#class='b navend']/a[#id='pnnext']";
WebElement oPrevious;
oPrevious = driver.findElement(By.xpath("//td[#class='b navend']/a[#id='pnprev']"));
if (!oPrevious.isDisplayed()){
System.out.println("First Page of GoogleResults");
}
}
If I run the above code I get "Unable to Locate Element Exception". I know the Previous Button Element is not in the first page of the Google Search Results page, but I want to suppress the exception and get the output of the next step if condition.
Logical mistake -
oPrevious = driver.findElement(By.xpath("//td[#class='b navend']/a[#id='pnprev']"));
will fail or give error if WebDriver can't locate the element.
Try using something like -
public boolean isElementPresent(By by) {
try {
driver.findElement(by);
return true;
} catch (NoSuchElementException e) {
return false;
}
}
You can pass the xpath to the function like
boolean x = isElementPresent(By.xpath("//td[#class='b navend']/a[#id='pnprev']"));
if (!x){
System.out.println("First Page of GoogleResults");
}

WebDriver: How to check if an page object web element exists?

How to check if an Element exists, when using Page Objects with webdriver.
So far I am doing it this way.
DefaultPage defaultPage = PageFactory.initElements(this.driver,
DefaultPage.class);
assertTrue(defaultPage.isUserCreateMenuLinkPresent());
Page Object:
public class DefaultPage {
#FindBy(id = "link_i_user_create")
private WebElement userCreateMenuLink;
public boolean isUserCreateMenuLinkPresent() {
try {
this.userCreateMenuLink.getTagName();
return true;
} catch (NoSuchElementException e) {
return false;
}
}
}
But I can not believe that this try/catch is the way one should do it. So what would be a better way to check if the elements exits (with using Page Objects)?
The problem is the pattern itself. It uses #FindBy annotation (used by PageFactory to init the fields that must be wrapped by Proxy) that replaces the standard elements with their proxy instances which contain InvocationHandler.
Each time you try to access a field, annotated with #FindBy, the invocation handler tries to find the element using the default ElementLocator.The problem is that the ElementLocator.findElement() method throws an TimeoutException / NoSuchElementException if there are no elements presented in the DOM.
public WebElement findElement(SearchContext context) {
List<WebElement> allElements = findElements(context);
if (allElements == null || allElements.isEmpty())
throw new NoSuchElementException("Cannot locate an element using "
+ toString());
return allElements.get(0);
}
Therefore, each time you need to check whether an element is displayed or not you have to search for a List of elements and check its size.
#FindBy(css = "div.custom")
private List<WebElement> elements
...
public isElementPresented(){
return elements != null && elements.size > 0
}
Another way to solve this problem is to create your own implementation of LocatingElementHandler and ElementLocator
So, if you need your own isDisplayed() method to return false instead of Exception, you have to replace the findElement() method in ElementLocator with something like that:
...
List<WebElement> elements = searchContext.findElements(by)
if(elements != null && elements.size() > 0){
List<WebElement> visibleElements = []
elements.each {
if(it.displayed){
visibleElements.add(it)
}
}
if(visibleElements.size() > 0){
return visibleElements.get(0)
}
}
return null
...
And add new conditions to LocatingElementHandler.invoke()
Something like:
element = locator.findElement()
if(element == null){
if(method.name == "isDisplayed"){
return false
}
}
Webdriver is designed to throw an exception if an element is not found, So there aren't any methods to verify presence of an element in Webdriver.
Check this - http://groups.google.com/group/webdriver/browse_thread/thread/909a9b6cb568e341
#Ralph: I do it the same way: try/catch. I've never found another way.
You could swap out the try/catch block in a super class and design it generic. In other words: You could write a method which expects an object of type WebElement. This method contains the try/catch block and return true/false...
So I wrote the following public method in the test framework's super class and am now able to use it in every page object:
public boolean isElementExisting(WebElement we) {
try {
we.isDisplayed();
return true;
} catch(NoSuchElementException e) {
LOGGER.severe("Element does not exist.");
return false;
}
}
I don't know why this is not implemented in WebDriver...
Otherwise you could use WebDriverWait.
I'm using this pattern, works fine for me:
public void login()
{
if (!loginButton.isDisplayed())
{
throw new IllegalStateException("Login button is not displayed!");
} else
{
loginButton.click();
}
}
or:
public boolean loginButtinIsDisplayed() {
try {
this.loginButton.getTagName();
return true;
} catch (NoSuchElementException e) {
e.printStackTrace();
return false;
}
}
I recently came across this old post and believe I've found one solution.
I was testing a page that had an Add User button. When the button was clicked, various editable text fields appeared (for First Name, Last Name, Email, etc..) and a single dropdown.
When a Cancel button was clicked, the fields disappeared and no longer existed. Using WebDriverWait with ExpectedConditions.visibilityOf() would not work since the elements no longer existed in the DOM.
I found that #FindAll was a solution for me, though I must admit my test ran noticeably slow at the my List assertion.
For your code, something like this:
public class DefaultPage {
#FindAll({#FindBy(id = "link_i_user_create")}) List<WebElement> userCreateMenuLink;
public boolean isUserCreateMenuLinkPresent() {
if (this.userCreateMenuLink.isEmpty()) fail("Link does not exist");}
I am able to use something similar in my own tests though, and it seems like a dependable way to skirt the 'No such element' exception. It's basically a page object adaptation of asserting: driver.findElements(By.locator).size() < 1.
Here is a nice pattern to access optional elements on a page:
#FindBy(...)
private List<WebElement> element;
public Optional<WebElement> getElement() {
return element.stream().findFirst();
}
In a test, you could then use the following assertions:
assertEquals(Optional.empty(), page.getElement()); // element should be absent
assertTrue(page.getElement().isPresent()); // element should be present
var e = page.getElement().orElseThrow(AssertionFailedError::new); // check and use element
Arquillian has implemented that feature in Graphene extension.
Check ElementLocatorConditionFactory.isPresent() function.
They more or less do what you wrote in your question (from ExpectedConditions.findElement in selenium-support.jar) :
try {
return driver.findElement(by);
} catch (NoSuchElementException e) {
throw e;
} catch (WebDriverException e) {
// [...] some log
throw e;
}
Using C# bindings:
using System.Collections.Generic;
using System.Linq;
public class DefaultPage
{
[FindsBy(How = How.Id, Using = "link_i_user_create")]
private IList<IWebElement> userCreateMenuLink;
public bool isUserCreateMenuLinkPresent()
{
return userCreateMenuLink.Any();
}
}
You're telling Selenium to grab all elements that match that Id and put them into a List of IWebElement. You then call .Any() on the list which evaluates to true if at least one IWebElement was found.
try this is defiantly work in pom
public boolean isPrebuiltTestButtonVisible() {
try {
if (preBuiltTestButton.isEnabled()) {
return true;
} else {
return false;
}
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
this will definitely work in page object model surround with try catch

Categories

Resources