Xpath with text() contains and not contains other text, case insensitive - xpath

I am trying to locate an element based on its text (I know, I know), and because there are two labels that contain some of the same words, I have to be able to locate it by some words but ensure it doesn't include other words. On top of that, it needs to be case insensitive.
Example: I am trying to locate and click the checkbox associated with the text Some Text, but not Some Text Too. The id and name, as well as the order (sometimes 'Some Text' is first, sometimes 'Some Text Too' is first) can vary from page to page depending on what else is shown, so I cannot rely on that to locate the correct checkbox.
<td style="padding-bottom: 2px"><input id="c_58" style="padding-left: 3px; background-color: rgb(255, 255, 255);" name="c_58" value="[dbo].[table].[Field]" type="checkbox"><label for="c_59" style="padding-left: 3px;">Some Text Too</label></td>
<td style="padding-bottom: 2px"><input id="c_59" style="padding-left: 3px; background-color: rgb(255, 255, 255);" name="c_59" value="[dbo].[table].[Field]" type="checkbox"><label for="c_59" style="padding-left: 3px;">Some Text</label></td>
What I have that works:
//*[*[text()[contains(translate(., 'SOME TEXT','some text'), 'some text')]]]
This finds the elements with 'Some Text', but also finds the elements with 'Some Text Too'. Since sometimes the page renders with the elements in different order, I need to be able to ensure I'm only finding 'Some Text' and not 'Some Text Too'
I have tried :
//*[*[text()[contains(translate(., 'SOME TEXT','some text'), 'some text') and not(contains(translate(., 'TOO', 'too'), 'too'))]]]
but that is not locating any element on the page.

Abdou you were correct - my scenario was more like:
label 1 : Some Text Here Too
label 2 : Some Texts Here
So the having the term "Some Text Here" couldn't find the second label because of the non-matching "Texts". I resolved this scenario by using:
//*[*[text()[contains(translate(., 'SOME','some'), 'some') and contains(translate(., 'TEXT','text'), 'text') and contains(translate(., 'HERE','here'), 'here') and not(contains(translate(., 'TOO','too'), 'too'))]]]
//*[*[text()[contains(translate(., 'SOME','some'), 'some') and contains(translate(., 'TEXT','text'), 'text') and contains(translate(., 'HERE','here'), 'here') and contains(translate(., 'TOO','too'), 'too')]]]

Related

construct the `xpath` to allow argument

User can drag the slider to different value from aria-valuenow="1" to aria-valuenow="30"
The web element:
<div tabindex="0" class="ant-slider-handle" role="slider" aria-valuemin="1" aria-valuemax="30" aria-valuenow="7" aria-disabled="false" style="left: 20.6897%; right: auto; transform: translateX(-50%);" xpath="1"></div>
I plan to have test case like this:
*** Test Cases ***
001_Move-Slider
[Arguments] ${aria-valuenow}
Click ${slider} 10
I am not sure how to construct the xpath of ${slider} to allow flexibility to enter any value from 1 - 30.

Element not interactable in dropdown. How to get an element?

Help please to get a correct solution of my task.
I have this dropdown (it looks like dropdown) with code:
<div class="jcf-select-drop jcf-select-jcf-hidden jcf-unselectable" style="position: absolute; top: 1331px; width: 376.125px; left: 285.75px;">
<div class="jcf-select-drop-content">
<span class="jcf-list jcf-scroll-active">
<span class="jcf-list-content" style="max-height: 369px; overflow: auto;">
<ul>
<li>
<span class="jcf-option" data-index="0">Afghanistan</span>
</li>
<li>
<span class="jcf-option" data-index="218">USA</span>
</li>
And simple test:
let countryTest = $$("span.jcf-select.jcf-unselectable").first();
let USA = $("body > div.jcf-select-drop.jcf-select-jcf-hidden.jcf- unselectable > div > span > span > ul > li:nth-child(217) > span");
countryTest.click();
USA.click();
I need to select USA, but have an error "Failed: element not interactable". I can get Afghanistan, but not USA.. I tried
browser.actions().mouseMove(USA).click().perform();
but it isn't help.
Can I somehow click on USA-element using data-index? Or what is correct way to choose the element?
And how is there a way to make shorter the element(by.css), because it's too long..
I am assuming that the dropdown contains a full list of countries. As such, USA will not be high on the list (number 218 it looks like). Because your dropdown will only display a limited amount of countries at once, USA is hidden. Most dropdowns allow text to be entered to search for a country. This also limits the matches to all be displayed on the screen. You can then click on USA (although its index may have changed)
Example
let countryTest = $$("span.jcf-select.jcf-unselectable").first();
let USA = $("body > div.jcf-select-drop.jcf-select-jcf-hidden.jcf-unselectable > div > span > span > ul > li:nth-child(217) > span");
//keep in mind USA selector will likely have changed after you do your search
countryTest.click();
countryTest.sendKeys('USA'); //likely will be a different element that you have to send keys to
USA.click();
Try the below one
const countryTest = element(by.cssContainingText('spna.jcf-list-content>ul>li>span', 'USA'));
So countryTest.click() selects USA from the dropDown.
hope it helps you.
Assuming you already solved clicking a parent element that displays the dropdown, have you tried the following?:
If you have just those 2 options:
var USA = element.all(by.css('.jcf-list-content ul li span')).last();
countryTest.click();
USA.click();
If the dropdown has more options (USA being 218?):
var USA = element.all(by.css('.jcf-list-content ul li span')).get(218);
countryTest.click();
USA.click();
You can try with the 'span' at the end, or removing it. I'm not sure which one will work.
Ultimately, try something like this:
var USA = element(by.cssContainingText('li', 'USA'));
countryTest.click();
USA.click();
Hope it helps.

