Selenium (Java) unable to find element by visible link text - java

I've gotten one of the more frustrating Selenium problems.
I've got a table on a page, where one of the elements have a link. The link is called "Send brev".
<td data-e2e-selector="sakHendelser" id="sakHendelser_0" class="ng-star-inserted">
<saksnytt><!----><!----><!---->
<div class="hb-tekst--ingenBryting ng-star-inserted">
<!----><!----><!---->
<button class="hb-knapp hb-knapp--lenke hb-knapp--alignTeks hb-knapp-lenke-nopadding ng-star-inserted"
data-e2e-selector="saksnytt-link">
<i aria-hidden="true" class="fa fa-flag fa-envelope"></i>
<span class="hb-knapp-tekst">Send brev </span></button>
<!----><span aria-hidden="true" class="fa fa-info-circle ng-star-inserted"
id="reservert-info">
</span><!----><!----><!----></div><!---->
</saksnytt></td>
This has worked before, and I haven't found a reason for why it's stopped working now. But no matter how I try to find it, Selenium responds with
no such element: Unable to locate element: {"method":"xpath","selector":"//data-e2e-selector[contains(text(),'Send brev ')]"}
or similar-
I've tried the following:
Browser.Wait().until(presenceOfElementLocated(By.linkText(merknad + " ")));
This times out.
driver.findElement(By.linkText(merknad + " ")).click();
driver.findElement(By.partialLinkText(merknad + " ")).click();
driver.findElement(By.xpath("//data-e2e-selector[contains(text(),'" + "Send brev" +"')]"));
driver.findElement(By.xpath("//id[contains(text(),'" + "Send brev" +"')]"));
data-e2e-selector="sakHendelser" id="sakHendelser
I've also tried adding a space after the "v" in the link text, with no luck.
How can Selenium not find an element that is clearly visible and interactable like this?
Since the code is generated in Angular, and is more or less dynamic, I cannot create a tag for this specific element either, so I'm left with trying to find it by text. Which I cannot get to work.
Any ideas?
I AM able to click it with this code:
driver.findElement(By.xpath("//*[#id='sakHendelser_0']/saksnytt/div/button/span")).click();
But I want to be able to send the link text to the method instead of hardcoding the xpath like that.

LinkText and PartialLinkText will only work with text inside an A tag. You don't have that given your HTML so this will not work. Your only option to locate an element given the contained text is to use XPath.

The way you are using XPath by placing // before an attribute (such as //id or //data-e2e-selector) is not correct. These are element attributes, not tags.
The text Send brev is contained in a span element, so trying to locate it by querying on data-e2e-selector will not work -- that's also not a WebElement, it's an attribute on button.
Because you mention this item has some visible link text that you want to use as a parameter, I would query on only text and use a contains to work around any hidden whitespace:
driver.findElement(By.xpath("//span[contains(text(), 'Send brev')]")).click();
You can use link text as a parameter as such:
string linkText = "Send brev"
driver.findElement(By.xpath("//span[contains(text(), '" + linkText + "')]")).click();
You might have better luck clicking on the button itself though:
driver.findElement(By.xpath("//button[span[contains(text(), '" + linkText + "')]]")).click();

Try using normalize-space with xpath:
//span[normalize-space(text())='Send brev']

You need to take care of a couple of things as follows:
By.linkText() and By.partialLinkText() works only for <a> tags, where as the desired element is within a <span> tag.
data-e2e-selector and id are attributes of an WebElement but you have tried to use them as tagName.
The text Send brev is with in a <span> tag.
So identify the element with text as Send brev and moving ahead to interact with it you need to induce WebDriverWait for the elementToBeClickable() and you can use either of the following Locator Strategies:
cssSelector:
new WebDriverWait(driver, 20).until(ExpectedConditions.elementToBeClickable(By.cssSelector("button.hb-knapp.hb-knapp--lenke.hb-knapp--alignTeks.hb-knapp-lenke-nopadding.ng-star-inserted[data-e2e-selector='saksnytt-link'] span.hb-knapp-tekst"))).click();
xpath:
new WebDriverWait(driver, 20).until(ExpectedConditions.elementToBeClickable(By.xpath("//button[#class='hb-knapp hb-knapp--lenke hb-knapp--alignTeks hb-knapp-lenke-nopadding ng-star-inserted' and #data-e2e-selector='saksnytt-link']//span[#class='hb-knapp-tekst' and contains(., 'Send brev')]"))).click();

Related

Unable to locate an element even when the xpath is correct

