How to Identify this element using Selenium Webdriver - c#

I have tried finding the element by Id, XPath, and CssSelector but have not had any luck. The test times out while looking for the element.
<div xmlns="http://www.w3.org/1999/xhtml" id="HyperlinkBetaSentry"
style="top:0px;left:521px;height:24px;width:70px;cursor:pointer;text-align:center"
class="DashboardHyperlink"><a target="_blank"
href="https://salsa.sentry.com/SalsaDataSentry/wafForm.aspx?__sso=1234567890" style="color:#e6e7e8;vertical-align:middle;text-decoration:none">Beta Sentry</a></div>
I have tried:
var title = Driver.Instance.FindElement(By.CssSelector("#HyperlinkBetaSentry"));
var title = Driver.Instance.FindElement(By.Xpath("//*[#id='HyperlinkBetaSentry']"));
var title = Driver.Instance.FindElement(By.Id("HyperlinkBetaSentry"));

I would think By.Id should be working. Usually when this happens it's because the code looking for the element is executed before the element exists (e.g. the DOM isn't fully loaded, or some Javascript changed the DOM, or an Ajax request, etc.)
As a test to confirm. Set a break point in your code just before looking for the element. Make sure the element does in fact exist as you expect, then step through the code that tries to find it. Chances are it'll find it.
The only other thing that sometimes causes this is that you're looking into a different frame than where your element is.

There are multiple issues that can cause this.
Pass the click to a tag
var title = Driver.Instance.FindElement(By.CssSelector("#HyperlinkBetaSentry>a"));
Element Load time
Duplicate ids
In case 2: You can define some explicit wait for the element to be visible.
WebElement myDynamicElement = (new WebDriverWait(driver, 10))
.until(ExpectedConditions.presenceOfElementLocated(By.id("YourID")));
See here for explanation.
In case 3: You might want to use a text base search using xpath or css with multiple attributes.
.//*[.='Beta Sentry']

Related

How to use wildcards in CssSelector when finding an element through Selenium?

I have an issue where the CssSelector I am using has a GUID in it that changes every time and therefore the tests will only ever pass once. Is there a wildcard I can use in the CssSelector that will help me get round this? Consider the following code...
IWebElement PersonalPhone = Driver.driver.FindElement(By.CssSelector("# Grid365e0689-dccb-695f-97af-dc29187d4e1d-id-cell-0-7 > a"));
PersonalPhone.Click();
I would like the above code to locate the element via the CssSelector using a wildcard so that I can remove the GUID part of the selector and only find the element based on the last part 'id-cell-0-7' and then click on the element.
I am using Selenium WebDriver(Chrome) written in C#
Any ideas?
You can use partial id with contains *=
IWebElement PersonalPhone = Driver.driver.FindElement(By.CssSelector("[id*='id-cell-0-7'] > a"));
Or end with $=
IWebElement PersonalPhone = Driver.driver.FindElement(By.CssSelector("[id$='id-cell-0-7'] > a"));
The value of the id attribute looks dynamic to me so as an alternative you can use the following css-selectors:
IWebElement PersonalPhone = Driver.driver.FindElement(By.CssSelector("[id^='Grid'][id*='-id-cell-'] > a"));
PersonalPhone.Click();
Optimizing the lines of code in a single line:
Driver.driver.FindElement(By.CssSelector("[id^='Grid'][id*='-id-cell-'] > a")).Click();
Explanation
The id attribute:
Always start with Grid followed by the dynamic value, so you can use ^ to indicate starts-with
Always contain -id-cell- at the rear end, so you can use * to indicate contains
However, as the desired element is a dynamic element so to invoke click() on the element you may have to induce WebDriverWait for the ElementToBeClickable() and you can use either of the following Locator Strategies:
CssSelector:
new WebDriverWait(driver, TimeSpan.FromSeconds(20)).Until(ExpectedConditions.ElementToBeClickable(By.CssSelector("[id^='Grid'][id*='-id-cell-'] > a"))).Click();
XPath:
new WebDriverWait(driver, TimeSpan.FromSeconds(20)).Until(ExpectedConditions.ElementToBeClickable(By.XPath("//*[starts-with(#id, 'Grid') and contains(#id, '-id-cell-')]/a"))).Click();
I am sorry to give you this news, but xpath 1.0 its still used in most drivers... quite:
As other answers have noted, XPath 1.0 does not support regular
expressions.
Suggested way is to use the parent elements to locate the element you wish to click.
or..
if the grid-xxx--xxx-- id keyword is constant you can do something like
Xpath: //*[starts-with(#id, 'Grid')]/a - id starts with Grid
CSS: input[id^='Grid'] > a - id starts with Grid
Change the input to the actual web element.

Find element in selenium

