Selenium: Get Element, which is only Text - c#

I'm trying to find a Text via Selenium, which is directly in the HTML.
This can look something like this:
<br>
Uploaded.net
<img class="bbCodeImage LbImage" />
<br>
I found the Image after the Text, but even now, I can't navigate to the text:
I I went to the img-Element, then tried:
var des2 = ele.FindElement(ByProxy.XPath("preceding-sibling::*"));
Interesting enough, this already returns the br-element and not the text, which is right above it. I also tried to brute force it and get all Elements, with this text:
var des2 = thread.FindElements(ByProxy.XPath("descendant::*[contains(text(), \"Uploaded.net\")]")).SelectMany(f => f.FindElements(ByProxy.XPath("descendant::*")));
foreach(var ele in des2)
{
Debug.WriteLine(ele.Text);
}
So I read all Descendants with the mentioned Text and iterate over all of them, but none of them has a Text set.
Am I missing something crucial here?

Selenium doesn't support a text node. You could however get the text with a piece of JavaScript:
string text = (string)((IJavaScriptExecutor)driver).ExecuteScript(
"return arguments[0].previousSibling.textContent.trim();", ele);

I dont think there is any obvious solution to this. Can offer a very very round about solution.
Get the pagesource of the page -- driver.getPageSource();
Split the pagesource by the img tag. Then split the first element of previous split by br tag. The last element of the array should now be the text.
If you have control over development of this, someone should fix the page.

Related

How to avoid HTMLElement.InnerHtml property to change relative path url of HTML elements

In winforms, I have something similar to a HTML editor where a textbox control is used to write Html code and a browser control to display a preview.
I am trying to set an InnerHtml property of a HTMLElement with something like this:
htmlElement.InnerHtml = txtCode.Text;
The problem is when assigning a string like:
"<a href='/foo/bar.aspx'>Click Here</a>"
htmlElement.InnerHtml returns:
"Click Here"
The HTML code of the InnerHtml property is saved in a file and the file is used to render content in a website which renders and invalid link.
Is there any way to avoid this behavior of the InnerHtml property, without saving the text directly from the textbox?
My only idea is to delete the text node child of the <a> element, and then append a newly-created text node with your text. This might work around whatever process is interfering with your assignment of InnerHtml.
As a workaround you can try to put script block in your txtCode:
<script>document.write("<a href='/foo/bar.aspx'>Click Here</a>")</script>

Text property on selenium web element is empty even though I can inspect it with Visual Studio

Without posting pages of C# code and markup, has anyone got a reason why this code
var link = _driver.FindElement(By.Id(field + "Field"));
var id = link.GetAttribute("id");
var text = link.Text;
given this markup
<a id="ForenameField" href="/MyUrl/MyFolder/MyId">3 errors</a>
Assigns an empty string to the text variable, but if I put a breakpoint on the second or third line and inspect the link variable, I can see the inner text of the element against the Text property on the inspector, it reads "3 errors", but the value of text is an empty string. It is not hidden, I can see the text if I add a watch or use quickview, any ideas?
Ok, it's my bad. Using jquery to toggle class on the div that contains the html in the question, meant that although users see the div appearing, the class that hides the div is still in the tag. A bit like this
<div class="hideThis showThis"><!-- my elements /--></div>
This makes it so that Selenium is right not give me a text value. It is strange however that the Visual studio debugger thinks that there should be a value. Visual Studio seems to go with what I can see, but Selenium is more pedantic about the hideThis class being there.
I go with the idea that if you can't see it you can't interact with it, so it is worth looking up the html graph from the element you expect to have a value to see if any class is present which would hide your element.
Feel free to recommend that I delete this rather obvious wisdom.
I know this was posted over a year ago, but I had this exact problem too and came across this thread. I was able to solve it by just waiting for the DOM to load--some elements aren't visible until the DOM is updated. So just putting Thread.Sleep(6000) or whatever after navigating to the page got it to work for me.

how to get text attribute from a asp:panel

Probably a simple question, but I've been browsing now for 30 mins and STILL cant find a solution!
i have a panel and it has an attribute text="something". but the panel class does not seem to have a getAttribute method... Which personally, I think is STUPID!
Code follows:
foreach (Control c in clientGrid.Controls)
{
if (c.GetType().ToString().Equals("System.Web.UI.WebControls.Panel"))
{
/*Something*/ textInsidePanel = ((Panel)c)./*Somthing*/
}
}
Now i've tried AttributeCollection text = ((Panel)c).Attributes;
and
string text = ((Panel)c).Attributes.toString();
and other useless things...
This should be really simple! when i inspect element on chrome, I can see the panel, (well the div) and i can see the text attribute right there. and i can see its value! but i want my c# code to have the value to!!
Please Help!
Alex
if I get you question right - you can use next code
asp part
<asp:Panel runat="server" ID="pnl" Text="hello world"></asp:Panel>
c# part -
string s = pnl.Attributes["Text"];
Have you tried using an accessor?:
string val = YourPanel.Attributes["Text"];
// ^ that's your attribute name
That should get the attribute's value BUT I'm pretty sure what you are doing isn't possible as attribute values are not persisted between postbacks (at least not when set via a client script). To do that you should use hidden inputs or some other form element.
The Panel control itself doesn't have a text property. But if you access the inner text as a LiteralControl it will work:
var panelContent = ((Panel)c).Controls[0] as LiteralControl;
var text = panelContent.Text;

Show more/less without stripping Html tags in JavaScript/jQuery

