locateByLabelText

Locate form elements in selenium tests by matching the text in their associated labels. A label can be associated with a form control by either setting its "for" attribute to the id of the form control or by nesting the form control within the label tag. This locator supports both methods and will support nested input, select, textarea and button tags. It supports some filters (notably index) and also a pseudofilter: within, which restricts the search for matching labels to a subtree of the infoset whose tree is identified by a given xpath expression.

example of use

For a form containing the HTML:

<label for="inputWithId">Input with ID:</label> <input id="inputWithId" />
<label>Nested Input: <input id="nestedInput" /></label>

Text can be typed into the two inputs using the following selenium commands:

type labelText=Input with ID: input found by id
type labelText=Nested Input* nested input found

notes

  • Use this extension with Selenium 0.6.0 or better. Success has been reported with Selenium 1.0b2.
  • The text can be specified using a pattern.
  • This extension will throw an exception under a few circumstances:
    • If a label with matching text is not found.
    • If a label with matching text is found but it has no associated form control.
    • If a label with matching text is found and its for attribute points to an ID that doesn't exist.
    • If a label with matching text is found and it has more than one nested form control.
  • This extension has been tested in IE 6.0, Firefox 1.0.7, Firefox 3.1b3, Safari 4 build 528.16, Opera 9.64 build 10487, and Google Chrome 1.0.154.53.

license

This user extension is available under Apache License 2.0.

File: 

Type: 

User-Extension

6 Comments

Thanks for your extention. I

Thanks for your extention. I installed it and got it to work. Before that, I used this code pasted in as a "dom=" selector.

function(labelText) {
var labels = inDocument.getElementsByTagName("label");
var inDocument=selenium.browserbot.getCurrentWindow().document;
for (var i = 0; labels && i < labels.length; i++) {
var currentLabel=labels[i];
if (currentLabel.innerHTML.match(labelText)) {
var forAttribute = currentLabel.attributes['for'] ? currentLabel.attributes['for'].value : null;
return inDocument.getElementById(labels[i].getAttribute("for"));
}
}
throw new SeleniumError("Unable to get label with text '" + labelText + "'");
};

Hi,

Hi,
I was having trouble getting this extension to work under Firefox 3.5 until I changed the following line:

var forAttribute = currentLabel.attributes['for'] ? currentLabel.attributes['for'].value : null;

to

var forAttribute = currentLabel.htmlFor ? currentLabel.htmlFor : (currentLabel.attributes['for'] ? currentLabel.attributes['for'].value : null);

Thanks for extension.

I had quite precisely the

I had quite precisely the same issue as Paul Hansen, in FF3.0.4 "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.0.14) Gecko/2009090217".
I also (after some grief) solved it similarly:

var forAttribute = (currentLabel.attributes['for'] ?
currentLabel.attributes['for'].value :
currentLabel.htmlFor || null );

 Anders Eurenius

The edit above (either of the

The edit above (either of the previous two comments worked fine) was necessary for this extension to work for me on Firefox version 3.0.10 (Linux) with Selenium IDE release 1.0.2.

I'm seeing a problem with the

I'm seeing a problem with the test cases supplied though.
 
When run inside Selenium IDE (environment above), the first  verifyErrorOnNext fails even though the condition string matches the error generated.
 
The message expected and generated is: "Found 2 nested form elements in the matched label! Should only be one."
 
Upon looking into this problem more, I found that it is a known issue and already in the bug tracking system.
 
At the moment, Selenium IDE does not support the verifyErrorOnNext command or the assert version of it.
I have tested and confirmed that the command works fine when run under selenium core using -htmlsuite

Does the labelText extension

Does the labelText extension work with the IDE? The code that calls the locators in the recorder checks that the result uniquely identifies the element being recorded, so it looks to me like the exceptions here might get in the way, preventing anything from being recorded? We use something much simpler, but we're only interested in labels with a for attribute:

PageBot.prototype.locateElementByLabel = function(value, inDocument) {
if (value.substr(-3) == "...") {
value = value.substring(0, value.length-3);
return this.locateElementByXPath("id(//label[starts-with(text(),'" + value + "')]/@for)", inDocument);
}
return this.locateElementByXPath("id(//label[text()='" + value + "']/@for)", inDocument);
}

Along with a second trivial locator for submit buttons:

PageBot.prototype.locateElementBySubmit = function(value, inDocument) {
return this.locateElementByXPath("//input[@type='submit'][@value='" + value + "']", inDocument);
}

And then this LocatorBuilder to record them into tests (as an IDE extension). The locators and the LocatorBuilder are deliberately not handling all the corner cases; it keeps the code simple and the IDE will just fall back on another LocatorBuilder if this one fails (eg by returning a locator that matches multiple elements). It does handle long labels and labels with newlines because that was a common case for us, though.

LocatorBuilders.add('label', function(e) {
// must be an input element to apply this strategy...
if ('input' != e.tagName.toLowerCase()) return null;

path = null;
type = e.getAttribute("type").toLowerCase();
if (type == 'submit') {
value = e.getAttribute("value");
return "submit=" + value;
}
if (e.id) {
label = this.findElement("//label[@for='" + e.id + "']");

if (label && label.textContent != "") {
value = label.textContent.replace(/\xA0/g, " ").replace(/^\s*(.*?)\s*$/, "$1");

if (value.length > 50) {
value = value.substring(0,50) + "...";
}
value = "label=" + value;
return value;
}
}

return null;
});