i'm tried to select an element from an auto suggestion field but i got always an error saying that the element could not be found even that i'm sure my xpath is correct
here's my code :
wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//*[#class=\"ui-menu-item-with-icon ui-menu-item\"][1]")));
driver.findElement(By.xpath("//*[#class=\"ui-menu-item-with-icon ui-menu-item\"][1]")).click();
it should find //*#class=\"ui-menu-item-with-icon ui-menu-item\" which is the first suggestion albert cammus
here's the outerHtml
<li class="ui-menu-item-with-icon ui-menu-item" role="menuitem">
<a class="ui-corner-all" tabindex="-1">
<span class="item-icon"></span>
Albert Camus (SARCELLES)</a>
</li>"
Your XPath is more or less OK apart from using wildcard which may result into longer processing so you can go for li instead of *.
Another option is sticking to the <a> tag containing the text you would like to click using normalize-space() function something like:
//a[normalize-space()="Albert Camus (SARCELLES)"]
Also your popup may reside within an iframe so you might have to switch the webdriver context to the relevant iframe element.
Why don't you try linkText over Xpath ?
linkText is more stable then Xpath, there's no doubt about that.
Code :
wait.until(ExpectedConditions.visibilityOfElementLocated(By.partialLinkText("Albert Camus (SARCELLES)")));
I'm not very sure about spaces in your HTML, that's the reason why I have used partialLinkText

How to select a nested webelement in html?

I would like to retrieve a webelement out of a nested html path using either css selectors or xpath. My specific use case is that I would like to select the i element in the following snippet:
<td class="headerActionsTd" data-rolename="Speaker">
<div class="headerActions">
<span class="addNewParticipantSection">
<i class="icon fa fa-user-plus" title="Add New"></i>
</span>
How do I obtain the i webelement for this using either css selector or xpath?
Use this xpath: //td[#data-rolename='Speaker']//div//span//i[#title='Add New'] or
css : div.headerActions i
driver.findElement(By.cssSelector("div.headerActions i"));
for multiple elements :
List<WebElement> users = driver.findElements(By.xpath("//td[#data-rolename='Speaker']//div//span//i[#title='Add New']"));
A simple one would be this :
CSS_SELECTOR
i.icon.fa.fa-user-plus[title='Add New']
Note that, if there is multiple element with this css selector, then you have this facility to differentiate between them:
:first-child
:nth-child(n)
:nth-last-child(n)
More can be found at this link
XPATH : would be :
//td[#data-rolename='Speaker']/descendant::span[#class='addNewParticipantSection']/i
Hope that helps.
Since you said data-role only changes in the comment of the other person, here is the xpath you can use
"//td[#data-role='Speaker']//i"
Or
"//td[#data-role='Speaker']/div/span/i"
Another option is that you can attempt to locate elements inside other elements. For example, you could store the addNewParticipantSection div in a WebElement, then use that WebElement's findElement method to locate the i element within it. Like so:
WebElement section = driver.findElement(By.className("addNewParticipantSection"));
WebElement icon = section.findElement(By.tagName("i"));
icon.click();

Clicking on Image Link with Selenium webdriver java

I have looked at the answers to similar questions and it seems like the code that I have should work but I get "Cannot click on element" error when the code invokes click on the web element.
Following is html markup segment
<div class="x-tree-node-item">
<a title="Manage Users" class="sidenavmenu_unselected" id="m-22" onclick="toggleMenu('22', '');" href="#">
<img title="" align="bottom" id="mi-22" alt="" src="ca/images/arrow.png" border="0">Manage Users
</a>
<div style="margin-left: 1em;">
<ul class="submenu-show" id="mp-22" style="height: auto; display: none;">
<li>
...
</li>
</ul>
</div>
Java code to locate the link is:
By xpath=By.xpath("//a[contains(#title,'Manage Users')]/img");
WebElement manageUsers = (new WebDriverWait(driver, 10))
.until(ExpectedConditions.presenceOfElementLocated(xpath));
manageUsers.click();
It finds the element but I get error:
org.openqa.selenium.ElementNotInteractableException: Cannot click on element
The ids are generated dynamically so we can't find by id and image source is used by multiple links.
Thank you for your help.
* Update *
The problem was solved with help from JeffC and Xwris. JeffC's last comment showed that there are multiple nodes being found. So, I added following code:
List<WebElement> manageUserImages=driver.findElements(xpath);
for (WebElement manageUserImage:manageUserImages) {
if (manageUserImage.isDisplayed()) {
manageUserImage.click();
}
}
Since there is only element displayed at one time with "Manage Users" as title, this finds the correct elements and delivers the desired results.
#JeffC, if you can post an answer with your comment, we can mark that answer as the correct answer.
Thanks again to everyone who helped.
It looks your xpath is wrong.
Personally I would start from the div and the drill down to the actual < a > tag.
In some cases where your web-element sits under a < li > tag, I would go even further up the tree and select a div which is not hidden.
i.e you instruct it to search for under the specific < div >
Who told you you can select only by id? You can use anything! :)
This should work.
//div[#class='x-tree-node-item']//a[#title='Manage Users']
This should work as well. Correct usage of 'contains' is as follows:
//div[#class='x-tree-node-item']//a[text()[contains(.,'Manage Users')]]
Hope this helps!
PS. notice that text contains is case-sensitive and will match partial text.
So if you searched for:
//a[text()[contains(.,'age User')]]
it will still be a successful match!
Update after OP's comments:
You don't actually need xpath helper. You just hit F12 in your browser and then CTRL+f so you open a search field at the bottom. Please see my example on how I locate the title of your question with partial text match ('Image').
Also notice next to xpath where it says 1 of 1 (meaning that our element is unique). Try to do the same for your case. I suspect that you need to go higher up the tree and start from an earlier < div > so you can locate the rest.
Leave off the "/img" part of your locator. You want to click the anchor (a) not the image itself.
By xpath=By.xpath("//a[contains(#title,'Manage Users')]");
WebElement manageUsers = (new WebDriverWait(driver, 10))
.until(ExpectedConditions.presenceOfElementLocated(xpath));
manageUsers.click();
Alternatively, the locator could be: //a[#id='m-22']

