How do I verify an xPath expression in Selenium IDE? - xpath

How would I test for the following expression in Selenium?
not(//select[#id='ddlCountry']/#class) or
not(contains(//select[#id='ddlCountry']/#class,'invalidValue'))
true if the class attribute doesnt exist, or if it does, the attribute doesn't contain invalidValue.
I've tried using the verifyElementPresent command, but it errors out, I assume because I'm returning a boolean rather than a node.
I'm happy with an alternative to this if theres no way to do the above using xPath.

In case your XPath engine API doesnt allow expressions returning atomic values (not nodes), then you still can
Use:
//select[#id='ddlCountry'][contains(#class,'invalidValue')]
and test if an element was selected or not.

true if the class attribute doesnt
exist, or if it does, the attribute
doesn't contain invalidValue.
not(//select[#id='ddlCountry']/#class[contains(.,'invalidValue')])

Related

Cypress xpath plugin does not work with cy.type()

I am unable to figure out why the cypress xpath is not working with the type(). I have two command functions: one that looks for the element using cy.get() and one that uses cy.xpath(). Unfortunately, this is a dynamic field so I have to use xpath.
(https://i.stack.imgur.com/wXl9q.png)
This is how I am using the above command.
(https://i.stack.imgur.com/snVn7.png)
Error:
(https://i.stack.imgur.com/08G32.png)
I tried to reading the cypress docs and searching on the internet, however the examples for solutions did not work. I am on on Electron version: 21.0.0, Bundled Node version:
16.16.0
I think you are mistaken about the results of your xpath expression.
You have used //div[5]/div[1]/input which can return multiple elements.
The // predicate will "select all" if they are present.
Only / predicate is guaranteed to return a single element.
Since Cypress is telling you it found multiple elements, it is more likely that your selector is wrong than the Cypress library.
You will have to change the xpath selector.
The answer is in your error message - you're trying to use cy.type() but the previous command (cy.xpath()) is yielding more than one element. I would focus on figuring out what differentiates the field you want to type in from the others found by cy.xpath(). If there is nothing different between them, then you can simply select the correct element by the 0-index of the element.
cy.xpath(element).eq(0).type(value); // assumes the first element yielded by cy.xpath

How to search multiple locators using a single find in ruby capybara?

In Ruby/Capybara, I tried searching multiple(two) locators(css) in a single find query and found that it automatically search both of them and perform the action on the locator which is present on page.
Ex-
find("css1","css2").set "ABC"
I observed that while running the script, at run time it search for both the locators and will perform the action on the one which is present on page.
However, When I tried the same logic using xpath, it dont work and throw element not found error or invalid selector(one xpath is present on page).
ex-
find(:xpath,"xpath1","xpath2").set "ABC"
Can anyone please help how we can do it for xpath also in ruby capybara.
The example you show of find("css1","css2").set "ABC" won't actually do anything with the "css2" argument passed and, in the current version of Capybara, will actually emit a warning about unused parameters. What will work would be
find("css1, css2").set("ABC")
because it's using the grouping comma which will find items matching either css1 or css2. In XPath you can do that with the union operator | which will return elements that match xpath1 or xpath2
find(:xpath, "xpath1 | xpath2").set("ABC")

getting attribute via xpath query succesfull in browser, but not in Robot Framework

I have a certain XPATH-query which I use to get the height from a certain HTML-element which returns me perfectly the desired value when I execute it in Chrome via the XPath Helper-plugin.
//*/div[#class="BarChart"]/*[name()="svg"]/*[name()="svg"]/*[name()="g"]/*[name()="rect" and #class="bar bar1"]/#height
However, when I use the same query via the Get Element Attribute-keyword in the Robot Framework
Get Element Attribute//*/div[#class="BarChart"]/*[name()="svg"]/*[name()="svg"]/*[name()="g"]/*[name()="rect" and #class="bar bar1"]/#height
... then I got an InvalidSelectorException about this XPATH.
InvalidSelectorException: Message: u'invalid selector: Unable to locate an
element with the xpath expression `//*/div[#class="BarChart"]/*[name()="svg"]/*
[name()="svg"]/*[name()="g"]/*[name()="rect" and #class="bar bar1"]/`
So, the Robot Framework or Selenium removed the #-sign and everything after it. I thought it was an escape -problem and added and removed some slashes before the #height, but unsuccessful. I also tried to encapsulate the result of this query in the string()-command but this was also unsuccessful.
Does somebody has an idea to prevent my XPATH-query from getting broken?
It looks like you can't include the attribute axis in the XPath itself when you're using Robot. You need to retrieve the element by XPath, and then specify the attribute name outside that. It seems like the syntax is something like this:
Get Element Attribute xpath=(//*/div[#class="BarChart"]/*[name()="svg"]/*[name()="svg"]/*[name()="g"]/*[name()="rect" and #class="bar bar1"])#height
or perhaps (I've never used Robot):
Get Element Attribute xpath=(//*/div[#class="BarChart"]/*[name()="svg"]/*[name()="svg"]/*[name()="g"]/*[name()="rect" and #class="bar bar1"])[1]#height
This documentation says
attribute_locator consists of element locator followed by an # sign and attribute name, for example "element_id#class".
so I think what I've posted above is on the right track.
You are correct in your observation that the keyword seems to removes everything after the final #. More correctly, it uses the # to separate the element locator from the attribute name, and does this by splitting the string at that final # character.
No amount of escaping will solve the problem as the code isn't doing any parsing at this point. This is the exact code (as of this writing...) that performs that operation:
def _parse_attribute_locator(self, attribute_locator):
parts = attribute_locator.rpartition('#')
...
The simple solution is to drop that trailing slash, so your xpath will look like this:
//*/div[#class="BarChart"]/... and #class="bar bar1"]#height`

XPath: nested/complex conditions

a certain element of my xml data should match EXACT ONE of the following conditions:
1.) It has a #when attribute and nothing else.
2.) It has a #when-iso attribute and nothing else.
3.) It has both a #notBefore-iso and a #notAfter-iso attribute, but neither a #when nor a #when-iso attribute.
I try to test that using schematron, but I fail at creating a matching xpath expression.
I tried
<assert test="#when or #when-iso or (not(#when) and not(#when-iso) and #notBefore-iso and #notAfter-iso)">
but that doesn't work. Obviously, the content in brackets is simply ignored. So, how can I build complex/nested conditional expressions?
An example that should work for your case :
<assert test="(#when and count(#*)=1) or (#when-iso and count(#*)=1) or (#notBefore-iso and #notAfter-iso and count(#*)=2)"/>

Can't get nth node in Selenium

I try to write xpath expressions so that my tests won't be broken by small design changes. So instead of the expressions that Selenium IDE generates, I write my own.
Here's an issue:
//input[#name='question'][7]
This expression doesn't work at all. Input nodes named 'question' are spread across the page. They're not siblings.
I've tried using intermediate expression, but it also fails.
(//input[#name='question'])[2]
error = Error: Element (//input[#name='question'])[2] not found
That's why I suppose Seleniun has a wrong implementation of XPath.
According to XPath docs, the position predicate must filter by the position in the nodeset, so it must find the seventh input with the name 'question'. In Selenium this doesn't work. CSS selectors (:nth-of-kind) neither.
I had to write an expression that filters their common parents:
//*[contains(#class, 'question_section')][7]//input[#name='question']
Is this a Selenium specific issue, or I'm reading the specs wrong way? What can I do to make a shorter expression?
Here's an issue:
//input[#name='question'][7]
This expression doesn't work at all.
This is a FAQ.
[] has a higher priority than //.
The above expression selects every input element with #name = 'question', which is the 7th child of its parent -- and aparently the parents of input elements in the document that is not shown don't have so many input children.
Use (note the brackets):
(//input[#name='question'])[7]
This selects the 7th element input in the document that satisfies the conditions in the predicate.
Edit:
People, who know Selenium (Dave Hunt) suggest that the above expression is written in Selenium as:
xpath=(//input[#name='question'])[7]
If you want the 7th input with name attribute with a value of question in the source then try the following:
/descendant::input[#name='question'][7]

Resources