Getting element in WebDriver, not by xpath - java

I am using webdriver for test automation on site which code is auto-generated probably in GWT.
All id's are in form like "x-auto-4009" which is not to reliable way of getting to elements.
I have page with something like form.
It's like
Label name | <---- Input ---->
Label name | <---- Input ---->
Label name | <---- Input ---->
Each new line is coded as new table in html.
Can you tell me what is the best way of getting to specific Input in more generic way?
I wrote a method that takes a label name and then it finds all elements by tag TR. Next it get's theese allRows and scans them for labelname. If it's found then i find within that row elements with tag input and that is my goal. It works fine but it takes some time to do find all those elements and loop through them.
I don't want to use xpath or locating elements through those fragile id's.
Can you recommend me any other way of doing that?
Thanks in advance,
regards.

If you can't use xpath, I think the only other way to do this would be to alter the code for the page.
It is possible to set these GWT ID values so that they have a clearer and more consistent value. See: https://developers.google.com/web-toolkit/doc/latest/DevGuideUiCss#widgets.
Less appealing is the option to give each input a class or name attribute by which you'd identify them, and then search By.class() or By.name().

Why not xpath? That's the most direct way to do it. Your existing approach is the slower alternative.
Use this xpath selection: <label> with text containing the "name", then its parent <td>, then its parent <tr>, then the first <input> in that row:
WebElement input = driver.findElement(By.xpath(
"//label[contains(text(), '"+name+"')]/../../input"
));
I have not tested this. Might have to adjust to your table structure, too.

Related

How do I select an iframe using java selenium if it doesn't have name or id

I'm trying to select an iframe in selenium java but the element doesn't have a Name or Id attribute. How should I get it? (I want to use the switchTo to switch to it)
The website I am trying to get the iframe from is jklm.fun and the xpath of the iframe is
"/html/body/div[2]/div[4]/div[1]/iframe"
(you need to be in a game for the iframe to exist)
Same way you select anything, based on their tree position: regular CSS selector. You query-select body div div div iframe and you're almost certainly going to get it (unless you have lots of three-deep divs with iframes in them, in which case what on earth is going on on that webpage =), but if that still gives you multiple options, narrow the query selector using tactical :nth-child(...) pseudo-classes.
I would not suggest to go with absolute xpath :
/html/body/div[2]/div[4]/div[1]/iframe
rather have a relative xpath.
Having said that, as far as switching is concerned, there are multiple ways:
Using driver.switchTo()
This basically provides 3 overloaded methods: -
with index :-
driver.switchTo().frame(index)
with name or ID:-
driver.switchTo().frame(nameOrId)
with web element
driver.switchTo().frame(frameElement)
so out of these 3, we can easily use 2 of them since id or name isn't available in your case.
Using the index:
driver.switchTo().frame("here pass the index if you know. ")
Using frame web element:
driver.switchTo().frame(driver.findElement(By.xpath("/html/body/div[2]/div[4]/div[1]/iframe")))
this should work for you.
The other way we have is with Explicit waits:
new WebDriverWait(driver, 20).until(ExpectedConditions.frameToBeAvailableAndSwitchToIt(By.xpath("/html/body/div[2]/div[4]/div[1]/iframe")));
This is more convenient, way to switch to iframe in angular or react based Application.

Selenium search text in a page section and click on a button inside it

I am using Webdriver and Java. My problem is that the page is splitted in 2 sections, both with the same name //div[#class='sg-content-box sg-content-box--spaced']
I want to click on the button Aprobă near the user David2211 (his answer can appear first or second)
My problem is that i don't know how to do click on the button in that specific area, for that specific username
For things like this, you have to use XPath since we are looking for an element that contains specific text. In this case, we will be looking for an element that contains the username 'David2211' and then a button that contains the text 'Aprobă'. I would assume that you will use this code more than once using different usernames so I would put this in a function so that it's easier to reuse.
The function
public void approveAnswerByUsername(String username)
{
driver.findElement(By.xpath("//a[contains(.,'" + username
+ "')]/ancestor::div[contains(#class, 'js-answer-element')]//div[contains(#class,'js-approve-button-text')][contains(.,'Aprobă')]")).click();
}
and you call it like
approveAnswerByUsername("David2211");
This XPath is rather large and complicated but it looks for an A tag that contains the specified username, goes up the DOM to find a parent DIV that encloses the entire answer and then navigates back down the DOM to find a DIV that contains the 'Aprobă' text.
Try Below xpath to locate the same element
Here you have to pass the user's name whose button you wants to click
//li/a[contains(.,'David2211')]/../../../preceding-sibling::div//button[#title='Aprobă']
The only thing specific to your button is indeed the username. I would suggest to get the xpath of the username's node, and then try to get its button from the parent's node using the xpath :
//{username's xpath}/parent::div[#class='sg-content-box sg-content-box--spaced']/{button's xpath}
It seems quite barbaric but that's the only way I see.
A challenging xpath after many days. Thanks for asking this question. Try this below xpath.
"//li/a[contains(text(),'DemonBolt')]/ancestor::div[#class='sg-content-box sg-content-box--spaced']//div[#class='sg-label__text js-approve-button-text']"
or
"//li/a[contains(text(),'DemonBolt')]/ancestor::div[#class='‌​sg-content-box sg-content-box--spaced']//div[contains(text(),'Aprobă')]"
Just change the text DemonBolt with the name whom you need to approve.
Hope this helps. Thanks.
Here is the Answer to your Question:
To click on the button Aprobă near the user David2211 (his answer can appear anywhere) you can use the following code block:
JavascriptExecutor je = (JavascriptExecutor)driver;
WebElement element = driver.findElement(By.xpath("//a[contains(text(),'David2211')]//preceding::button[2]/div/div[contains(text(),'Aproba')]"));
je.executeScript("arguments[0].scrollIntoView(true);",element);
element.click();
Let me know if this Answers your Question.