I am using Selenium with C# to run some tests. I have an issue with an element which i can not locate. I know it is there, and I have it in html. even knowing everything about it, i can not seem to find it. When I used nodeJS it was pretty easy to locate, but in C# I just can not. After trying so many things, I thought I would ask here.
I get OpenQA.Selenium.NoSuchElementException when using the following:
IWebElement Title = driver.FindElement(By.XPath("//*[contains(., 'TextHere')]"));
I tried using the css path, xpath and tag, but the only case where I even found something was with tag. And it was not the correct element.
Is there just something majorly wrong with my syntax? I have looked at multiple threads about this and all the syntax they used haven't worked either.
say or between two calls of contains function
//*[contains(text(), 'About us') or contains(text(), 'about us')]
or use translate function to make xpath case insensitive
//*[contains(translate(text(), 'ABOUTS', 'abouts'), 'about us')]
when you are using Contain text make sure the contain text is unique or else you will get list of result and based on your condition iterate it.
Ok, so I figured it out. The element was inside an iframe. But not only that, it was also being created by a function which ran on load. Meaning i had to put in a delay to wait for it to load.
Here is the working code in case anyone is looking at a similar issue:
driver.SwitchTo().Frame(driver.FindElement(By.Id("iFrame id")));
System.Threading.Thread.Sleep(500);
IWebElement Title = driver.FindElement(By.XPath("path to element"));
Just using sleep might not be optimal, but I am quite new at this, and it works. If someone has a good replacement i would love to hear suggestions.

How to find a dynamic element and send text through Selenium and C#

