4

I have a XPath that will select a specific radio button item of my HTML. I would like to enhance my locator to be more dynamic by using a stored variable to represent the text for which my XPath is using to lock on.

This is my current setup

Command: Click

Target:

//*[contains(@for,'Page149.Question48.TypeChoiceOneAnswerRadioButton.holder_ctl02')
and text()="Below 70 – May be too low"]

I would like to replace the literal text "Below 70 – May be too low" with a variable. My proposed Target is failing to evaluate. I hope I just have the syntax incorrect.

Can I do this? Can I use stored variables with XPath locators?

Proposed Target:

//*[contains(@for,'Page149.Question48.TypeChoiceOneAnswerRadioButton.holder_ctl02')
and text()=${radioText}] 

EDIT: Adding code. I made a simple example of my HTML radio button list and isolated my Selenium commands. I am using the Selenium IDE in the Firefox. My commands example has comments.

Sample HTML

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>Untitled Page</title>
</head>
<body>
    <table border="0" class="srvy_radiobuttonlist" id="ctl00_cphSurveyControls_surveyCategoryPage_Page51.Question5.TypeChoiceOneAnswerRadioButton.holder_ctl02">
        <tbody>
            <tr>
                <td>
                    <input type="radio" checked="checked" value="Page51.Question5.Answer580" name="ctl00$cphSurveyControls$surveyCategoryPage$Page51.Question5.TypeChoiceOneAnswerRadioButton.holder$ctl02"
                        id="ctl00_cphSurveyControls_surveyCategoryPage_Page51.Question5.TypeChoiceOneAnswerRadioButton.holder_ctl02_0"><label
                            for="ctl00_cphSurveyControls_surveyCategoryPage_Page51.Question5.TypeChoiceOneAnswerRadioButton.holder_ctl02_0">Male</label>
                </td>
                <td>
                    <input type="radio" value="Page51.Question5.Answer581" name="ctl00$cphSurveyControls$surveyCategoryPage$Page51.Question5.TypeChoiceOneAnswerRadioButton.holder$ctl02"
                        id="ctl00_cphSurveyControls_surveyCategoryPage_Page51.Question5.TypeChoiceOneAnswerRadioButton.holder_ctl02_1"><label
                            for="ctl00_cphSurveyControls_surveyCategoryPage_Page51.Question5.TypeChoiceOneAnswerRadioButton.holder_ctl02_1">Female</label>
                </td>
            </tr>
        </tbody>
    </table>
</body>
</html>

Mocked up Selenium IDE

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head profile="http://selenium-ide.openqa.org/profiles/test-case">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<link rel="selenium.base" href="http://localhost" />
<title>LocatorTest</title>
</head>
<body>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">LocatorTest</td></tr>
</thead><tbody>
<!--Select Male-->
<tr>
    <td>click</td>
    <td>//*[contains(@id,'Page51.Question5.TypeChoiceOneAnswerRadioButton.holder_ctl02_0')]</td>
    <td></td>
</tr>
<tr>
    <td>store</td>
    <td>Female</td>
    <td>Gender</td>
</tr>
<tr>
    <td>assertTextPresent</td>
    <td>${Gender}</td>
    <td></td>
</tr>
<tr>
    <td>assertTextPresent</td>
    <td>javascript{ storedVars['Gender']}</td>
    <td></td>
</tr>
<!--FYI, locates first item in radio collection-->
<tr>
    <td>click</td>
    <td>//*[contains(@for,'Page51.Question5.TypeChoiceOneAnswerRadioButton.holder_ctl02')]</td>
    <td></td>
</tr>
<!--Works to select female-->
<tr>
    <td>click</td>
    <td>//*[contains(@for,'Page51.Question5.TypeChoiceOneAnswerRadioButton.holder_ctl02') and text()='Female']</td>
    <td></td>
</tr>
<tr>
    <td>click</td>
    <td>//*[contains(@for,'Page51.Question5.TypeChoiceOneAnswerRadioButton.holder_ctl02') and contains(text(),'Female')]</td>
    <td></td>
