How do I select an empty element in XPath? - selenium

We select elements with Django 1.4 tests and Selenium like this:
self.assertEqual(1, len(self.selenium.find_elements_by_xpath("//a[#href='#'][#class='button save-as'][#title='Save As...'][text()='Save As']")))
(The class inherits from LiveServerTestCase).
The problem is that sometimes there are elements without text, and if we select with [text()=''] it fails (the len is 0). How can I select elements without text?
Update: Because [text()=''] didn't work, I had to assert two lines to assert no text:
self.assertEqual(1, len(self.selenium.find_elements_by_xpath("//a[#href='#'][#class='button properties'][#title='Properties']")))
self.assertEqual("", self.selenium.find_element_by_xpath("//a[#href='#'][#class='button properties'][#title='Properties']").text)
Now I can assert the same with one line:
self.assertEqual(1, len(self.selenium.find_elements_by_xpath("//a[#href='#'][#class='button properties'][#title='Properties'][not(text())]")))

You could use XPath's not() function.
//a[#href='#'][#class='button save-as'][#title='Save As...'][not(text())]

Related

How to select a field whose selector id is dynamic in behavior in selenium

I have an ID: s2id_autogen4_search in which the number after autogen keeps changing due to which I am not able to select the ID. Is there a way to select the element in selenium
driver.find_element((By.XPATH,"//[starts-with(#id,'s2id_autogen')]"))
You can use starts with to find an id.
driver.find_element((By.XPATH,"//*[starts-with(#id,'s2id_autogen') and contains(#id,'_search')]"))
use both start with and contains using "and"
Based on the neighbor answer, you can try also:
driver.find_element_by_xpath("//*[contains(#id,'s2id_autogen')]")
or
driver.find_element_by_xpath("//<tag>[contains(#id,'s2id_autogen')]")
where 'tag' of the element
to make selector more unique, use 'and' like that:
driver.find_element_by_xpath("[contains(#id,'s2id_autogen') and contains(#id,'search')]")
or with starts_with:
driver.find_element((By.XPATH,"//*[starts-with(#id,'s2id_autogen') and contains(#id,'_search')]"))

Xpath to select second text match instead of first one and selecting next element