Selenium, JAVA - how to find such element?

Do you know how to find and click at an element like this:
<div class="offer ctrlOpenOfferInfo">
<a class="linkOffer" href="offer_view.html?id=1007"/>
<p class="photo">
<p class="name">New offer</p>
<p class="price">123</p>
<div class="rate ctrlViewRateOffer" data-value="0.0000">
<p class="date"/>
<div class="hide info">
<div class="bgInfo"/>
using Selenium WebDriver and using the name of the element as there are few very similiar elements on the page?
Here's what I've tired so far:
WebDriverWait wait = new WebDriverWait(driver, 30);
wait.until(ExpectedConditions.invisibilityOfElementLocated(By.xpath("//*[text()='New offer']")));
wait.until(ExpectedConditions.elementToBeClickable(By.xpath(".//*[#id='formDevelopmentElementAdd'][text()='New offer']")));
driver.findElement(By.xpath(".//*[#id='formDevelopmentElementAdd']/div/p[2][text()='New offer']")).click();
or:
driver.findElement(By.xpath("//p[#class='name'][text()='New offer']")).click();
or:
String address = driver.findElement(By.xpath("//*[contains(text(), 'New offer') and #class='name']")).getAttribute("href");
driver.get(baseUrl + address);
or:
driver.findElement(By.xpath("//a[Text()='New offer']")).click();
I've tried these with text, class, xpath...
Assuming you want to click the p tag containing New offer:
I would think this element is not inside an iframe. If so, you must use driver.switchTo().frame("name or xpath or css for frame locator"); first before start looking for element.
Now, how can you find that element. Consider the following options:
Using xpath text based search
//p[.='New offer']
//to be more precise you can do
//p[#classs='name'][.='New offer']
You can use By.className('name') to identify that element even though that name does not look like unique to me
Using cssSelector
.name
using nth-child() function of cssSelector
.offer.ctrlOpenOfferInfo>a>p:nth-child(2)

How to access div ids using xpath?[selenium webdriver]

<div class="col-lg-3 col-sm-4 col-xs-6">
<div class="logo">..................</div> </div>
logo is inner div.
I need to acces col-lg-3 col... div content using xpath.
I did this in java:
WebElement mydiv = driver.findElement(By.className("col-lg-3 ")) ;
but it does not work - because it has spaces in the name.
How do I access this using xpath?
In CSS, you could access it like this:
driver.findElement(By.cssSelector(".col-lg-3 .logo"));
Since you asked, in XPath, it could be:
driver.findElement(By.xpath("//div[contains(#class, 'col-lg-3')]/div[contains(#class, 'logo')]")
As you can see, the CSS selector is much simpler.
To see xpath, I suggest to install Firebug and FirePath; those extensions are Firefox.
Example:
Can you see the image? xpath
Imagine that you don't have id neither name locators or you need to use xpath
Open Firefox.
Click on "Firebug". (#1)
There a panel.
Click on "Click an element in the page to inspect" icon (#2)
Click on "FirePath" tab. (#3)
Select the element that you wish (#4)
It displays the xpath into textbox. (#5)
So, you need to add this line:
driver.findElement(By.xpath("html/body/form/fieldset/p[1]/input"));

Categories