</tr>
<!---- not found -->
<tr>
    <td>click</td>
    <td>//*[contains(@for,'Page51.Question5.TypeChoiceOneAnswerRadioButton.holder_ctl02') and contains(text(),${Gender})]</td>
    <td></td>
</tr>
<!--Works to select female-->
<tr>
    <td>click</td>
    <td>//*[contains(text(),'Female')]</td>
    <td></td>
</tr>
<!---- not found -->
<tr>
    <td>click</td>
    <td>//*[contains(text(),${Gender})]</td>
    <td></td>
</tr>
</tbody></table>
</body>
</html>
MADCookie
  • 2,596
  • 3
  • 26
  • 46

3 Answers3

4

You need quotation marks around the variable.

//*[contains(text(),'${Gender}')]

And yes, I have successfully used an XPath locator with stored variables, though it was not with 'click' but with 'waitForXpathCount'. At first it didn't work and I had to resort to printf-debugging to get to the cause. The reason it didn't work is irrelevant here(I didn't set the target appropriately), but I think a list of relevant files will be of interest to those having trouble with Selenium IDE.

Location of the files on a Mac:

~/Library/Application Support/Firefox/Profiles/[your profile]/extensions/{a6fd85ed-e919-4a43-a5af-8da18bda539f}/chrome/content/selenium-core/scripts/

Important files:

  • selenium-api.js
    Core command handlers. ex. Selenium.prototype.doClick
  • selenium-browserbot.js
    Responsible for interfacing with the browser. The doClick handler above calls BrowserBot.prototype.findElement, for instance.
  • selenium-executionloop.js
    Calls command handlers. Most importantly in this case, preprocesses the locator string with selenium.preprocessParameter(command.target). selenium.preprocessParameter can be found in selenium-api.js.
  • htmlutils.js
    Provides XPathEvaluator

How to print to the IDE log:

LOG.error("Useful debugging information");

You need to restart Firefox each time you make a change to Selenium IDE's internals (I couldn't find a way to reload it on the fly).

Additionally, you can test your XPath expression like $x("xpath/expr/with/stored/variables/replaced/accordingly") on a normal Firefox JS console.

ento
  • 5,801
  • 6
  • 51
  • 69
  • The follow code worked for me: `//*[contains(text(),'${Gender}')]` My specific solution was: `//a[contains(text(), '${categoryName}' )]/following-sibling::a` – Campinho Nov 07 '12 at 13:06
0

What is the HTML element you are selecting? Can you provide the HTML? Yes, this is possible. What binding are you using? ie. Python, Ruby, Java???

You can do something like this:

var = selenium.get_eval(locator)
kenneth koontz
  • 849
  • 1
  • 8
  • 16
0

Yes, that should work just fine. The documentation shows a simple example:

type    |   textElement |   Full name is: ${fullname}

The obvious question would be "Where did you get the value of radioText from?", followed closely by "Are you sure there is no other text in it?" (because you coded "text()='xxx'", not "contains(text(), '...')". Or perhaps you really did leave out the quotes in the code, not just in your example (i.e., "text()=xxx", not "text()='xxx'")?

Ross Patterson
  • 9,527
  • 33
  • 48
  • I added code samples to help illustrate. Your feedback is not clear to me as to what you mean. – MADCookie Apr 29 '11 at 19:28
  • I ran your test in Firefox 3.6.17 with Selenium IDE 1.0.10. It ran successfully. The log is doesn't fit in a comment, but here's the useful part. # [info] Executing: |store | Female | Gender | # [info] Executing: |assertTextPresent | ${Gender} | | # [info] Executing: |assertTextPresent | javascript{ storedVars['Gender']} | | Then I changed "Female" to "Banana", and got this: # [info] Executing: |store | Banana | Gender | # [info] Executing: |assertTextPresent | ${Gender} | | # [error] false – Ross Patterson May 04 '11 at 18:35