How to retrieve hidden elements when visibility is hidden

I want to retrieve hidden text when the visibiility attribute is hidden:
<div id = "tt52433002" class="yui-module yui-overlay yui-tt yui-overlay-hidden" style="z-index: 2; visibility: hidden;">
<div class="bd">Associated with the domain : testci20160503105556.com</div>
</div>
I tried:
browser.hidden(:class, 'bd').text
and
browser.hidden(:class, 'bd').value
But I get this error:
"unable to locate element, using {:class=>"bd", :tag_name=>"input", :type=>"hidden"}"
Watir is designed to act like a user. So if a user can not see the text in an element, then Watir will not return the text of the element.
Also, the element you are looking for is a div not a hidden.
If you need the text you can do:
browser.div(class: 'bd').inner_html
which makes a JavaScript call to provide the result.
This works:
browser.div.attribute_value('id') => tt52433002
as does this:
browser.div(class: 'bd').inner_html[/testci\d{14}/] => testci20160503105556
First things first. The error says that Watir cannot find an element using the criteria you specified. That means either that no such thing exists anywhere in the DOM, or that it might be inside a frame.
Since the element you want is a div, then you should be using the .div method to access it
browser.div(:class => 'bd') #finds first matching div
A potential second problem could occur if that classname is not very unique. Unless you specify an additional parameter, such as index, or perhaps a portion of the text contained by the div, you may not find the div you are looking for. A fast debugging trick (I like to do it from IRB) is to get a collection of matching divs and check the size
div_count = browser.divs(:class => 'bd').size
puts "there are #{divcount} divs of class bd in the dom"
If the count is anything more than 1, then you likely need to change how you are selecting it to ensure you get the right one. for example
browser.div(:class => 'bd', :text => /Associated with the domain/)
If the count is zero, then check for frames
frame_count = browser.frames.size
iframe_count = browser.iframes.size
If there are frames you will have to tell watir to look inside the frame for the div, if more than one frame then be sure you specify the right one
browser.frame.div(:class => 'bd') #looks for div inside first frame
Once you are sure you have the right div, then you ought to be able to use a method like .text or as in another answer .inner_html to get the contents of the div.

XPATH- How to select radio button and text in a single xpath expression?

