XPath Following-Dibling Not Contains and Following-Sibling Contains Topic - xpath

Here it is the source code output:
When I use this code: //b[text()= 'SEM Grubu']/following-sibling::span[text()[not(contains(., 'Sil'))]] gives me "Dosyayı İndir" button selected.
But I want to select this element with not contains 'Sil' button just only 'Dosyayı İndir' button like this code:
//b[text()= 'SEM Grubu']/following-sibling::span[text()[not(contains(., 'Sil'))]]/following-sibling::span[text()='Dosyayı İndir']
If you help me, I appreciate it.

Related

xPath: fetch element with an attribute containing the text of another element

Given I have the following HTML structure:
<button aria-labelledby="ref-1" id="foo" onclick="convey(event)">action 2</button>
<div class="anotherElement">foobar</div>
<div id="ref-1" hidden>target 2</div>
I would like to fetch button by its aria-labelledby attribute. I tried the following options:
//*[#aria-labelledby=string(/div[#id="ref-1"]/#id)]
//*[#aria-labelledby = string(.//*[normalize-space() = "target 2"]/#id)]
//*[#aria-labelledby = .//*[normalize-space() = "target 2"]/#id]
But wasn't able to fetch the element. Anyone has an idea what the right xPath could be?
Edit: simply put: how do I fetch the button element if my only information is "target 2", and if both elements can be randomly located?
//button[#aria-labelledby='ref-1']
or
//button[#aria-labelledby=(//*/#id)]
or
//button[#aria-labelledby=(//*[contains(.,'target 2')]/#id)]
or
//button[#aria-labelledby=(//*[contains(text(),'target 2')]/#id)]
?
Since button and div are the same level siblings here you can use preceding-sibling XPath expression like this:
//div[text()='target 2']//preceding-sibling::button
pay attention with with your actual XML this will match 2 button elements.
To make more precise math I think we will need to be based on more details, not only the target 2 text

XPATH select second item (not child)

I was trying to get only the first element:
<xml>
<title>xpath.playground.fontoxml.com</title>
<summary>This is a learning tool for XML, XPath and XQuery.</summary>
<tips>
<tip id='1' name='hello'>You can edit everything on the left</tip>
<tip id='examples'>You can access more examples from a menu in the top right</tip>
<tip id='permalink'>Another button there lets you share your test using an URL</tip>
</tips>
<tips>
<tip id='2' name='hello'>You can edit everything on the left</tip>
<tip id='examples'>You can access more examples from a menu in the top right</tip>
<tip id='permalink'>Another button there lets you share your test using an URL</tip>
</tips>
</xml>
This is the XPATH, im trying to get one element from all with name='hello'
//*[#name='hello'][1]
but it returns both <tip id='1' name='hello'> and <tip id='2' name='hello'>
my expectation was //*[#name='hello'][1] returns the element with id=1 and //*[#name='hello'][2] returns the element with id=2
how do I get this result
Please try this:
(//*[#name='hello'])[2]

The <title> of the page is changing. How to get it with XPath?

Got the page with dynamic <title> tag depending on language selected by user, e.g.
<title>English</title> or <title>Italiano</title>
I'm trying to select that page among many others with XPath selector:
//*[contains(#title, 'English') or contains(#title, 'Italiano')]
but it doesn't work at all.
Also tried
(//*[contains(#title, 'English')] | //*[contains(#title, 'Italiano')])[1] - no positive result
title is not an attribute, so no need to add #:
//*[contains(title, 'English') or contains(title, 'Italiano')]
This will return parent node. If you want to select title node then try
//title[.='English' or .='Italiano']

Xpath get element above

suppose I have this structure:
<div class="a" attribute="foo">
<div class="b">
<span>Text Example</span>
</div>
</div>
In xpath, I would like to retrieve the value of the attribute "attribute" given I have the text inside: Text Example
If I use this xpath:
.//*[#class='a']//*[text()='Text Example']
It returns the element span, but I need the div.a, because I need to get the value of the attribute through Selenium WebDriver
Hey there are lot of ways by which you can figure it out.
So lets say Text Example is given, you can identify it using this text:-
//span[text()='Text Example']/../.. --> If you know its 2 level up
OR
//span[text()='Text Example']/ancestor::div[#class='a'] --> If you don't know how many level up this `div` is
Above 2 xpaths can be used if you only want to identify the element using Text Example, if you don't want to iterate through this text. There are simple ways to identify it directly:-
//div[#class='a']
From your question itself you have mentioned the answer for it
but I need the div.a,
try this
driver.findElement(By.cssSelector("div.a")).getAttribute("attribute");
use cssSelector for best result.
or else try the following xpath
//div[contains(#class, 'a')]
If you want attribute of div.a with it's descendant span which contains text something, try as below :-
driver.findElement(By.xpath("//div[#class = 'a' and descendant::span[text() = 'Text Example']]")).getAttribute("attribute");
Hope it helps..:)

Capybara - Finding a disabled button located in table row

I have a button
<button type="button" id="saveListing" class="button small save-button" data-bind="enable: saveEnabled, click: save"><i class="fa fa-save"></i> Save</button>
located in the tr of a table.
I wrote a function for testing the button status, simply using:
And(/^...the button "(.*?)" on "(.*?)" page is disabled$/) do |button_name, page|
button_id = ConfigHelper.get_button_info(button_name, page)['id']
button_class = ConfigHelper.get_button_info(button_name, page)['class']
if !button_id.nil?
find_button(button_id)[:disabled].should eq 'true'
elsif !button_class.nil?
find(button_class)[:disabled].should eq 'true'
else
button_text = ConfigHelper.get_button_info(button_name, page)['text']
find('button', text: button_text)[:disabled].should eq "true"
end
end
However, this block does not work for a button in a table row. I also tried add checking by button id, and it also did not work. How can I implement it without taking table id as a parameter? (As I don't want to write table id inside the feature)
When using id, the error is:
Capybara::ElementNotFound: Unable to find css ".saveListing"
or using text:
Ambiguous match, found 4 elements matching css "button" (Capybara::Ambiguous)
Thanks.
Capybaras find_button doesn't search css classes at all so unless you have overwritten find_button I'm not sure why you would be getting that error from using it with an id. find_button will search by the id, value, text content, or title attribute of the button, and also supports a disabled filter for searching. More stable (if the status of the button is changing due to JS) versions of those checks would be
find_button('saveListing', disabled: true).should be #Note: no # in front of the id here since its not a css selector
find_button('button text', disabled: true).should be
These would be more stable because they will utilize Capybaras waiting behavior to find the disabled button, whereas the way they were written previously would immediately find the button and error if they weren't yet disabled.
saveListing is the id of your button, not a class. In css selectors, dot is used for classes and hash sign is used for ids.
Therefore, you should either be using #saveListing or .save-button, but not .saveListing. This is why your first matching fails.
As to why the second one does - I guess there are 4 rows, each with one button and Capybara doesn't know which one you are referring to. If you want to check this condition for all of them, you could use all instead of find like this:
all('button', text: button_text).each do |button|
button[:disabled].should eq "true"
end

Resources