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

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")

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

Xpath expression pulling multiple items despite specifying item with [ ]

I am trying to write an XPath expression which can return the URL associated with the next page of a search.
The URL which leads to the next page of the search is always the href in the a tag following the tag span class="navCurrentPage" I have been trying to use a following-sibling term to pull the next URL. My search in the Chrome console is:
$x('//span[#class="navCurrentPage"][1]/following-sibling::a/#href[1]')
I thought by specifying #href[1] I would only get back one URL (thinking the [1] chooses the first element in list), but instead Chrome (and Scrapy) are returning four URLs. I don't understand why. Please help me to understand how to select the one URL that I am looking for.
Here is the URL where you can find the HTML giving me trouble:
https://www.yachtworld.com/core/listing/cache/searchResults.jsp?cit=true&slim=quick&ybw=&sm=3&searchtype=advancedsearch&Ntk=boatsEN&Ntt=&is=false&man=&hmid=102&ftid=101&enid=0&type=%28Sail%29&fromLength=35&toLength=50&fromYear=1985&toYear=2010&fromPrice=&toPrice=&luom=126&currencyid=100&city=&rid=100&rid=101&rid=104&rid=105&rid=107&rid=108&rid=112&rid=114&rid=115&rid=116&rid=128&rid=130&rid=153&pbsint=&boatsAddedSelected=-1
Thank you for the help.
Operator precedence: //x[1] means /descendant-or-self::node()/child::x[1] which finds every descendant x that is the first child of its parent. You want (//x)[1] which finds the first node among all the descendants named x.
xpath index will apply on all matching records, if you want to get only the first item, get the first instance.
$x('//span[#class="navCurrentPage"][1]/following-sibling::a/#href[1]').extract_first()
just add, .extract_first() or .get() to fetch the first item.
see the scrapy documentation here.
I've found this very helpful to make sure you have the bracket in the right place.
What is the XPath expression to find only the first occurrence?
also, the first occurrence may be [0] not [1]

Xpath Error: Can not convert #STRING to a NodeList

In one of the API solution, incoming request is in XML format, and i need to fetch first child node tag name to make decision to run the logic. I am using xpath to get the tag name, when in am running xpath i am getting error "Can not convert #STRING to a NodeList"
I have tried with local-name and name, but both are giving same error.
my xml is as below
<p:Check xmlns:p="http://amarwayx.com.cu/WCSXMLSchema/creptonium">
<AttributeChnageLocal>
<TaskID>17723</TaskID>
<BatchID>12345</BatchID>
<Expiry>2022-12-06</Expiry>
<TimeStamp>2019-07-20T22:45:48</TimeStamp>
</AttributeChnageLocal>
</p:Check>
and Xpath i used are
local-name(/p:Check/*)
name(/p:Check/*)
local-name(/p:Check/*[1])
name(/p:Check/*[1])
how ever is some online xpath evaluator has evaluated correct name(AttributeChnageLocal), i am not getting where the xpath syntax is wrong.
below is my tool snapshot.
same kind of expression works fine
You have ticked a box labelled "store the string value of the selected node as text", which suggests that the XPath evaluation tool you are using expects your XPath expression to select a node; but it doesn't, it selects a string.
I don't know what this tool you are using is, but unfortunately all its options seem to assume that you are selecting nodes.

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`

Make 1 page objects Two Elements ID's to 1 page object Variable

I am using the page object Gem with Watir. During testing I found that I have a field that has the same contents that show in the same location but have separate unique ID's. The difference is before you get to the page.
I tried using Xpaths:
select_list(:selectionSpecial, :xpath => "//select[#id='t_id9' OR #id='t_id7']")
But was met with a script error.
They are static ID's but I want to force them into one variable since that would allow me to use "populate_page_with" feature.
I have a long winded way currently, but I am fishing for a more efficient way that works with the page object Features.
Does anyone know of a way to do this?
Your approach of using xpath can work. The problem is the syntax errors in the xpath selector. It should be:
"//select[#id='t_id9' or #id='t_id7']"
Note:
The start should be a // rather than a \
Using or is case-sensitive; it has to be lower case
There was also a missing closing ' for the first id attribute
Personally, I find css and xpath selectors harder to use. I would go with the id locator with a regex. The following gives the same results, but some will find it easier to read.
select_list(:selectionSpecial, :id => /^t_id(7|9)$/)

Resources