how to use selenium wait.until with anchor element in java - c#

i have selenium project written in c# and i want to migrate it to java, but i have a problem that i could not solve by myself.
lets say i have a webElement elem1 and i want to find another element elem2 using elem1 as the anchor.
so in java i can do it like that:
WebElement elem1 = wait.until(ExpectedConditions.presenceOfElementLocated(By.cssSelector("div.uiContextualLayer.uiContextualLayerBelowLeft"))) ;
WebElement elem2 = elem1.findElement(By.tagName("li"));
now, my problem starts when i want to do the same but with wait.until() for elem2. the thing is that elem1 is always appear in the DOM, but elem2 will appear in the DOM only after some time (it depends on some code that is not relevant for this issue), so using the above code will throw an exception.
in c# i used lambda expression and it was very simple:
IWebElement elem1 = wait.Until((d) => { return d.FindElement(By.CssSelector("div.uiContextualLayer.uiContextualLayerBelowLeft")); });
IWebElement elem2= wait.Until((d) => { return **elem1**.FindElement(By.TagName("li")); });
in java i cant find a way to do the wait.until AND use elem1 as the anchor for the findElement function.
here is a sample of the html i'm working on:
<div class="uiContextualLayer uiContextualLayerBelowLeft">
<div style="width: 240px;">
<div class="uiTypeaheadView uiContextualTypeaheadView">
<ul id="typeahead_list_u_jsonp_2_2" class="search" role="listbox">
<li id="js_2" class="user" aria-label="whatEver" role="option" aria-selected="false">
…
</li>
</ul>
</div>
</div>
</div>
</div>
</div>
i don't want to get all the elements that has the "li" tagName into a list and than go over each element to find the element i need. i'm pretty sure i'm missing something which is very basic, and would appreciate any suggestion/explanation.