I have Radio button with value as "CREDIT_CARD" and the text of the radio button as "New". Now i need to select a radio button which has text "New".
<div>
<input type="radio" onchange="javascript:toggleAdvancedDisplay('pay_detail','CREDIT_CARD');" value="CREDIT_CARD" name="payment_type" style="margin:0; vertical-align: middle;"/>
<span class="value">New</span>
I tried the below xpath, but it doesn't locate the expected element.
/fieldset[1]/div/div/div[2]/input[#value='CREDIT_CARD']/fieldset[1]/div/div/div[2]/span[contains(text(), 'New')]
What is it i am doing wrong here?
You can try :
xpath = //input[#value='CREDIT_CARD' and following-sibling::span[contains(., 'New')]]
This will get input tag with CREDIT_CARD as value and whose sibling contains New as text.
The <span> element is not a child of the <input> element, but it is the next sibling. XPath should be:
/fieldset[1]/div/div/div[2]/input[#value='CREDIT_CARD' and following-sibling::span[1] = 'New']
Try this. Does this locate the element you're looking for?
xpath = //*[#value="CREDIT_CARD"]/span[contains(.,"New")]

how to scroll a web application in watir

How do I scroll a web application in Watir ?
I have tried#browser.send_keys :space
This just brings the whole page down. But I have a scroll within the application, I need to scroll the vertical scroll bar down & up in my automation testing, Please help me !
Thanks!
<div dojoattachpoint="containerNode" class="containerNode tabContentPane typeNavigationSingleChild" style="overflow: auto; left: 5px; top: 10px; width: 1549px; height: 535px;">
<div pageid="lifecycle_theme_home_page_dashboard_pageId" id="lifecycle_theme_home_page_dashboard_pageId" style="height: 535px; padding: 0px; width: 1549px;" widgetid="lifecycle_theme_home_page_dashboard_pageId" title="" role="group" class="dijitContentPane wcs-nullLayout">
Solution 1) Scroll to Last Element
I think Vinay's approach should work. However, in the current form, it assumes that the element already exists on the page. I am guessing the element you want is only visible once you scroll far enough. So what you can do is scroll to the last element in the div.
Watir-Webdriver
In Watir-Webdriver:
div_with_scroll = browser.div(:class => 'containerNode tabContentPane typeNavigationSingleChild')
div_with_scroll.elements.last.wd.location_once_scrolled_into_view
Watir-Classic
In Watir-Classic, it is different since it does not use selenium-webdriver:
div_with_scroll = browser.div(:class => 'containerNode tabContentPane typeNavigationSingleChild')
div_with_scroll.elements.last.document.scrollIntoView
Solution 2) Use ScrollTop Property
As an alternative, if the above does not work, you can set the scrollTop property to move the div element's scrollbar. This worked for an application that I was working on that had content that was only loaded once you scrolled to the bottom.
Watir-Webdriver
To jump the scrollbar to the bottom, which in theory should trigger the below content to load, set the scrollTop property to the scrollHeight:
div_with_scroll = browser.div(:class => 'containerNode tabContentPane typeNavigationSingleChild')
scroll_bottom_script = 'arguments[0].scrollTop = arguments[0].scrollHeight'
div_with_scroll.browser.execute_script(scroll_bottom_script, div_with_scroll)
To jump back to the top, set the scrollTop to zero.
div_with_scroll = browser.div(:class => 'containerNode tabContentPane typeNavigationSingleChild')
scroll_top_script = 'arguments[0].scrollTop = 0'
div_with_scroll.browser.execute_script(scroll_top_script, div_with_scroll)
You can also use any value in between depending on where you need to go to.
Watir-Classic
In Watir-Classic, you can set the scrollHeight more directly:
div_with_scroll = browser.div(:class => 'containerNode tabContentPane typeNavigationSingleChild')
#Go to bottom
div_with_scroll.document.scrollTop = div_with_scroll.document.scrollHeight
#Go to top
div_with_scroll.document.scrollTop = 0
if the element is at the bottom of the page, it will load more content:
browser.element.wd.location_once_scrolled_into_view
Using Watir-Classic, the second method Justin Ko provided works great for iterating through a scrollable section to find something specific. Here's an example of that:
div_with_scroll = browser.div(:class => 'containerNode tabContentPane typeNavigationSingleChild')
scroll_value = 50 # change this number to match how much you want to scroll each iteration
max_loop = div_with_scroll.document.scrollHeight / scroll_value
if div_with_scroll.document.scrollHeight % scroll_value > 0 # accounts for any remainder height
max_loop = max_loop + 1
end
for i in 0..max_loop do
div_with_scroll.document.scrollTop = i * scroll_value # moves the scrollbar
if div_with_scroll.text.include? 'Search Text'
puts 'Search Text found in iteration: ' + i.to_s()
break # exits the loop when found
end
end
There may be a more efficient way to do what I'm doing here, but you get the idea.
Use Javascript (eg. bottom of page):
browser.execute_script("window.scrollTo(0, document.body.scrollHeight);\n")
use a correct javascript executor to achieve this result - below i have written some code to show you the 'in my opinion' best and most reliable way to achieve this:
BOTTOM OF PAGE:
((IJavaScriptExecutor)webapplication).ExecuteScript("window.scrollTo(0, document.body.scrollHeight - 5)");
TOP OF PAGE:
((IJavaScriptExecutor)webapplication).ExecuteScript("window.scrollTo(0, document.body.scrollHeight 0)");
you can also set different values to scroll to different heights - for example the scroll to bottom code i have set to 5px from the bottom of the page. good luck, hope this is of somewhat use to you.

Resources