Java Selenium - How to interact with id-less/class-less element?

I'm trying to interact with a button on a page. Linktext and xpath do not work, there are no classes or combinations of selecting elements and looping through them I can find that work.
Here is the screen shot of the code I'm trying to do a .click()
Please help me how do i achieve the same ?
I think you have 2 options as below. I simplified your example HTML code to smoke test these queries:
Select an element based on its content. The drawback is of course that as soon as "Historical Scans" label changes to something else your query will stop working.
//nav[#id='secondaryNav']//ul[contains(#class, "menu")]//a[normalize-space(.)="Historical Scans"]
(working example on xpath tester http://xpather.com/dqZ7UWvz)
Select an element based on the position on the list. The downside is that it will stop working once this element changes its position.
//nav[#id='secondaryNav']//ul[contains(#class, "menu")]/li[3]/a
(http://xpather.com/rgexHKBB)
Based on my experience you should not rely on any other attributes or elements. Ideally, the best option would be to add ids/classes. Please let us know if this solves your problem.

Unable to retrieve Textbox Value In Selenium Testing

I am new to Selenium testing, I am trying to put the value into the textbox with the help of xpath, name & id. (java using eclipse IDE):
driver.findElement(By.xpath(".//* [#id='txtEmpDepAddressLine1']")).sendKeys("2nd Main")
driver.findElement(By.xpath(".//*[#id='txtEmpDepAddressLine2']")).sendKeys("Bangalore");
While running, textbox is not retrieve the from the above code. Can anyone help me out to solve this problem?
Use By.id instead By.xpath
If you insist xpath then:
Start with: // instead: .//
Make sure the id value is unique on page.
if using xpath in some browsers id or ID makes differnce.
It is difficult to say without the HTML, but I'd suggest a few things:
Open your page, go to the Google Chrome DevTools console, and verify you can locate the element using your xpath. So you'd type:
$x("//* [#id='txtEmpDepAddressLine1']")
and verify the text box is located.
If the sendKeys isn't working on the element at that id, I'd wonder if it is not on the text field itself, but on a containing table or something like that. Make sure the element located by the id is the input, so the sendKeys will work.
By
In the text box it is fetching the value but it can't able not store
in the text box field
do you mean you can see selenium typing those values into the textbox and then the values disappear?
If that is what is happening, it is possible there is some javascript running on the page while selenium is entering the values in the textbox. you can try to put a wait before selenium enters the value. If waiting resolves the issue, you will need to write a method to detect when the javascript is done.

Is it possible to enter a text in a textbox without specific Element ID

Im doing a test that enter text in the textbox but it dont have specific ID so everytime i run the test it will change. im using selenium webdriver in java please help
The following can work. You can google for them and see how they work.
driver.findElement(By.id("id"));
driver.findElement(By.cssSelector("cssSelector"));
driver.findElement(By.name("name"));
driver.findElement(By.linkText("linkText"));
driver.findElement(By.partialLinkText("partialLinkText"));
driver.findElement(By.className("className"));
driver.findElement(By.xpath("xpath"));
I am sure some of them will be useful. Please let me know if you want more info.
The easiness of using them is in the order which i have mentioned.
What means doesn't have a specific ID?If id at least partially remains the same you can use the CSS locator
driver.findElement(By.cssLocator("input[id*=somePartWhichNotChange]"));
//* star means contains
if not, then you can use cssSelector to get to your element like "body table input" or use xpath as a last resort.

Categories