I have a site I need to login to but one of the input text fields id and name change each time. Is there a way to access element via a regex? Thanks in advance.
Example:
id="form:wrap:j_idt1297:0:j_idt1298:input"
id="form:wrap:j_idt2151:0:j_idt2152:input"
<input class="iceInpSecrt large"
id="form:wrap:j_idt1297:0:j_idt1298:input"
name="form:wrap:j_idt1297:0:j_idt1298:input"
onblur="setFocus('');" onfocus="setFocus(this.id);"
onkeyup="iceSubmit(form,this,event);"
onmousedown="this.focus();" tabindex="" type="password" value="">
Yes, you can match elements using regular expressions. It is similar to locating the id/name by string.
It looks like:
browser.text_field(:id => /a_regex/)
For your example, the following would locate the text field with either of the ids mentioned:
browser.text_field(:id => /form:wrap:j_idt\d{4}:0:j_idt\d{4}:input/)
Note:
You will need to verify that this regex will not end up also matching other elements on the page. If it does, you will need to make your search more specific by using other information about the element (perhaps the class) or information around the element (perhaps the field's label).
Depending on the other elements on the page, this regex might be more specific than you need. For example, perhaps just the first part is unique. In that case you could just do /form:wrap:j_idt/.
Related
I am trying to get xpath for following html code, but nothing seems to be working. I appreciate your suggestion. I need to get the xpath based on text.
<label class="label" securityidpath="ACCOUNTS_FS.PART_ACCOUNT_HEADER_FS.PART_ACCOUNT_STATUS" title="Part Account Status">Part Account Status:
</label>
FYI, I tried following variant xpath
//label[normalize-space(text())='Part Account Status:\u00a0']
//label[normalize-space(text())='Part Account Status:\u000a']
//label[normalize-space(text())='Part Account Status:\u202f']
and all the options as per following url https://en.wikipedia.org/wiki/Whitespace_character
Thank You,
Yougander
You can use
/label[normalize-space(text())='Part Account Status: ']
Or use the hexadecimal variant instead of the decimal .
Also note that XPath uses slashes (and not backslashes) to define paths, so referencing the root node label would be done by /label.
The typo lable instead of label is trivial.
BTW you can avoid the trouble with the entity by using the title attribute in your XPath:
label[normalize-space(#title)='Part Account Status']
your element name is wrong and change UTF character name as HexaDecimal entity values:
//label[normalize-space(text())='Part Account Status: ']
XPATH require forward slash
So I have an application which holds multiple entries that are strings of comma separated emails. The strings live in text area elements where they can be modified. The application uses JavaScript to modify these strings, I need to use Capybara to watch verify that a target string has the correct number of emails in it. To illustrate what I mean here's my Cucumber (assuming the target list starts with a 5 email string):
When I remove the 3rd email under list one
Then I should see 4 emails under list one
When I click the "Cancel" button for list one
Then I should see 5 emails under list one
I can pretty easily grab the string with Capybara like so:
expect(page).to have_css(".css-selectors textarea")
but I don't know what to do from there. I need to be able to assert that the number of emails in the string is in fact changing to the desired number. I need to split the string and count the number of emails to see if they match the target number, but everything I've tried leads to a race condition where Capybara checks the value before the JS can finish updating. I've looked into passing a filter block to the have_css call but I can't find documentation on how that would work, or if it's even the right tactic. And so I'm out of ideas here.
Since all the emails are in one element your inclination to use a filter block is exactly correct. The filter block receives each element that matches the initial selector and needs to return whether or not it matches whatever extra filtering you wish to do (true/false). Therefore, to check that the element had a string (value not text since it's a form field) with 4 comma separated items it would be something like
expect(page).to have_css(".css-selectors textarea"){ |ta|
ta.value.split(',').size == 4
}
This will then use Capybaras waiting/retrying behavior while also performing the extra step of checking for a matching number of comma separated items in the text of the element, thereby getting around the race condition.
Your check could also be performed by using a regex for the with option of the field selector, along the lines of
expect(page).to have_field(type: 'textarea', with: /^[^,]+,[^,]+,[^,]+,[^,]+$/)
or fillable_field selector
expect(page).to have_selector(:fillable_field, type: 'textarea', with: /^[^,]+,[^,]+,[^,]+,[^,]+$/)
Those don't currently scope to the .css-selectors element but you could do that with within or a chained find. You could also ensure a unique element by passing the id/name/label text of the element. Obviously you could make the regex more complicated if you want to actually verify the text strings are emails, etc.
I used Firebug's Inspect Element to capture the XPath in a webpage, and it gave me something like:
//*[#id="Search_Fields_profile_docno_input"]
I used the Bookmarklets technique in IE to capture the XPath of the same object, and I got something like:
//INPUT[#id='Search_Fields_profile_docno_input']
Notice, the first one does not have INPUT instead has an asterisk (*). Why am I getting different XPath expressions? Does it matter which one I use for my tests like:
Selenium.Click(//*[#id="Search_Fields_profile_docno_input"]);
OR
Selenium.Click(//INPUT[#id='Search_Fields_profile_docno_input']);
*[Id=] denotes that it can be any element while the second one clearly mentions selenium to look ONLY for INPUT fields which have id as Search_Fields_profile_docno_input. The second xpath is better due to following reasons
It takes more time to find the element using * as IDs of all elements should be matched.
If your HTML code is not "well written" there could be other elements which have the same id and this could cause your test to fail.
The first one matches any element with a matching ID, whereas the second one restricts matches to <input> elements. If these were CSS expressions it'd be the difference between #Search_Fields_profile_docno_input and input#Search_Fields_profile_docno_input.
Assuming you only use this ID once in your web page, the two XPaths are effectively equivalent. They'll both match the <input id="Search_Fields_profile_docno_input"> element and no other.
There are some good answers to your "why?" question here, but for Selenium use, there's an even better alternative. Since your page element has an ID attribute, use Selenium's ID locator instead of XPath or CSS:
Selenium.Click("id=Search_Fields_profile_docno_input");
This will go directly to the element, and will run quicker than just about any other locator. Note that the syntax is id=value, not id="value".
Given any element in your document, there's an infinite number of XPath expressions that will select it uniquely. Therefore it's entirely reasonable for two different products to generate two different paths.
Google has just released Wicked Good XPath - A rewrite of Cybozu Lab's famous JavaScript-XPath. Link: https://code.google.com/p/wicked-good-xpath/ The rewritten version is 40% smaller and about %30 faster than the original implementation.
You can check this out and replace the one being used in Selenium.
I'm trying to parse a webpage to get posts from a forum.
The start of each message starts with the following format
<div id="post_message_somenumber">
and I only want to get the first one
I tried xpath='//div[starts-with(#id, '"post_message_')]' in yql without success
I'm still learning this, anyone have suggestions
I think I have a solution that does not require dealing with namespaces.
Here is one that selects all matching div's:
//div[#id[starts-with(.,"post_message")]]
But you said you wanted just the "first one" (I assume you mean the first "hit" in the whole page?). Here is a slight modification that selects just the first matching result:
(//div[#id[starts-with(.,"post_message")]])[1]
These use the dot to represent the id's value within the starts-with() function. You may have to escape special characters in your language.
It works great for me in PowerShell:
# Load a sample xml document
$xml = [xml]'<root><div id="post_message_somenumber"/><div id="not_post_message"/><div id="post_message_somenumber2"/></root>'
# Run the xpath selection of all matching div's
$xml.selectnodes('//div[#id[starts-with(.,"post_message")]]')
Result:
id
--
post_message_somenumber
post_message_somenumber2
Or, for just the first match:
# Run the xpath selection of the first matching div
$xml.selectnodes('(//div[#id[starts-with(.,"post_message")]])[1]')
Result:
id
--
post_message_somenumber
I tried xpath='//div[starts-with(#id,
'"post_message_')]' in yql without
success I'm still learning this,
anyone have suggestions
If the problem isn't due to the many nested apostrophes and the unclosed double-quote, then the most likely cause (we can only guess without being shown the XML document) is that a default namespace is used.
Specifying names of elements that are in a default namespace is the most FAQ in XPath. If you search for "XPath default namespace" in SO or on the internet, you'll find many sources with the correct solution.
Generally, a special method must be called that binds a prefix (say "x:") to the default namespace. Then, in the XPath expression every element name "someName" must be replaced by "x:someName.
Here is a good answer how to do this in C#.
Read the documentation of your language/xpath-engine how something similar should be done in your specific environment.
#FindBy(xpath = "//div[starts-with(#id,'expiredUserDetails') and contains(text(), 'Details')]")
private WebElementFacade ListOfExpiredUsersDetails;
This one gives a list of all elements on the page that share an ID of expiredUserDetails and also contains the text or the element Details
I have such content of html file:
<a class="bf" title="Link to book" href="/book/229920/">book name</a>
Help me to construct xpath expression to get link text (book name).
I try to use /a, but expression evaluates without results.
If the context is the entire document you should probably use // instead of /. Also you may (not sure about that) need to get down one more level to retrieve the text.
I think it should look like this
//a/text()
EDIT: As Tomalak pointed out it's text() not text
Have you tried
//a
?
More specific is better:
//a[#class='bf' and starts-with(#href, '/book/')]
Note that this selects the <a> element. In your host environment it's easy to extract the text value of that node via standard DOM methods (like the .textContent property).
To select the actual text node, see the other answers in this thread.
It depends also on the rest of your document. If you use // in the beginning all the matching nodes will be returned, which might be too many results in case you have other links in your document.
Apart from that a possible xpath expression is //a/text().
The /a you tried only returns the a-tag itself, if it is the root element. To get the link text you need to append the /text() part.