I want to implement readmore/less feature. i.e I will be having html content and I am going to show first few characters from that content and there will be a read more link in front of it. I am currently using this code :
var txtToHide= input.substring(length);
var textToShow= input.substring(0, length);
var html = textToShow+ '<span class="readmore"> … </span>'
+ ('<span class="readmore">' + txtToHide+ '</span>');
html = html + '<a id="read-more" title="More" href="#">More</a>';
Above input is the input string and length is the length of string to be displayed initially.
There is an issue with this code, suppose if I want to strip 20 characters from this string:
"Hello <a href='#'>test</a> output", the html tags are coming between and it will mess up the page if strip it partially. What I want here is that if html tags are falling between the range it should cover the full tag i.e I need the output here to be "Hello <a href='#'>test</a>" . How can I do this
Instead of doing too much manually, I prefer you to go with following jQuery plugin.
http://plugins.learningjquery.com/expander/index.html#getting-started
It will expand and collapse your text for Read more options, Also provide you much customization.
Hope this will help.
Thanks!
Hussain
This will be quite hard since HTML is not a regular language, so using regular expressions would be cumbersome.
Really want you need to do is parse the HTML into a DOM structure using jQuery $('html text') and then recursively go through the elements getting the length of each elements text using .text() and when you come to an element with causes the cumulative text length thus far to be over the limit, split this elements text at that point and set it the element's text to be the left of the split.
Then keep all elements before this one, and disregard all siblings etc that occur after this element. However I have no idea how to implement that simply.
On the other hand you could just strip the HTML tags away, why bother.
If you have the text in a dom element, you could use the innerText/textContent property of the dom element to get just the text without the tags. substring of this text could be used without worrying about the tags.
var post_dom = document.getElementById('#post-content');
var input = post_dom.innerText || post_dom.textContent;
I think the best solution here would be to use
var textToHide = input;
var textToShow = $("<div/>").html(input).text().substring(0, length);
which will convert your HTML to plain text and extract the first few characters for the summary. Then toggle between them when they click the ellipsis rather than trying to display both at the same time.
maybe you could rethink the problem : instead of modifying your text, you could modify the way it is shown on the page.
Say if you want to show only 3 rows of the content, you could modify the content's container style to a height equal to the height of one content row * 3.
Anyway, this could be easily implemented in jquery ,and if you take advantage of it's animate function, you could easily make your own plugin such as :
(function($){
$.fn.lessDetails = function(desiredHeight){
var desiredHeight = desiredHeight || 20; //or any other "default" value
return this.each(function(i){
$(this).realHeight = $(this).css("height");
$(this).css('height',desiredHeight);//or you could animate it
});
};
$.fn.moreDetails = function(){
return this.each(function(i){
$(this).css('height',$(this).realHeight || "auto");//or you could animate it
});
};
})(jQuery);
and then you could call :
$('.less').lessDetails(); $('.showMore').click(function(){$('#'+$(this).attr('rel')).moreDetails();});'
having your html structured as :
< div class="container"> < div id="1" class="less">content goes here </div> < a href="#" rel="1" class="showMore"> show more</a> </ div >
Haven't tested it ,but it should work, or at least should give you a basic idea of my solution.

How determine css text of each node in html

How can I iterate over HTML nodes of a web page and get the CSS Text of each node in it? I need something like what Firebug is doing, if you click on a Node, it gives you complete list of all CSS Texts associated with that Node (even inherited styles).
My main problem is not actually iterating over HTML nodes. I am doing it with Html Agility Pack library. I just need to get complete CSS for each node.
p.s. I am sorry, I should have explained that I want to do this in C# (not javascript)
I found the following code snippet useful for all element in the page and 'CurrentStyle' property of them shows their computed style:
HTMLDocument doc = (HTMLDocument)axWebBrowser1.Document;
var body = (HTMLBody)doc.body;//current style
var childs = (IHTMLDOMChildrenCollection)body.childNodes;
var currentelementType = (HTMLBody)childs.item(0);
var width = currentelementType.currentStyle.width;
Note that according to my prev post axWebBrowser1 is a WebBrowser control.
If you want the current styles for an element, look into getComputedStyle(), but if you want the inheritance too then you may have to implement the style cascade. Firebug does quite a lot of work behind the scenes to generate what you see!
You can get the CSS text from the style attribute like this:
node.getAttribute('style')
Or if you want style you can iterate through the keys and values in
node.style
If you want to grab the entire computed style of the element and not just the CSS applied in the style attribute, read this article on computed and cascaded styles.
You can use WebBrowser control in C# to access the htm document object and cast its body tag as following:
HTMLDocument doc = (HTMLDocument)axWebBrowser1.Document;
var body = (HTMLBody)doc.body;
But before that you should add com refrence: MSHTML to you project.
here you could access body.currentStyle that show you all its styles that might be css or inline styles.
You can try for (property in objName) operator as seen here.
I'm not sure if you can simply get "all" CSS properties using JavaScript to be honest, you could look into the [DOMNode].currentStyle, [DOMNode].style and document.defaultView.getComputedStyle thingamajiggy's. They should contain the 'current' style they had. What you could then do is have an array of all CSS properties you want to test and simply loop them through a function of your own that gets the CSS property for everything using forementioned methods (depending on which browser). I usually attempt the DOMNode.style[property] first as this is "inline" javascript and always rules over everything, then I sniff if the browser uses the .currentStyle method or .getComputedStyle and use the correct one.
It's not perfect and you might need to clean up some things (height: auto; to the actual current height, some browsers might return RGB colours instead of HEX) etc.
So, yes, I don't know of anything prefab that you can use in Javascript.

Categories

Resources