I'm trying to select an element that has random generated class so my only way to select that element is using xpath.
The element I need to select is an input box with the previous label "City" but the problem is that it appears three times on the website and I want to select the second match on the website.
I have tried this, but it only selects the first one.
input = driver.find_element_by_xpath("//label[contains(text(),'City')]//following::input")
To select the second one I tried this but it doesn't work.
input = driver.find_element_by_xpath("//label[contains(text(),'City')]//following::input")[1]
Any help would be greatly appreciated.
You are missing an 's' in find_element_by_xpath. Try find_elements_by_xpath.
input = driver.find_elements_by_xpath("//label[contains(text(),'City')]//following::input")[1]
You can make sure there are expected 3 instances that match this xpath with some thing like:
input_all = driver.find_elements_by_xpath("//label[contains(text(),'City')]//following::input")
print("len(input_all):", len(input_all))
This would get only the second match:
input = driver.find_element_by_xpath("//label[contains(text(),'City')][2]/input")
if at all you are looking to get second matching element, you may try
WebElement input = driver.findElements(By.xpath("//label[contains(text(),'City')]//following::input")).get(1)
Strictly speaking, the following XPath fulfill your needs :
(//input[preceding::label[1][contains(.,"City")]])[2]
Select the 2nd input element on the page which respect the following condition : is preceded by a label element containing a specific text.

How can i select element in selenium webdriver by part of ID.

I have a td element with ID like "a:2:3:d:", and when i want to select it by id, my webdriver can not find it. Is there a way to search by part of ID, because I think, that the problem is at last ":" in the identifier.
First, you need to confirm that this really is the problem, and it's not just that the page isn't fully loaded, or is loaded asynchronously. I don't see any particular reason why Selenium should care about the trailing ":".
Update: From the comments, it's much more likely that the dynamic id that is the problem, but the solution is the same either way:
To find an element by partial id, you can use xpath. If you were trying to find a div by partial id, for example:
//div[contains(#id, 'a:2:3')]
You don't say what language you are using, but in python, this would be used as follows:
driver.find_element_by_xpath("//div[contains(#id, 'a:2:3')]")
and in Java:
driver.findElement(By.xpath("//div[contains(#id, 'a:2:3')]"))
Assuming you are using Java
WebElement el = driver.findElement(By.cssSelector("td[id*='a:2:3']"));
The above code gets the element of TD which starts with a:2:3 as we use * in the css Selector.
XPath is more powerful and can be sometimes difficult to understand. CSS Selector is easy.

Selenium nth match by id without common parent

I have to test some complicated web service using Selenium.
Problem is that ids of elements are changing from session to session.
For example there is bunch of inputs each have id with prefix textf_id_DComboBox_ and ends with a consecutive numbers, starting number is random (session dependent).
Those inputs doesn't have a common parent so nth-child doesn't work.\
I can find first input by using selector: css=input[id^='textf_id_DComboBox_'] but I have no idea how to find next items (1-7) which match this selector.
I've found some suggestions on stackoverflow that xpath selector should be used, but I was unable to adopt examples for my use case.
Update:
I have also alternative selector which captures first input: css=td.DForm_treeGridNoWrap input.
You can use this XPath in order to select all inputs that contain a common id:
string comboBoxXPath = "//input[contains(#id, 'textf_id_DComboBox')]";
List<WebElement> comboBoxElements = driver.findElements(By.XPath(comboBoxXPath));
At this point, you can iterate through the entire collection, or you can select which one you'd like to interact with by using an index:
comboBoxElements[1]
comboBoxElements[2]
comboBoxElements[3]
etc...
Well, that descrption does not help that much. You can try these tricks:
You can call findElement on WebElement This trick will probably not work, because those IDs do not have common parent. But if they are wrapped, say, in table, you can find the table first:
WebElement table = driver.findElement(By.id("the-table"));
And then to find all input in such table:
List<WebElement> inputs = table.findElements(By.tagName("input"));
Install Selenium IDE to your firefox and try record testcase by using it. You can play with target in Selenium IDE.
Dirty approach
List<WebElement> allInputs = driver.findElements(By.tagName("input"));
Will find all inputs in such page.
Footnote: The code is Java and driver variable is considered as healthy instance of WebDriver

Selenium *ElementPresent and *XpathCount give different results?

I am getting different results for the same locator. For example
//table[#id='foo']
returns true when testing ElementPresent, but returns 0 for XpathCount. In Selenium v1.0.10 IDE the Find button highlights the correct element for both functions. Any ideas on what could be causing this?
Notes:
We have frames on the page EDIT: This is probably the problem. Bounty to verification.
There are many tables on the page, but only one with #id of "foo"
Firefox 3.6
Happens in both IDE and Java RC
Well, this is not a verification more of a non-verification.
I use Selenium to test a GUI with frames. To make isElementPresent and getXpathCount to work I always have to select a frame first with selectFrame (even to get isElementPresent to work correctly). By just opening an URL no frame at all seems to be selected.
This is what the HTML and corresponding selectFrame code looks like:
<frameset id="mainframeset"><frame name="nav" id="nav" src....
selenium.selectFrame("nav");
Use these XPath expressions:
boolean(//table[#id='foo'])
and
count(//table[#id='foo'])
In case there is a table element whose id attribute's value is "foo", then the first expression above should evalute to true() and the second expression above should evalute to a positive integer.
Not really a direct answer to the question, but a workaround if you are reading this and want to loop over the elements. Use isElementPresent in the for loop like this:
for(int i = 2; selenium.isElementPresent("//table[#id='foo']//tr["+i+"]"); i++)
{
selenium.getText("//table[#id='foo']//tr["+i+"]//td["+columnNum+"]");
}
Note that we start i at 2 since XPath is indexed from 1 and we want to skip the header