The most Java-style way is to have methods that return locators and write your own inline ExpectedCondition that uses these methods.
public By getElem1Locator() {
return By.cssSelector(....);
}
public By getElem2Locator() {
return By.tagName(....);
}
...
WebElement elem2 = wait.until(new ExpectedCondition<WebElement>() {
public WebElement apply(WebDriver driver) {
try {
return driver.findElement(getElem1Locator()).findElement(getElem2Locator());
} catch (NoSuchElementException e) {
return null;
}
});
...
The reason why we want to use locators and not final WebElement instances is that if DOM changes while we are waiting, the WebElement can become stale.
A quick and dirty solution is to use a single Xpath selector for the second element
WebElement elem2 = wait.until(ExpectedConditions.presenceOfElementLocated(By.xpath("//div[contains(concat(' ',normalize-space(#class),' '),' uiContextualLayer ') and contains(concat(' ',normalize-space(#class),' '),' uiContextualLayerBelowLeft ')]//li"));
You should also take a look at Page Factory

Related

Write someting in a <input> tag in html with selenium c# doesn't work

I wanted to fill in a input from website with html.
THis how the part of the website (https://account.protonmail.com/signup?language=de) looks like:
<div class="flex-item-fluid">
<input autocomplete="username" autocapitalize="off" autocorrect="off" spellcheck="false" aria-invalid="false" id="username" aria-describedby="id-1" class="w100 inputform-field" value="">
</div>
This my c# selenium part:
var elem = driver.FindElement(By.XPath("//*[#id='username']")).SendKeys("test");
// I also tried this:
var elem = driver.FindElement(By.XPath("//input[#id='username']")).SendKeys("test");
I hope somebody can help me.
The username field is in iframe
use the below xpath to switch to iframe first then you can continue with the rest of the code:
//iframe[#src]
something like this :
IWebElement iframe = driver.FindElement(By.Xpath("//iframe[#src]"));
driver.SwitchTo().Frame(iframe);
Also, I see multiple elements for username field. Always remember we should give more precedence to css_selector over xpath
Username field can be locate with this css:
body.color-norm.bg-norm input[id='username']
so in code something like this :
var elem = driver.FindElement(By.CssSelector("body.color-norm.bg-norm input[id='username']")).SendKeys("test");
var pass = driver.FindElement(By.CssSelector("input[id='password']")).SendKeys("password here");
The element you are looking resides in an iframe so first switch the frame.
xPath for iframe:
//iframe[contains(#src,'Name=username')]
Then find the element using below xPath,
//input[#id='username']
Completed code:
driver.switchTo().frame(driver.findElement(By.xpath("//iframe[contains(#src,'Name=username')]")));
var elem = driver.FindElement(By.XPath("//*[#id='username']")).SendKeys("test");
you can try this
var elem = driver.FindElement(By.CssSelector(".w100.inputform-field")).SendKeys("")
Here we search by class name, not by input name. Good Luck.
if it worked for you. USEFUL

Unable to click on Done link. Need help Finding Element or Xpath

I need help getting the xpath or link from this html
<div class="g-btn g-hyperlink " id="s99AB6D3E3FBF404BA01A344322BFA0EE263_2_1"><a onmousemove="window.status='';" onmouseout="window.status='';" name="" href="javascript:;" id="s99AB6D3E3FBF404BA01A344322BFA0EE263_2_1_anchorId" onfocus="DCT.Util.setFocusField('s99AB6D3E3FBF404BA01A344322BFA0EE263_2_1_anchorId');" onclick="DCT.Util.customOnClick(this,"",{InsertTextAtCursorAction:0,showReminderMessages:0,skipScrollToTop:0});DCT.Util.setFocusField('s99AB6D3E3FBF404BA01A344322BFA0EE263_2_1_anchorId');DCT.Util.processInterviewButtonAnchor('a_s99AB6D3E3FBF404BA01A344322BFA0EE263_2_1_div',"","");" onblur=""><div class="g-btn-l"></div><div class="g-btn-m"><span class="g-btn-text" ext:qtip="" data-tip="" fieldref="Done" xmlns:ext="urn:ext">Cancel</span></div><div class="g-btn-r"></div></a></div>
I'm trying to click in a link but I'm having a hard time getting the xpath .
I have try this
Driver.FindElement(By.XPath(#"onclick,s99AB6D3E3FBF404BA01A344322BFA0EE263_2_1_anchorId")).Click();
}
and this
{Driver.FindElement(By.LinkText("Done")).Click();}
When I do this {
Driver.FindElement(By.XPath(#"onclick,s99AB6D3E3FBF404BA01A344322BFA0EE263_2_1_anchorId")).Click();
I get this error
Unable to locate an element with the xpath expression onclick,s99AB6D3E3FBF404BA01A344322BFA0EE263_2_1_anchorId because of the following error:
SyntaxError: Failed to execute 'evaluate' on 'Document': The string 'onclick,s99AB6D3E3FBF404BA01A344322BFA0EE263_2_1_anchorId' is not a valid
XPath expression.
When I try this
{
Driver.FindElement(By.LinkText("Done")).Click();}
I get this error
OpenQA.Selenium.ElementClickInterceptedException: element click intercepted: Element <a onmousemove="window.status='';" onmouseout="window.status='';" name="" href="javascript:;" id="sF6195287351B43A7BC7610F2A63626FA263_2_1_anchorId" onfocus="DCT.Util.setFocusField('sF6195287351B43A7BC7610F2A63626FA263_2_1_anchorId');" onclick="DCT.Util.customOnClick(this,"",{InsertTextAtCursorAction:0,showReminderMessages:0,skipScrollToTop:0});DCT.Util.setFocusField('sF6195287351B43A7BC7610F2A63626FA263_2_1_anchorId');DCT.Util.processInterviewButtonAnchor('a_sF6195287351B43A7BC7610F2A63626FA263_2_1_div',"","");" onblur="">...</a> is not clickable at point (310, 605). Other element would receive the click: <div id="s_p900F519A82CE4AE6BA9F48EAF71BBF95144_3_1" class="downLayout x_ statusBar">...</div>
UPDATE
Added WebDriverWait
You can try following xpath:
//*[#class='g-btn-text' and text()='Cancel']
WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(20));
IWebElement elmt = wait.Until(ExpectedConditions.ElementToBeClickable(By.XPath("//*[#class='g-btn-text' and text()='Cancel']"));
elmt.Click();
Use below Xpath:
//div[#class='g-btn g-hyperlink ']//span[#class='g-btn-text' and contains(.,'Cancel')]
So your code will be like:
WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(5));
IWebElement button = wait.Until(ExpectedConditions.ElementToBeClickable(By.XPath("//div[#class='g-btn g-hyperlink ']//span[#class='g-btn-text' and contains(.,'Cancel')]"));
button.Click();
Your locator is not correct, if you really want to use the onclick attribute you should amend it to
mention <div> tag
use XPath contains() function:
Driver.FindElement(By.XPath("//div[contains(#onclick,'s99AB6D3E3FBF404BA01A344322BFA0EE263_2_1_anchorId')]")).Click();
More information:
XPath Tutorial
XPath Axes
XPath Operators & Functions

In ASP.net, what kind of IF statement could I use to hide a div if the image inside it matches the current page URL?

This is within Sitefinity if that matters, and I am really new at ASP.NET and C#.
I have an image-based navigation element at the bottom of a page that links to different articles using the same template. There are 5 articles, and I would like the link to the active page/article to be hidden so there is a grid of 4 image links.
Here's a screenshot:
https://i.imgur.com/PG2Sfpo.png
Here is the code behind it:
#{
string navTitle = string.Empty;
string url = string.Empty;
if (Model.CurrentSiteMapNode != null && Model.CurrentSiteMapNode.ParentNode != null)
{
if (Model.CurrentSiteMapNode.Title == "Home")
{
navTitle = Model.CurrentSiteMapNode.ParentNode.Title;
}
else
{
navTitle = Model.CurrentSiteMapNode.Title;
}
url = Model.CurrentSiteMapNode.ParentNode.Url;
}
}
<div class="foundation-stories-container">
#foreach (var node in Model.Nodes)
{
#RenderRootLevelNode(node);
}
</div>
#*Here is specified the rendering for the root level*#
#helper RenderRootLevelNode(NodeViewModel node)
{
string[] thisPage = (node.Url).Split('/');
string thisImage = thisPage[4] + ".jpg";
<a href="#node.Url" target="#node.LinkTarget">
<div class="foundation-story-block">
<div class="hovereffect">
<img src="[OUR WEBSITE URL]/stories/#thisImage" class="img-fluid">
<div class="overlay">
<h2>#node.Title</h2>
</div>
</div>
</div>
</a>
}
So we're already getting the page URL and image file name
string[] thisPage = (node.Url).Split('/');
string thisImage = thisPage[4] + ".jpg";
Is this as easy as doing the following?
if (thisImage = thisPage)
{
foundation-story-block.AddClassToHtmlControl("hide")
}
Seems easy enough, but I don't know where to start.
I'm better at Javascript, so I do have a JS solution in place for this already, but I'd really like to find a cleaner way to do it.
<script type="text/javascript">
$(document).ready(function() {
var active = window.location.pathname.split("/").pop()
var name = active;
name = name.replace(/-/g, ' ');
jQuery.expr[":"].Contains = jQuery.expr.createPseudo(function(arg) {
return function( elem ) {
return jQuery(elem).text().toUpperCase().indexOf(arg.toUpperCase()) >=
0;
};
});
$("h2:Contains('" + name + "')").closest(".foundation-story-block").addClass("hide");
});
</script>
This exists on the main template page.
Gets the last part of the URL
Sets that as a variable called "name"
Changes the dash to a space if there is one (most of the pages are associated with names so it's like /first-last)
Then it goes and looks at the which is where the title of the page lives, and if it equals the "name" variable, the ".hide" class is added to the block.
Thanks for any help anyone can provide.
You could bind a click event to your elements with the foundation-story-block class. The reason I use .on instead of .click is because when using UpdatePanels the click event won't fire after an UpdatePanel has it's update event triggered - you might encounter a similar problem with your dynamic binding so I used .on to avoid this.
$(".foundation-story-block").on("click", function() {
// Remove the "hide" class from any elements that have it applied
$.each($(".foundation-story-block.hide"), function(index, value) {
// Remove the class using the "this" context from the anonymous function
$(this).removeClass("hide");
});
// Add the "hide" class to the element that was clicked
$(this).addClass("hide");
});
I haven't run this though an IDE so it might not be 100% correct but it will put you on the correct path.
It is possible, yes. Here is how:
...
#{
var hiddenClass = thisImage == thisPage ? "hide" : string.Empty;
}
<div class="foundation-story-block #hiddenClass">
<div class="hovereffect">
<img src="[OUR WEBSITE URL]/stories/#thisImage" class="img-fluid">
<div class="overlay">
<h2>#node.Title</h2>
</div>
</div>
</div>

How could I get the text is inside of a span which has no ID but a class

I was testing WebBrowser, but there's no method to getElemments by class, but by tag.
I have something like this.
html:
<div class="Justnames">
<span class="name">Georgia</span>
</div>
So i'd like to get the string "Georgia", which is inside of that span.
I tried:
Var example = Nav.Document.GetElementsByTagName("span");
But it return null, and I've no idea why.
Sorry my english and thanks a lot of the help! :)
This may help:
var elementCollection = default(HtmlElementCollection);
elementCollection = webBrowser1.Document.GetElementsByTagName("span");
foreach (var element in elementCollection)
{
if (element.OuterHtml.Contains("name"))
// we reach here, we get <span class="example"
}
Or:
foreach (var element in elementCollection)
{
if (element.GetAttribute("className") == "name")
// we reach here, we get <span class="example"
}
You can do this using jquery :
var test = $(".name").text();
alert(test):
Because you tagged "C#" and ".net" i assume you have a aspx page and try to access it from server code. To access it from server side you have to add the runat="server" tag to the span:
<span class="name" runat="server">Georgia</span>
Otherwise you only can access it from client side (JavaScript)

Retrieving Text between <span>Text</span> in Selenium C#

I am facing problem in retrieving Subject title of a mail from Unread mails using Selenium webdriver-C#.
Here's the HTML code :
<div class="ae4 UI UJ" gh="tl">
<div class="Cp">
<div>
<table id=":8e" class="F cf zt" cellpadding="0">
<colgroup>
<tbody>
<tr id=":8d" class="zA zE">
<td class="PF xY"></td>
<td id=":8c" class="oZ-x3 xY" style="">
<td class="apU xY">
<td class="WA xY">
<td class="yX xY ">
<td id=":87" class="xY " role="link" tabindex="0">
<div class="xS">
<div class="xT">
<div id=":86" class="yi">
<div class="y6">
**<span id=":85">
<b>hi</b>
</span>**
<span class="y2">
</div>
</div>
</div>
</td>
<td class="yf xY "> </td>
<td class="xW xY ">
</tr>
I am able to print 'emailSenderName' in console but unable to print 'text' (subject line i.e. "hi" in this case) as it is between span tags. Here's my code.
//Try to Retrieve mail Senders name and Subject
IWebElement tbl_UM = d1.FindElement(By.ClassName("Cp")).FindElement(By.ClassName("F"));
IList<IWebElement> tr_ListUM = tbl_UM.FindElements(By.ClassName("zE"));
Console.WriteLine("NUMBER OF ROWS IN THIS TABLE = " + tr_ListUM.Count());
foreach (IWebElement trElement in tr_ListUM)
{
IList<IWebElement> td_ListUM = trElement.FindElements(By.TagName("td"));
Console.WriteLine("NUMBER OF COLUMNS=" + td_ListUM.Count());
string emailSenderName = td_ListUM[4].FindElement(By.ClassName("yW")).FindElement(By.ClassName("zF")).GetAttribute("name");
Console.WriteLine(emailSenderName);
string text = td_ListUM[5].FindElement(By.ClassName("y6")).FindElement(By.TagName("span")).FindElement(By.TagName("b")).Text;
Console.WriteLine(text);
}
I had also tried by directly selecting the Text from tag of 5th Column (td), which contains the subject text (in my case), but no results.
I might went wrong somewhere or may be there is some other way of doing it.
Please suggest, Thanks in advance :)
The 'getText' method available in the Java implementation of Selenium Web Driver seems to do a better job than the equivalent 'Text' property available in C#.
I found a way of achieving the same end which, although somewhat convoluted, works well:
public static string GetInnerHtml(this IWebElement element)
{
var remoteWebDriver = (RemoteWebElement)element;
var javaScriptExecutor = (IJavaScriptExecutor) remoteWebDriver.WrappedDriver;
var innerHtml = javaScriptExecutor.ExecuteScript("return arguments[0].innerHTML;", element).ToString();
return innerHtml;
}
It works by passing an IWebElement as a parameter to some JavaScript executing in the Browser, which treats it just like a normal DOM element. You can then access properties on it such as 'innerHTML'.
I've only tested this in Google Chrome but I see no reason why this shouldn't work in other browsers.
Using GetAttribute("textContent") instead of Text() did the trick for me.
Driver.FindElement(By.CssSelector("ul.list span")).GetAttribute("textContent")
Try this
findElement(By.cssSelector("div.y6>span>b")).getText();
I had the same problem. Worked on PhantomJS. The solution is to get the value using GetAttribute("textContent"):
Driver.FindElementsByXPath("SomexPath").GetAttribute("textContent");
Probably too late but could be helpful for someone.
IWebElement spanText= driver.FindElement(By.XPath("//span[contains(text(), 'TEXT TO LOOK FOR')]"));
spanText.Click();
IWebElement spanParent= driver.FindElement(By.XPath("//span[contains(text(), 'TEXT TO LOOK FOR')]/ancestor::li"));
spanParent.FindElement(By.XPath(".//a[contains(text(), 'SIBLING LINK TEXT')]")).Click();
bonus content here to look for siblings of this text
once the span element is found, look for siblings by starting from parent. I am looking for an anchor link here. The dot at the start of XPath means you start looking from the element spanParent
<li>
<span> TEXT TO LOOK FOR </span>
<a>SIBLING LINK TEXT</a>
</li>
This worked for me in Visual Studio 2017 Unit test project. I'm trying to find the search result from a typeahead control.
IWebElement searchBox = this.WebDriver.FindElement(By.Id("searchEntry"));
searchBox.SendKeys(searchPhrase);
System.Threading.Thread.Sleep(3000);
IList<IWebElement> results = this.WebDriver.FindElements(By.CssSelector(".tt-suggestion.tt-selectable"));
if (results.Count > 1)
{
searchResult = results[1].FindElement(By.TagName("span")).GetAttribute("textContent");
}

Categories