EDIT: Not sure if it really helps to figure it out, but this is Sharepoint based.
I have an element with special character which the Webdriver can't locate.
var element = wait.Until(x => x.FindElement(By.Id("Tasrit_6aecdca9-e3b9-4141-ae36-d537784f9592_$TextField_inplacerte")));
element.SendKeys("foo");
I guess it is the $ that causes the problem.
On the contrary , I found it by using :
var element = wait.Until(x => x.FindElements(By.CssSelector("div[id*='Tasrit_6aecdca9-e3b9-4141-ae36-d537784f9592']")));
element[2].FindElement(By.TagName("p")).SendKeys("foo");
The test passes that way(seemingly), but the value isn't really being sent to the field.
Unfortunately, there is no input tag on the element's hierarchy, and when inserting the text manually , I can then see that the value was inserted to the <p> tag. But , as shown, when using the <p> tag , it doesn't really help.
The HTML:
<div class="ms-rtestate-write ms-rteflags-0 ms-rtestate-field" id="Tasrit_6aecdca9-e3b9-4141-ae36-d537784f9592_$TextField_inplacerte" role="textbox" aria-haspopup="true" aria-labelledby="Tasrit_6aecdca9-e3b9-4141-ae36-d537784f9592_$TextField_inplacerte_label" style="min-height: 84px;" contenteditable="true" aria-autocomplete="both" aria-multiline="true" RteDirty="true">
<p>
<span id="ms-rterangecursor-start" RteNodeId="1"></span>
<span id="ms-rterangecursor-end"></span>
​</p>
</div>
Instead of implementing two FindElement* you can do it in single step as follows:
CssSelector:
wait.Until(x => x.FindElement(By.CssSelector("div.ms-rtestate-write.ms-rteflags-0.ms-rtestate-field[id^='Tasrit_'][aria-labelledby$='_inplacerte_label']>p"))).SendKeys("foo");
XPath:
wait.Until(x => x.FindElement(By.XPath("//div[#class='ms-rtestate-write ms-rteflags-0 ms-rtestate-field' and starts-with(#id,'Tasrit_')][contains(#aria-labelledby,'_inplacerte_label')]/p"))).SendKeys("foo");
Update
However the element looks dynamic to me so you need to induce WebDriverwait for the desired element to be clickable and you can use either of the following solutions:
CssSelector:
new WebDriverWait(driver, TimeSpan.FromSeconds(20)).Until(ExpectedConditions.ElementToBeClickable(By.CssSelector("div.ms-rtestate-write.ms-rteflags-0.ms-rtestate-field[id^='Tasrit_'][aria-labelledby$='_inplacerte_label']>p"))).SendKeys("foo");
XPath:
new WebDriverWait(driver, TimeSpan.FromSeconds(20)).Until(ExpectedConditions.ElementToBeClickable(By.XPath("//div[#class='ms-rtestate-write ms-rteflags-0 ms-rtestate-field' and starts-with(#id,'Tasrit_')][contains(#aria-labelledby,'_inplacerte_label')]/p"))).SendKeys("foo");
If SendKeys() doesn't work you can try using JavaScript
IWebElement webElement = element[2].FindElement(By.TagName("p"));
driver.ExecuteJavaScript("arguments[0].setAttribute('value', 'arguments[1]')", webElement, "foo");
And I guess there is extra space in that element's id :) Try this:
wait.Until(x => x.FindElement(By.Id("Tasrit_6aecdca9-e3b9-4141-ae36-d537784f9592_$TextField_inplacerte")));
element.Click();
Either that or the Id value of that element in the DOM is different, $TextField_inplacerte being a variable that parses to eg. spaceMonkey, undefined, 5 etc. Open up the dev tools, find the element, right-click, inspect and confirm the actual Id of the element in the DOM.
You can use dev tools API to search for text in DOM of the currently opened page (with that element in it) if it matches the Id matches if not there is a difference in it. It could be any part eg. 6th character in Id being different :)
Just to make sure that space between 1st part of id and 24 you mention is the problem you can either:
look at webdriver's code and see internally what is used to access DOM elements
load jquery before testing this out:
var element = wait.Until(x => x.FindElements($('#id containing
spaces')).SendKeys("foo");
Basically, instead of using webdriver way to find element, you use jQuery to obtain the element reference. If that works it's the space problem due to bad design of the application having space in element's id
Possibly that is why CSS selector route worked.

Find elements on webpage with Selenium

I have XPath
/html/body/div[#id='page']/div[#id='page-inner']/div[#id='main-box']/div[#class='in1']/div[#id='content-and-context']/div[#id='content']/div[#class='under-bar']/table[#class='flights']/tbody/tr[#id='flight-932539']/td[2]:
But flight-number are changes. Can I find Elements with part XPath ?
I use foreach() and write data for every flight.
this is html code:
First thing first: don't use absolute path. Even the smallest change in the html invalidate the path, especially in dynamic applications. Your xpath could easily be //tr[#id='flight-932539']/td[2]
As for your question, you can use contains() for partial id
//tr[contains(#id, 'flight-')]/td[2]
As Guy mentioned xpath above, for same you can easily use findElements to find all the flight details and then according perform you actions using for loop.
List<WebElement> WebElements = driver.findElements(By.xpath("//tr[contains(#id, 'flight-')]/td[2]");
for(WebElement element : WebElements){
//perform any operation like for click you can use
element.getText();
}
Above example is in JAVA you can do same in C# as well.

HTML Agility Pack Screen Scraping XPATH isn't returning data

I'm attempting to write a screen scraper for Digikey that will allow our company to keep accurate track of pricing, part availability and product replacements when a part is discontinued. There seems to be a discrepancy between the XPATH that I'm seeing in Chrome Devtools as well as Firebug on Firefox and what my C# program is seeing.
The page that I'm scraping currently is http://search.digikey.com/scripts/DkSearch/dksus.dll?Detail&name=296-12602-1-ND
The code I'm currently using is pretty quick and dirty...
//This function retrieves data from the digikey
private static List<string> ExtractProductInfo(HtmlDocument doc)
{
List<HtmlNode> m_unparsedProductInfoNodes = new List<HtmlNode>();
List<string> m_unparsedProductInfo = new List<string>();
//Base Node for part info
string m_baseNode = #"//html[1]/body[1]/div[2]";
//Write part info to list
m_unparsedProductInfoNodes.Add(doc.DocumentNode.SelectSingleNode(m_baseNode + #"/table[1]/tr[1]/td[1]/table[1]/tr[1]/td[1]"));
//More lines of similar form will go here for more info
//this retrieves digikey PN
foreach(HtmlNode node in m_unparsedProductInfoNodes)
{
m_unparsedProductInfo.Add(node.InnerText);
}
return m_unparsedProductInfo;
}
Although the path I'm using appears to be "correct" I keep getting NULL when I look at the list "m_unparsedProductInfoNodes"
Any idea what's going on here? I'll also add that if I do a "SelectNodes" on the baseNode it only returns a div with the only significant child being "cs=####" which seems to vary with browser user agents. If I try to use this in anyway (putting /cs=0 in the path for the unidentifiable browser) it pitches a fit insisting that my expression doesn't evaluate to a node set, but leaving them still leaves the problem of all data past div[2] is returned as NULL.
Try using this XPath expression:
/html[1]/body[1]/div[2]/cs=0[1]/rf=141[1]/table[1]/tr[1]/td[1]/table[1]/tr[1]/td[1]
Using Google Chrome Developer Tools and Firebug in Firefox, it seems like webpage has a 'cs' and 'rf' tags before the first table. Something like:
<cs="0">
<rf="141">
<table>
...
</table>
</rf>
</cs>
There is something that might be useful to know what is happening when you want to parse a known HTML file and you're not getting results as expected. In this case I just did:
string xpath = "";
//In this case I'll get all cells and see what cell has the text "296-12602-1-ND"
foreach (HtmlNode node in doc.DocumentNode.SelectNodes("//td"))
{
if (node.InnerText.Trim() == "296-12602-1-ND")
xpath = node.XPath; //Here it is
}
Or you could just debug your application after document loads, and go through each child node until you find the node you want to get the info from. If you just set a breakpoint when InnerText is found, you can just go through parents and then keep looking for other nodes. I usually do that entering manually commands in a 'watch' window and navigating using the treeview to see properties, attributes and childs.
Just for an update:
I switched from c# into a bit more friendly Python (my experience with programming is asm, c, and python, the whole OO thing was totally new) and managed to correct my xpath issues. The tag was indeed the problem, but luckily it's unique, so a little regular expression and a removed line and I was in good shape. I'm not sure why a tag like that breaks the XPATH though. If anyone has some insight I'd like to hear it.

Categories

Resources