I have a radio button:
<input type="radio">test</input>
and I would like to retrieve the element by XPath using through its type and the text inside. I have tried the following:
//input[#type='radio' and text() = 'test']
but it hasn't worked out. I believe the problem is in the text() part since //input[#type='radio'] does select the element.
What is it I'm doing wrong?
In HTML/XHTML, input is an empty element; it cannot contain text. In this case, the text test actually exists as a sibling text node that directly follows the input element node, rather than as a text node within the input element node. Consequently, the closing </input> tag you have there doesn't mean anything.
Try this instead:
//input[#type='radio' and following-sibling::text() = 'test']
Or this:
//input[#type='radio' and contains(following-sibling::text(), 'test')]
Related
I am running automation on a webpage that has a lot of elements in the form:
<label ...>"label name"</label>
<div ...></div>
And I need to click the <div> element. I have a function that locates it using the xpath:
driver.findElement(By.xpath("//label[contains(text(),'value')]/following-sibling::div"))
However, some of the element have a slight different form. E.g., one is in the form:
<label ...>"label name"</label>
<br ...></br>
<input ...></input>
And I need to click the <input> element. I can't just use /following-sibling::* because the <br> element is the following sibling.
I could easily just write another function using <input> but I would prefer to just update and reuse the function I already have (and I'm curious). Is there any way to specify an element can have one of multiple tag names?
Maybe something like: /following-sibling::[div or input]
This XPath,
//label[.='l1']/following-sibling::*[self::div or self::input]
will select all div or input sibling elements following a label element with a string value of l1.
I am trying to find and replace all the text on a webpage with JavaScript. I am currently using a variation of the following code from this answer which recursively processes every Text node in the document.
function replaceInText(element, pattern, replacement) {
for (let node of element.childNodes) {
switch (node.nodeType) {
case Node.ELEMENT_NODE:
replaceInText(node, pattern, replacement);
break;
case Node.TEXT_NODE:
node.textContent = node.textContent.replace(pattern, replacement);
break;
case Node.DOCUMENT_NODE:
replaceInText(node, pattern, replacement);
}
}
}
replaceInText(document, /e/gi, '');
Once I tested it out, I discovered that there's an exception: the placeholder attribute of <input> and <textarea> elements. These are not Text nodes, but are still displayed as visible text by the browser and searchable with CTRL-F. Try running the above on the Stack Overflow homepage and see that the search bar is left out.
Now I'm wondering if there's any other attributes out there like this too. All I can currently think of is value for <input> and <textarea>, alt for <img> and <area>, and the global title attribute (tooltips), and I'm worried I'm missing some obscure attribute since I couldn't find a comprehensive list of this sort anywhere.
It's been a while and I've discovered value for input[type="button"]and I will record my list so far below. I have marked the answer as community wiki so anybody who finds more can easily add them.
placeholder for <input> and <textarea>: placeholder text
value for <input> and <textarea>: actual contents of field
value for <input type="button">: the text inside the button
alt for <img>, <area>, and <input type="image">: alternative text for when images fails to load
title for anything: tooltip that displays on mouse hover
I have the following HTML structure
<tr>
<td><input name="Choice" type="radio" value="someValue"></td>
<td>text</td>
</tr>
I would like to write a Xpath that finds the link by the value of its text then search the input element and perform an action like click on the input radio button.
I have tried a number of Xpaths like this one
//a[contains(text(), 'text')]/ancestor::/td/input
but they all fail. The first part of the xpath is right but the second path with the ancestor is where it gets into trouble.
//tr[.//[contains(text(), 'text')]]//input
You can search for the common wrapper first, that has text inside. And then just search required element in that wrapper.
It doesn't care about order of the elements, which can be good or not, depending on your task. It also doesn't care about elements being on the same level, but both elements should be inside tr tag.
You can be more precise by adding inner path, or attributes select.
//tr[td[contains(text(), 'text')]]/td/input
This pattern is rarely used for some reason, but I would recommend it for it's readability, simplicity, and straight-forward approach.
//a[contains(text(), 'text')]/../..//input
or
//a[contains(text(), 'text')]/ancestor::tr/td/input
just use '..' goto the immediate parent and then find the input child tag of that
you have to mention which ancestor tag to be select
You were close enough. To locate the <input> element with respect to the <a> tag with text as text you can use either of the following Locator Strategies:
Using the <td> and it's child attributes:
//td[.//a[text()='text']]//preceding::td[1]/input
Using the textContext of <a>:
//a[text()='text']//preceding::td[1]/input
If you want to select input node by link text try
//td[a="text"]/preceding-sibling::td/input
I need to find a certain text in a nested div that has no class or id.
This is a structure of the html.
<div class="active_row">
<div class="outcomes">
<div class="event_outcome" onclick="doSomething">
<div>Target Text</div>
</div>
</div>
</div>
I tried accessing the text directly using the example I got from here.
driver.find_elements_by_xpath("//div[contains(., 'Target Text')]")
This returns a list of elements that contain the target text but nothing happens when I run the click method on them.
What's the best way to set this query to find the text and then click on the div with event_outcome class?
To select the div with event_outcome class, you can add a predicate in your XPath to check class attribute value :
//div[contains(., 'Target Text') and #class='event_outcome']
or add a predicate to check existence of onclick attribute :
//div[contains(., 'Target Text') and #onclick]
What's the best way to set this query to find the text and then click on the div with event_outcome class?
You should try using below xpath which would returns <div class="event_outcome" onclick="doSomething"> with text Target Text which would fullfil all your needs as below :-
element = driver.find_element_by_xpath(".//div[contains(., 'Target Text') and #class='event_outcome']")
print(element.text)
element.click()
Or you can also get the same with exact match of the inner text using normalize-space() function of the xpath as below :-
element = driver.find_element_by_xpath(".//div[normalize-space()='Target Text' and #class='event_outcome']")
print(element.text)
element.click()
Is there any way to allow a link/anchor within an input field so that whatever text is in the field is ALSO clickable and actionable?
This is unfortunately not possible in HTML 4 or below. Even with HTML5 which has several new INPUT TYPEs, including URL, it only does validation and has some other useful functions, but won't give you want you want.
You might look for some jQuery plugins that can help you do this, most use the same principals behind Rich Text or other online/web-based HTML WYSIWYG editors. I've had trouble locating them myself.
These 3 situations (that I can think of right now) are pretty much what you will face natively with HTML4 or below, as text in an actual HTML4 INPUT textbox is pure text. It is not html and therefore NOT clickable. Here are some variations:
The INPUT tag's VALUE attribute, also referenced as the corresponding DOM object's "value" property (which is basically what you've been doing, and the most you can hope for, if you decide that you MUST have the text that's ACTUALLY inside the textbox (because the text inside the textbox is the VALUE attribute, as I have it with "http://yahoo.com" in this example):
<input id="myTxtbox" type="text" value="http://yahoo.com">
where the INPUT's VALUE = "http://yahoo.com", which you can retrieve with:
in pure javascript:
document.getElementById("myTxtbox").value
in jQuery:
$("myTxtBox").val()
When your link/url is the text in between the <INPUT> and </INPUT>, i.e. the text/innerText of the textbox. This is useless for your question/scenario since it's not clickable, and more importantly NOT INSIDE the textbox. However, someone might want to use this to retrieve any text that you may be using as a label (if you're not using the <label> tag itself already that is):
<input id="myTxtbox" type="text">
http://yahoo.com
</input>
The textbox's text/innerText is NOT an attribute here, only a DOM object property, but can still be retrieved:
pure javascript:
document.getElementById("myTxtbox").innerText
jQuery:
$("myTxtBox").text() -- you would use this to capure any text that you may be using as a label (if you're not using the tag).
The result being: http://yahoo.com
When your link/url is the form of an ANCHOR (<A>) with an HREF to your url (and visible link text) in between the <INPUT> and </INPUT>, i.e. the innerHTML of the textbox. This is getting a bit closer to what you want, as the link will appear as, and function as an actual link. However, it will NOT be inside of the textbox. It will be along side it as in example #2. Again, as stated in example #1, you CANNOT have actual working HTML, and therefore a working 'link' inside of a textbox:
<input id="myTxtbox" type="text">
<a href="http://yahoo.com">
http://yahoo.com
</a>
</input>
Once again, similarly to example #2, the textbox's innerHTML is NOT an attribute here, only a DOM object property, but can still be retrieved:
pure javascript:
document.getElementById("myTxtbox").innerHTML
jQuery:
$("myTxtBox").html()
The result being: http://yahoo.com