xpath OR operator for multiple values - selenium

For the following scenario, xpath OR operator is not working. The same label showing in different nodes in different pages.
#FindBy(xpath = "(//label[#class='x-form-item-label'])[19] | (//label[#class='x-form-item-label'])[36]")
public WebElement lblFee;

Use the position() function with the or operator:
#FindBy(xpath = "(//label[#class='x-form-item-label'])[position()=19 or position()=36]")
public WebElement lblFee;

Related

How can I avoid having multiple xpath variables in Selenium?

i am defining 2 variables in Selenium like this:
#FindBy(xpath = "//span[contains(text(),'€11')]")
private WebElement singleTicket;
#FindBy(xpath = "//span[contains(text(),'€19')]")
private WebElement returnTicket;`
i need to pass different values in these variables for different tests e.g. "$12" but i dont want to create more variables in my page object with different prices. what is a good solution for this?
There is no way to pass parameter to #FindBy annotation. But you can write a custom function to get webelement based on specific value and tag too. so you don't need to create separate element everytime. Please have a look on below function.
public WebElement getWebElementForSpecificText(String tagName, String text) {
String formXpath= ".//"+tagName+"[contains(text(),'"+text+"')]";
return driver.findElement(By.xpath(formXpath));
}
Yu can call this function as mentioned below:
getWebElementForSpecificText("span", "€11");
getWebElementForSpecificText("span", "€12");
getWebElementForSpecificText("span", "€19");

Is there any way to get the xpath of element stored following page object model from a separate file?

Suppose I have stored WebElment in LoginPage.java class as shown below.
#FindBy(xpath="//input[#name='user_name']") WebElement username;
Now from my test file say VerifyLogin.java I want to access xpath of username which is stored in above LoginPage.java file something like this
LoginPage loginPage = PageFactory.initElements(driver, LoginPage.class);
loginPage.username;//then it should return the xpath //input[#name='user_name']
I know the above approach is wrong, but is there any way to get only the xpath that was stored in LoginPage file that I can use in VerifyLogin file?
If you need it outside of the page object then your design is not that good .
Anyhow if you really want it the following should do the job
#FindBy(xpath="//input[#name='user_name']")
public WebElement username;
new YourPageObject().username;
Not sure why you need to see the xpath after it's done its job but you can do something like this:
public final String xUserName = "//input[#name='user_name']";
#FindBy(xpath = xUserName)
public WebElement username;
The final attribute is required.
This way you store the path as a string, and use the string in your POM, but it is still readable as a string. I start the String variable with x so I know that the String is in xpath format. Start with c for CSS Selector notation.
I've done similar for a couple reasons:
The actual xpath is gigantic so I break it into smaller, reusable String chunks. But for that I mark the String as private.
I need the string to pass to other Selenium methods such as a pause class I created.
But to answer the direct question, no, you can't get the xpath from a POM variable because that information is not stored. The variable is a WebElement and doesn't care by what method you assigned it. It's like asking how a String was created.
you can use this small trick , I used it and it worked for me.
toString method lets you print webelement which has its xpath in it
then using substring method get ur xpath
// method to fetch xpath from PageFacotry webElement
public String getXpathFromWebelement(WebElement e) {
String xpath = e.toString();
xpath = xpath.substring(xpath.indexOf("/"), xpath.lastIndexOf("]"));
return xpath;
}

In Selenium, how is it possible to retrieve, by code, the value of a "FindsBy" attribute?

For my tests, I have an all my WebElements declared like this :
[FindsBy(How = How.XPath, Using = "//div[contains(text(),'blah blah')], Priority = 0)]
private IWebElement _webElementName;
I would like to get the XPath value for using this value in an other function (because this function can take only one parameter : a By variable).
I tried with the "GetAttribute" method, but it's for the attribute of the element in the page and I need the "Using" value of the FindsBy attribute.
In java this can be done using final but for c# you can try using readonly keyword.
readonly static string xpathString ="//div[contains(text(),'blah blah')]";
[FindsBy(How = How.XPath, Using = xpathString, Priority = 0)]
private IWebElement _webElementName;
// Now xpathString can be used anywhere

#FindBy with Arquillian Graphene using className

#FindBy(className = "shellTileBase")
private WebElement tile;
#FindBy(className = "FilterDefault FilterIcon UiIcon IconMirrorInRTL")
private WebElement form;
I am working with selenium and testng but am trying to add arquilliian to my testing. can arquillian handle
#FindBy(className ="")
With multiple class names as per my above example. When I run this I am getting a:
InvalidSelectorError: Compound class names not permitted
Is there a way around this?
Compound class names (class names with a spaces) cannot be used as selector in search by className. You can solve it using XPath as below:
#FindBy(xpath="//*[#class='FilterDefault FilterIcon UiIcon IconMirrorInRTL']")
or CSS:
#FindBy(css=".FilterDefault.FilterIcon.UiIcon.IconMirrorInRTL")

when do FindBy attributes trigger a driver.FindElement?

My question is: do webelements decorated with findby attributes call the findelement function upon each reference to them? If not, when?
And what is the procedure with List< webelement > which is also decorated? Does it trigger when you reference the list, or when you reference an element inside that list?
I'm asking because I have some situations where I'm getting stale element exceptions and I want to know how to deal with them.
WebElements are evaluated lazily. That is, if you never use a WebElement field in a PageObject, there will never be a call to "findElement" for it. Reference.
If don't want WebDriver to query the element each time, you have to use the #CacheLookup annotation.
What about the list part of my question?
The findElements is triggered when you query from the list. Say you have:
#FindBy(xpath = "//div[#class=\"langlist langlist-large\"]//a")
private List<WebElement> list;
Following code samples all trigger the findElements :
list.isEmpty();
WebElement element = list.get(0);
Where as
List<WebElement> newList = new ArrayList<WebElement>();
newList = list;
does not trigger the findElements().
Please check the LocatingElementListHandler class. I suggest diving into the source for answers.
You may find this code comment from PageFactory class helpful:
/**
* Instantiate an instance of the given class, and set a lazy proxy for each of the WebElement
* and List<WebElement> fields that have been declared, assuming that the field name is also
* the HTML element's "id" or "name". This means that for the class:
*
* <code>
* public class Page {
* private WebElement submit;
* }
* </code>
*
* there will be an element that can be located using the xpath expression "//*[#id='submit']" or
* "//*[#name='submit']"
*
* By default, the element or the list is looked up each and every time a method is called upon it.
* To change this behaviour, simply annotate the field with the {#link CacheLookup}.
* To change how the element is located, use the {#link FindBy} annotation.
*
* This method will attempt to instantiate the class given to it, preferably using a constructor
* which takes a WebDriver instance as its only argument or falling back on a no-arg constructor.
* An exception will be thrown if the class cannot be instantiated.
*
* #see FindBy
* #see CacheLookup
* #param driver The driver that will be used to look up the elements
* #param pageClassToProxy A class which will be initialised.
* #return An instantiated instance of the class with WebElement and List<WebElement> fields proxied
*/
For Question 1) The concept in Page Factory pattern is to identify WebElements only when they are used in any operation.
For Question 2) Whenever you try to access the Page class variables (WebElement or List) #FindBy triggers FindElement or FindElements based on the variable type.
class LoginPage{
.....
#FindBy(id, "uname")
WebElement username;// no trigger
#FindBy(xpath, "//table/tr")
List<WebElement> pdtTable; // no trigger
.....
.....
public void enterUserame(String text){
uname.sendKeys(text);
}
.....
.....
}
.....
.....
LoginPage loginPage = PageFactory
.initElements(driver, LoginPage.class); // creates WebElement variables but not triggers
if(loginPage.uname.isDisplayed()){// Trigger happens
loginPage.enterUserame("example");// Trigger happens
}
int count=pdtTable.size();// Trigger happens for FindElements
Additional Info : PageFactory annotation #CacheLookup is used to mark the WebElements once located so that the same instance in the DOM can always be used. This annotation, when applied over a WebElement, instructs Selenium to keep a cache of the WebElement instead of searching for the WebElement every time from the WebPage. This helps us save a lot of time.