Is #FindBy (id = 'blabla') same thing as //*[#id='blabla] - selenium

I decided to give a try to Katalon and got this question because Katalon Studio, when user choose "locate by attribute 'id' " it shows that //*[#id='blabla'] will be used to locate element. But as for me it looks like variation of xPath. So i wonder, when in JAVA - Selenium i write #findBy (id='blabla') - under the hood selenium convert it to //*[#id = 'blabla'] ???
Could`t find answer
Google, forums, katalon docs
UPDATE:
I want to know if this two methods are exactly the same. 1. Will it take same amount of time to find element? 2. Are both of methods going to start looking for element from top of the DOM ?

Functionally these all do the same thing:
The #FindBy(id = "foo") annotation
driver.findElement(By.id("foo"))
driver.findElement(By.xpath("//*[#id = 'foo']"))
driver.findElement(By.css("#foo"))
They all find an element by its Id.
I'm not sure what that translates to in API calls to the Selenium Server, but Selenium is open source. Have a look for yourself.
The #FindBy(...) annotation is defined in FindBy.java, which inherits from AbstractFindByBuilder. Trace through the code and you'll figure it out.

It is the equivalent. (But it could depend on the particular Selenium bindings)
If to look into By class of Selenium Java library there you can see the code like this:
public List<WebElement> findElements(SearchContext context) {
return context instanceof FindsById ? ((FindsById)context).findElementsById(this.id) : ((FindsByXPath)context).findElementsByXPath(".//*[#id = '" + this.id + "']");
}
A single element lookup just reuses lookup of a collection.

Related

Getting description using selenium xpath

I am trying to get the job description for job search page indeed.com This is how it looks like
Provide technical leadership around
QA
automation to IT teams. Work with various team to promote
QA
processes, practices and standardization....
Any idea how can I get that description? I tried the following:
//span[contains(#class,'summary')]
That does not give me the text description. Should I xpath or is there any other solution? Thanks in advance for your time.
This XPath are correct.
//span[contains(#class,'summary')]
//span[#class='summary']
I'm a Python guy, But I translated it to Java. You can do:
element = driver.findElement(By.name("summary"));
element = driver.findElement(By.className("summary"));
element = driver.findElement(By.cssSelector('span[class="summary"]');
And remember that If you want the element text, every element has the method .getText(), the find* functions only retrieve the element/s.
Double check you were not using driver.findElements(By.xpath()) in plural. In that case you should first retrieve the individual elements. Then access to the .getText() method.
description = driver.findElement(By.className("summary")).getText();
System.out.print(description);
Alternatively you could do:
description = driver.findElement(By.className("summary"));
description_text = description.getAttribute("innerHTML");
System.out.print(description_text);
If your problem is that your element is not visible or reachable (stale). Then you can use javascript.
element = driver.executeScript("return document.querySelector('span[class=\"summary\"]');");
For more reference:
https://seleniumhq.github.io/selenium/docs/api/java/org/openqa/selenium/WebElement.html

Page Factory #FindBy

I am currently learning page object model (POM) and I am trying to access a specific web element using #FindBy but I am not sure how to correctly write the syntax for my element into #FindBy?
What I have is:
driver.findElement(By.cssSelector("a[dta-qid='inventory']");
So my question is how do I place a[da-qid='inventory'] correctly into #FindBy?
By, a[da-qid='inventory'], what I mean is that it selects every <a> element whose da-qid value begins with 'inventory'.
Why do not you read through this? Use of #FindsBy is easier if you do that with How Enum. You have multiple options in that case. With cssSelector it should look like this
#FindBy(how = How.css, using = "a[dta-qid='inventory']")
WebElement foobar;
If you assume that multiple elements will be found using this selector, try the following:
#FindBy(css="a[da-qid='inventory']")
List<WebElement> elements;
Just don't forget to choose correctly between da-qid='inventory' and dta-qid='inventory'
You could use the XPath selector:
driver.findElement(By.xpath("//a[contains(#da-qid,'inventory')]");
or
#FindBy(xpath = "//a[contains(#da-qid,'inventory')]")
WebElement inventoryLink;
respectively
#FindAll(xpath = "//a[contains(#da-qid,'inventory')]")
List<WebElement> inventoryLinks;
Theoretically the XPath "//a[startsWith(#da-qid,'inventory')]" exists as well, but it didn't work in all WebDrivers for me.

selenium webdriver code to click on 'Album' in facebook

I am not able to click on 'Albums' in Facebook.
The HTML is Albums how to locate the element 'Albums' in selenium web driver.
I tried with using driver.findelement(By.xpath(span[#class="_3sz"]) showing error as element not found
And, the html looks the following:
<span class="_3sz">Albums</span>
If I am understanding your problem correctly then that xpath you mentioned returns more than one elements. Use a text based search which is more easier and specific.
driver.findelement(By.xpath("//*[.='Albums']").click();
And, here . is used to directly point to the parent element. Additional wait might be needed to wait for the element to interact. Also, I am assuming you are trying to click the element.
EDIT
Driver = new ChromeDriver();
WebDriverWait wait = new WebDriverWait(Driver, TimeSpan.FromSeconds(10));
Driver.Navigate().GoToUrl("http://www.facebook.com");
Driver.Manage().Window.Maximize();
Driver.FindElement(By.CssSelector("#email")).SendKeys("your email");
Driver.FindElement(By.CssSelector("#pass")).SendKeys("your pass");
Driver.FindElement(By.CssSelector("[type='submit'][value='Log In']")).Click();
Driver.FindElement(By.CssSelector(".fbxWelcomeBoxName")).Click();
Driver.FindElement(By.XPath("//*[.='Photos']")).Click();
wait.Until(ExpectedConditions.ElementIsVisible(By.XPath("//*[.='Albums']")));
Driver.FindElement(By.XPath("//*[.='Albums']")).Click();
By albumname = By.XPath("//strong[.='2014']"); //this should be your album name. In my case it's 2014
wait.Until(ExpectedConditions.ElementExists(albumname));
Driver.FindElement(albumname).Click();
wait.Until(ExpectedConditions.ElementExists(By.CssSelector(".fbPhotoAlbumHeader.fbPhotoAlbumOptionsPresent [type='file']")));
Driver.FindElement(By.CssSelector(".fbPhotoAlbumHeader.fbPhotoAlbumOptionsPresent [type='file']")).SendKeys(#"D:\Users\Saifur\Desktop\FacebookPicture\150232_585410621540701_1836495431_a.jpg");
wait.Until(ExpectedConditions.ElementExists(By.CssSelector(".pvm.phl.footerBox.uiBoxWhite")));
Driver.SwitchTo().ActiveElement();
wait.Until(ExpectedConditions.ElementExists(By.CssSelector("[name='postPhotosButton']")));
Driver.FindElement(By.CssSelector("[name='postPhotosButton']")).Click();
Notice mine is C#
It always best practice to follow this sequence while selecting elements.
1) ID
2) CSS
3) XPath (This will have some issues with different browsers specially IE)
In this case, considering this is no other span class with same name. It would have work like this "span._3sz". Simple and powerful.

WebDriver Selenium API: identifying a WebElement in XPath

I have recently started with Selenium, and I've decided to use only Selenium 2 / WebDriver.
In my test code, I often arrive at a WebElement without knowing where it is in the page.
I'd like to have code that, given an WebElement, constructs an XPath expression to uniquely select it.
FireFox recorder plugins for Selenium do this; what I want is code to do it in Selenium 2.
I can write such code myself by using WebElement's findElement to walk up the tree and findElements to find the child we came from, but it's nontrivial to come up with something fast (repeatedly calling By.xpath seems bad) and complete (e.g. due to namespaces).
(A related question suggests using CSS selectors instead - that's fine with me.)
Has anyone done this for me? What is the best approach?
Maybe this will help: I am testing a website where the id's are dynamically generated, so they change all the time. In order to get their xpath and work with it I use this function:
/**
* Gets the absolute xPath for elements with dynamic ids.
*
* #param driver - the current WebDriver instance
* #param element - the element for which the xPath will be found
* #return the absolute xPath for this element
*/
public static String getElementXPath(WebDriver driver, WebElement element) {
return (String)((JavascriptExecutor)driver).executeScript(
"gPt=function(c)" +
"{" +
"if(c.id!=='')" +
"{return c.tagName + '[#id=\"'+c.id+'\"]'}" +
"if(c===document.body)" +
"{return c.tagName}" +
"var a=0;" +
"var e=c.parentNode.childNodes;" +
"for(var b=0;b<e.length;b++)" +
"{var d=e[b];" +
"if(d===c)" +
"{return gPt(c.parentNode)+'/'+c.tagName+'['+(a+1)+']'}" +
"if(d.nodeType===1&&d.tagName===c.tagName)" +
"{a++}" +
"}" +
"};" +
"return gPt(arguments[0]);", element);
}
It's pretty straight forward: and btw yes css is the way to go; xpath should be only used as a measure of last resort. http://sauceio.com/index.php/2010/01/selenium-totw-css-selectors-in-selenium-demystified/ explains css locators in much more depth than I can in the space provided here.
Best approach: If you're using firefox download firebug, that will let you look at your html. Pres cmd+Shift+c and it'll open for you with an element highlighter. Find your html element, maybe it'll look something like this
<input type="submit" tabindex="110" value="Post Your Answer" id="submit-button">
Then you can find your element pretty simply
WebElement element = driver.findElement(By.cssSelector("input[id='submit-button']"))
Notice that we put the tagname first "input" followed by some kind of unique identifier in the brackets "input[id='submit-button']." For the most part this will cover 75% of all css locators you use. The other 25% require a little bit more tricky stuff covered in the link I placed at the top of the page.
You may ask "What kind of unique identifiers can I use besides id" well that is covered here: http://release.seleniumhq.org/selenium-remote-control/0.9.2/doc/dotnet/Selenium.html
Good luck starting out
EDIT
Well good luck finding your elements in the first place...If you need you can search elements by partial locator text like input[id*='submit']. Using that is helpful for dynamically generated elements, when you use the partial text as the part of the locator that doesn't vary from element to element.
You mentioned walking up the html tree perhaps I didn't see that when I first read the question. I think you hit the on issue at hand. Walking up the html tree isn't suggested as it makes your tests more fragile to html changes. It will also make your code unreadable in the long run as well. In general if your id's are missing or unpredictable I would suggest talking to proj. management about getting the developers to make code that can actually be automated (eg: getting identifiers implemented on critical elements). This will actually save both you and the developers alot of effort in the long run, and it will also increase the speed and reliability of your tests.
We can find the Submit Button using ID:
1.driver.findElement(By.id("submit-button"))
ID > NAME > CSS > XPATH

Is by.id better than by.tagname?

I was working on reading mails from gmail using webdriver and in between I hit upon this difference between By.id and By.tagname.
I am trying to get access to a "table" whose id is ":pg". So I could
Either use By.id(":pg")
OR use By.tagname("table") and search for an element with id :pg
Here is the code for both cases.
By.id:
WebDriver webDriver = new FirefoxDriver();
webDriver.manage().timeouts().implicitlyWait(5, TimeUnit.SECONDS);
webDriver = webDriver.switchTo().frame("canvas_frame");
WebElement table1 = webDriver.findElement(By.id(":pg"));`
Above code, I directly get the element which has id ":pg"
By.tagname:
WebDriver webDriver = new FirefoxDriver();
webDriver.manage().timeouts().implicitlyWait(5, TimeUnit.SECONDS);
List<WebElement> tables = webDriver.findElements(By.tagName("table"));
for(WebElement table2: tables){
String id = table2.getAttribute("id");
System.out.println("id: "+ id);
if(id != null && id.equals(":pg")){
System.out.println("FOUND IT!!!");
}
}
Above code, I find all elements with the tagname of table and then see which one has the id ":pg".
Both these code snippets are essentially doing the same but using different ways(By.id or By.tagname). However, the first snippet of code which uses By.id always succeeds while the second snippet of code which uses By.tagname fails almost always. (It will work with additional waiting however)
Why is this difference between By.id and By.tagname?
Thanks,
Chris.
The :pg element is not present on the page initially.
Using By.Tag, selenium will not wait for the :pg element.
Because By.Id example is more specific, selenium will continue checking if the :pg element exists until the implicit wait (5 seconds) times out.
By.Tag is not specific at all. On findElements(By.tagName("table"), Selenium will return an array of all the tables that are present immediately after the page loads. As the :pg element is not present yet, it will not be in the array.
To answer your question, yes it is better to use By.Id because:
1. It is more specific.
2. Saves lines of code
3. Forces selenium to wait for the element to exist.
It is better to use By.Id according to your question.
By.tag is not used for specific data, it actually will search and return an array of all the tables with the specified tag name. On the other hand using id you can get the appropriate output for identifying/locating element.
Go for tag only if id, name or class is not specified and the best way can be By.cssSelector if no element is found.
Thanks