11

With ASP.NET the tag IDs are pretty volatile so to make my tests more robust I want to locate elements by their label texts. I have played some with WatiN and it does this perfectly but that project seem kind of dead nowadays so I thought I'd look into Selenium as well before I decide on a framework.

I have html that looks something like this

<label for="ctl00_content_loginForm_ctl01_username">Username</label>:
<input type="text" id="ctl00_content_loginForm_ctl01_username" />

I don't want to type:

selenium.Type("ctl00_content_loginForm_ctl01_username", "xxx");

That is too reliant on the ID. In WatiN I'd write:

browser.TextField(Find.ByLabelText("Username")).TypeText("xxx");

Is there a way to do this in Selenium?

Johan Levin
  • 830
  • 1
  • 9
  • 26
  • Sorry you got the impression WatiN is a dead project, but it is alive and kicking. Last December we did a release of WatiN 2.0 RC1. Jeroen van Menen – Jeroen van Menen Jan 15 '10 at 10:36
  • Well, you had a roadmap that mentioned a release q1 2009 and towards the end of 2009 it still hadn't been released and the roadmap hadn't been updated. Also, when I submitted a patch to the source forge feature request forum (to access raw html source) I didn't get any reply at all. It did seem like pretty dead project. I'm glad I was wrong. – Johan Levin Jan 23 '10 at 12:25

4 Answers4

13

This works:

//input[@id=(//label[text()="Username"]/@for)]

Explanation: Since you are looking for the input:

//input[@id=("ctl00_content_loginForm_ctl01_username")]

replace the "ctl00_content_loginForm_ctl01_username" by the attribute's value of the label:

//label[text()="Username"]/@for
  • I had no idea you could use "sub-queries" in xpath. I no longer have access to the project where I had this problem, so I can't easily verify the solution. But it looks promising. Thanks! – Johan Levin Dec 30 '11 at 15:53
7

I believe you can do this with the following:

selenium.Type(selenium.getAttribute("//label[text()='Username']/@for"), "xxx");

The text()='Username' bit gets the label you want by its innerHTML, then the /@for gives you back the value of its "for" attribute.

Heads up: this is not tested (apologies for that!) but I think it'll work, based on some tooling around in the IDE plugin

vogomatix
  • 4,856
  • 2
  • 23
  • 46
Paul Degnan
  • 1,972
  • 1
  • 12
  • 28
3

Ok, this may be a year old but what they hey. This will select the first input under a label containing the text 'Username'.

//label[text()='Username']/input

I generally prefer using contains() as I find that some browsers are adding annoying spaces into the occasional element:

//label[contains(., 'Username')]/input

Note that the single slash before input denotes it will only look one level down, where the double slash would check all levels under the label. Use XPather for Firefox to create and check your XPaths, it's very useful.

Hans Kesting
  • 38,117
  • 9
  • 79
  • 111
  • Yes, that question is a bit old, but I don't think I ever solved that problem in a clean way. The problem with your suggestion is that it requires the `` input to be _inside_ the ` – Johan Levin Feb 14 '11 at 09:53
1

Yes, you can use XPath, CSS or DOM locators to identify your element. In this example your XPath could look like //lable[@for='ctl00_content_loginForm_ctl01_username'] to identify that particular label.

John
  • 1,681
  • 3
  • 20
  • 28
  • Except it's not the label I want to identify - it is the input box. – Johan Levin Jan 08 '10 at 23:18
  • Oh then change the XPath to look for that input - in this case: //input[@id='ctl00_content_loginForm_ctl01_username'] Here is the explanation for it - you are looking for all the input elements (hence //) where the attribute id equals ctl00_content_loginForm_ctl01_username – John Jan 08 '10 at 23:46
  • Yes, but my whole problem is that I don't want any of the IDs in my test code since they change as soon as I change something on the page. There was more to my question than I could fit in the headline... – Johan Levin Jan 09 '10 at 18:17