Text validation on a webpage where multiple elements have the same label - ruby

I have the following code as part of a test:
if page.text.include? "Provide your details"
go_and_enter_details
end
The webpage has multiple elements labelled h2, including the one that's being checked for content.
This error is returned:
Ambiguous match, found 3 elements matching css "h2" (Capybara::Ambiguous)
How can get Ruby/Cucumber/Capybara to identify whether the page contains the text I need to check?

You have various options:
if the element you want to fill is the first one in the page, you can use first element
first('YOUR ELEMENT').click
you can use within, so you can tell capybara where to find your element (for example, in a div)
within('body > div > div') do
#find your element and do your work
end
you can use the CSS selector or the XPath of your element

Related

How to find the exact element path without using xpath

I'm currently trying to locate this check box. I know I can use a xpath to locate it but I'm trying to see if there's a more efficient way of doing it. The problem I'm seeing is that there are multiple div class with the same name. I'm trying to find this specific one and isolate it. I'm trying to make my code more efficient if possible.
Xpath
/html/body/div/div/div/div[1]/cow-data/cat-panel/section/div[1]/div/div/md- checkbox[4]/div[1]
Element path:
<div class="cd-container" cd-gar-ripple="" cd-gar-ripple-checkbox=""><div class="cd-icon"></div></div>
Code I'm trying to use:
find('cd-container').click
The problem I'm seeing is that the div id 'cd-container' has multiple occurrences on the page and thus this doesn't work. I'm trying to see if I can find a more efficient way of doing this.
As per the HTML cd-container is the value of the class attribute but not id attribute. So your effective line of code will be:
find('.cd-container').click
If you want to find an element (AND THEN), return it's xpath. Use capybara.
This will allow you to locate using text / css selector. And then you can just return the path of the element.
i.e.
page.find('td', text: 'Column 1').path # Random td with text
page.find('#main').path # ID
page.all('div').select { |element| element.text == 'COoL dIv' }.first.path # First div that matches certain text
page.find('.form > div:nth-of-type(2)').path # Specific structured div
page.all('p div li:nth-child(3)').sample.path # Random li

How to ignore non visible elements in xPath?

I want to ignore elements from my xpath query that are not visible, either because they or any of their ancestors are display:none.
I tried the below, but it's including elements which non displayable ancestors
//button[
not(contains(#style,'display:none'))
and
not(ancestor::div[contains(#style,'display:none')])
and
contains(translate(., 'ABCDEFGHIJKLMNÑOPQRSTUVWXYZ', 'abcdefghijklmnñopqrstuvwxyz'), 'acept')
]
"
Try to apply this
//*[not(ancestor-or-self::*[contains(#style,'display: none;')])]

XPATH - how to get the text if an element contains a certain class

JHow do I grab this text here?
I am trying to grab the text here based on that the href contains "#faq-default".
I tried this first of all but it doesn't grab the text, only the actual href name, which is pointless:
//a/#href[contains(., '#faq-default-2')]
There will be many of these hrefs, such as default-2, default-3 so I need to do some kind of contains query, I'd guess?
You are selecting the #href node value instead of the a element value. So try this instead:
//a[contains(#href, '#faq-default-2')]

Get element name by containing text

I'm looking through HTML documents for the text: "Required". What I need to find is the element that holds the text. For example:
<p>... Required<p>
I would get to element name = p
However, it might not be in a <p> tag. It could be in any kind of tag, which is where this question differs from some of the other search text Stack Overflow questions.
Right now I'm using:
page.at(':contains("Required")')
but this only get me the full HTML element
The problem you have is the :contains pseudo class matches any element that has the searched for text anywhere in its descendants. You need to find the innermost element that contains such text. Since html is the ancestor of all elements, if the page contains the text anywhere then html will contain, and so that will be the first matching element.
I’m not sure you can achieve this with CSS, but you can use XPath like this:
page.at_xpath('//*[text()[contains(., "Required")]]')
This finds the first element node that has a text() node as a child that contains Required. When you have that node (if it exists) you can then call name on it to give the name of the element.
For CSS you can do:
page.at('[text()*="Required"]')
It's not real CSS though, or even a jQuery extra.
You should use CSS selectors:
page.css('p').text

How to find the first link on the page containing this text?

If I have two links:
<div class="abc">
<a id="def1" href="/definitely">Definitely 1</a>
<a id="def2" href="/definitely">Definitely 2</a>
</div>
And I want to identify the first (def1), I thought this would work:
var linkXPath = "//div[#class='abc']//a[contains(#href,'def')][1]";
But it doesn't seem to.
What am I doing wrong?
It is a FAQ why
//someName[1]
doesn't select the first element of //someName.
Looking at the definition of the // abbreviation, one would realize that in fact
//someName[1]
is equivalent to:
/descendant-or-self::node()/someName[1]
and this selects every someName element that is the first someName child of its parent node.
Thus, if there are two or more someName elements that are the first someName child of their parent, all of them are selected.
Solution:
Instead of
//someName[1]
use:
(//someName)[1]
So, in your particular case use:
(//div[#class='abc']//a[contains(#href,'def')]) [1]
Apart from this, none of the above expressions would select any node, if in the actual XML document a default namespace was specified. Selecting nodes in a document with a default namespace is the biggest XPath FAQ. To find the solution just search for "default namespace" in this SO tag and anywhere on the Internet.
Your XPath expression selects the first a element (with the right href) of every div (that has the right class) that contains one. So if there were two divs that matched, each with multiple a elements that matched, you'd get a reault set containing two elements -- the first a in the first div, and the first a in the second div.
To select just the first element of the entire result set, use parentheses like so:
(//div[#class='abc']//a[contains(#href,'def')])[1]
Other than that, your expression works fine for me (tested here).

Resources