selenium - how to find xpath - selenium

can any one help me for finding the correct xpath for the given link Logout

What you could do is to locate all links in your page, and then file the one corresponding to what you're searching for.
Here is the code converted to java
public static IWebElement GetLinkContainingText(string textToBeContained) {
// Here Driver is my ChromeDriver instance. You can replace a, by whatever tag your href is in.
ArrayList<WebElement> allTags = Driver.FindElements(By.Xpath("//a"));
for (WebElement v : allTags) {
if (v.GetAttribute(href).contains(textToBeContained)) {
return v;
}
}
return null;
}
calling the method would result for you in that.
WebElement elementYouSeachFor = GetLinkContainingText("http://ec2-34-210-163-161.us-west-2.compute.amazonaws.com:8094/login/index/logout");
Most likely
WebElement elementYouSeachFor = GetLinkContainingText("/logout");
would work too since there's probably not many links with logout on your page.
Hope this helps.

driver.findElement(By.xpath("//a[text()='Logout']"))
Is one way.
driver.findElement(By.linkText("Logout"));
Both could be problematic if you have more than 1 logout link on the page.
More resources on selecting elements: https://seleniumhq.github.io/selenium/docs/api/java/org/openqa/selenium/By.html

Related

How to pass dynamic value into xpath in selenium, java?

I have a website, where i open contract and get the unique contractId. Then, i need to go to other page and search this id in table with pagination. I wrote code which goes to next page if this requesid(it's a link) is not found and if it exist, it just opens this requestId. But there is a problem with initialization of webelement where i'm trying add dynamic value. Selenium gives error below and i have no idea how to solve it
org.openqa.selenium.NoSuchElementException: no such element: Unable to locate element: {"method":"xpath","selector":"//span[#class='link__text' and text()='222254']/../../..//input"}
(Session info: chrome=89.0.4389.72)
contractId is the variable where i store dynamic value that changes every test run. This is how the code looks like:
csecp.waitForElementVisibility(csecp.getContractStatusEmergencyChangeHeader());
int totalPages = Integer.parseInt(csecp.getTotalPagesString().getText());
for(int i = 0; i < totalPages; i++) {
csecp.sleep(500);
if (**csecp.prepareWebElementWithDynamicXpath(csecp.getContractDynamicValue(),contractId).isDisplayed()**) {
csecp.prepareWebElementWithDynamicXpath(csecp.getContractDynamicValue(),contractId).click();
csecp.waitForElementVisibility(csecp.getConfirmAMLApprovalButton());
csecp.getConfirmAMLApprovalButton().click();
break;
}
csecp.waitForElementVisibility(csecp.getNextPageButton());
csecp.getNextPageButton().click();
}
This is how i'm trying to pass dynamic valueinto xpath
private String contractDynamicValue = "//span[#class='link__text' and text()='xxxxx']/../../..//input";
public WebElement prepareWebElementWithDynamicXpath (String xpathValue, String substitutionValue ) {
return getWebDriver().findElement(By.xpath(xpathValue.replace("xxxxx", substitutionValue)));
}
You can define and use this XPath locator as following:
String contractDynamicValue = "//span[#class='link__text' and text()='%s']/../../..//input";
public WebElement prepareWebElementWithDynamicXpath (String xpathTemplate, String substitutionValue ) {
String xpath = String.format(xpathTemplate,substitutionValue);
return getWebDriver().findElement(By.xpath(xpath));
}
See the xpath that you are using is
//span[#class='link__text' and text()='xxxxx']/../../..//input
and if you wanna make xxxxx as dynamic, you could do following :-
string sub_value = "222254";
//span[#class='link__text' and text()='"+sub_value+"']/../../..//input
It's always the best solution to get element by text and the following element. For dynamic elements, you can use XPath like
//div[.='Dummy_text']/following::span[text()='test_text']
You can see some tutorials from here
https://www.guru99.com/xpath-selenium.html

Element present fails due to iframe issue for getting image src using Selenium WebDriver

As we know iframe can be counted using frameslist but that doesn't work for me and gives blank output although frame count gives me count as 2. I'm using Selenium WebDriver and Java.
Basically I want to get img source's data-mce-src starts with cid and dfsrc ends with # according to below screenshot.
I tried :
public static final String imageAttachment="css=img[data-mce-src^='cid']&&[data-mce-src$='#']";
which works fine using sIsElementPresent in selenium 1.0 but it fails in webdriver using findElement. In fact it doesn't identify iframe itself.
Expected:
css=img[data-mce-src^='cid']&&[data-mce-src$='#'] element present?
Code:
WebElement we = null;
List <WebElement> framesList = webDriver().findElements(By.tagName("iframe"));
for (WebElement frame:framesList){
System.out.println(frame.getText()); // returns nothing
}
int listSize = framesList.size();
webDriver().findElement(By.xpath("//iframe"));
System.out.println(listSize);
Also tried:
webDriver().switchTo().frame(webDriver().findElements(By.tagName("iframe"));
we = webDriver().findElement(By.cssSelector("html body div img"));
System.out.println(we.getAttribute("src")); // returns nothing
You should try as below :-
webDriver().switchTo().frame("Editor1_body_ifr");
we = webDriver().findElement(By.cssSelector("body#tinymce img"));
System.out.println(we.getAttribute("src"));
try {
webDriver().switchTo().frame("Editor1_body_ifr");
we = webDriver().findElement(By.cssSelector("html body img"));
System.out.println(we.getAttribute("src"));
System.out.println(we.getAttribute("data-mce-src"));
System.out.println(we.getAttribute("dfsrc"));
} finally {
webDriver.switchTo().defaultContent();
}

Shadow-dom support for selenium

I am working on an automation project which uses shadow DOMs extensively.
I use the execute_script function to access shadow root elements.
For example:
root = driver.execute_script('return document.querySelector(".flex.vertical.layout").shadowRoot')
Then I use the root element to access the elements within.
Since we have shadow root elements at many levels, this is annoying me a lot.
Is there any better solution to access elements within shadow root elements?
I am using Chrome 2.20 driver.
By googling I found another workaround for this problem - which is using the "/deep/ combinator".
For example, I was able to access all the shadow roots elements with
driver.find_elements_by_css_selector('body/deep/.layout.horizontal.center')
This will have access to the element with the compound class name layout horizontal center regardless of the number of shadow roots it has.
But this only works for the chromedriver and /deep/ is a deprecated approach.
The WebDriver spec still doesn't have anything specific to say about Shadow DOM.
Nor the Selenium project pages - which is understandable, as they closely follow the spec. Yet there is some low-level code in existence.
So, the short answer is: no, there is no special support in the spec, in Selenium's WebDriver API or implementation code at present.
Yes, the capability seems to exist in ChromeDriver 2.14 (as a wrapper around Chrome). However, as far as I can tell there are no Selenium or WebDriver-level bindings to let you use it.
But for more detail and possible workarounds, see also: Accessing Shadow DOM tree with Selenium, also: Accessing elements in the shadow DOM, and especially: Finding elements in the shadow DOM
You can write extension methods to operate on IWebElement to expand the root as below.
public static class SeleniumExtension
{
public static IWebElement ExpandRootElement(this IWebElement element, IWebDriver driver)
{
return (IWebElement)((IJavaScriptExecutor)driver)
.ExecuteScript("return arguments[0].shadowRoot", element);
}
}
You can use the above extension method to traverse through the element's hierarchy to reach the element of interest.
By downloads_manager_ShadowDom= By.TagName("downloads-manager");
By downloadToolBarShadowDom = By.CssSelector("downloads-toolbar");
By toolBarElement = By.CssSelector("cr-toolbar");
IWebElement ToolBarElement = driver.FindElement(downloads_manager_ShadowDom).ExpandRootElement(driver).FindElement(downloadToolBarShadowDom).ExpandRootElement(driver).FindElement(toolBarElement);
Trying to have this automated on Chrome I came up with an inelegant solution of recursively searching through each shadow dom explicitly using:
driver.executeScript(scriptToRun, cssSelector);
Here's the javascript (passed as a string):
function recursiveSearch(element, target) {
let result = element.querySelector(target);
if (result) { return result; }
let subElements = element.querySelectorAll("*");
for (let i = 0; i < subElements.length; i++) {
let subElement = subElements[i];
if (subElement && subElement.shadowRoot) {
let result = recursiveSearch(subElement.shadowRoot, target);
if (result) return result;
}
}
}
return recursiveSearch(document, arguments[0]);
Since the contents of a shadowRoot might be empty initially one can use driver.wait and until.elementIsVisible to avoid returning a null element.
Async example:
return await driver.wait(until.elementIsVisible(await driver.wait(async () => {
return await driver.executeScript(scriptToRun, cssSelector);
}, timeOut)));
Alternatively
My previous solution was to traverse the elements with shadowdoms explicitly, but is less autonomous. Same as above but with this script:
let element = document.querySelector(arguments[0][0]);
let selectors = arguments[0].slice(1);
for (i = 0; i < selectors.length; i++) {
if (!element || !element.shadowRoot) {return false;}
element = element.shadowRoot.querySelector(selectors[i]);
}
return element;
Where selectors would be something like:
['parentElement1', 'parentElement2', 'targetElement']
Sidenote
I found that running my automation tests on Firefox Quantum 57.0 doesn't suffer from hidden shadow doms, and any element can be found with a simple:
driver.findElement(searchQuery);
Since you use often that you may create a function, then the above becomes:
def select_shadow_element_by_css_selector(selector):
running_script = 'return document.querySelector("%s").shadowRoot' % selector
element = driver.execute_script(running_script)
return element
shadow_section = select_shadow_element_by_css_selector(".flex.vertical.layout")
shadow_section.find_element_by_css(".flex")
on the resulting element you can put any of the methods:
find_element_by_id
find_element_by_name
find_element_by_xpath
find_element_by_link_text
find_element_by_partial_link_text
find_element_by_tag_name
find_element_by_class_name
find_element_by_css_selector
To find multiple elements (these methods will return a list):
find_elements_by_name
find_elements_by_xpath
find_elements_by_link_text
find_elements_by_partial_link_text
find_elements_by_tag_name
find_elements_by_class_name
find_elements_by_css_selector
later edit:
Sometime the shadow host elements are hidden withing shadow trees that's why the best way to do it is to use the selenium selectors to find the shadow host elements and inject the script just to take the shadow root: :
def expand_shadow_element(element):
shadow_root = driver.execute_script('return arguments[0].shadowRoot', element)
return shadow_root
#the above becomes
shadow_section = expand_shadow_element(find_element_by_tag_name("neon-animatable"))
shadow_section.find_element_by_css(".flex")
To put this into perspective I just added a testable example with Chrome's download page, clicking the search button needs open 3 nested shadow root elements:
import selenium
from selenium import webdriver
driver = webdriver.Chrome()
def expand_shadow_element(element):
shadow_root = driver.execute_script('return arguments[0].shadowRoot', element)
return shadow_root
selenium.__file__
driver.get("chrome://downloads")
root1 = driver.find_element_by_tag_name('downloads-manager')
shadow_root1 = expand_shadow_element(root1)
root2 = shadow_root1.find_element_by_css_selector('downloads-toolbar')
shadow_root2 = expand_shadow_element(root2)
root3 = shadow_root2.find_element_by_css_selector('cr-search-field')
shadow_root3 = expand_shadow_element(root3)
search_button = shadow_root3.find_element_by_css_selector("#search-button")
search_button.click()
Not sure it works in all browsers, but for me
::shadow works fine in chromedriver 2.38 For example:
div::shadow div span::shadow a
Maybe you may use IJavaScriptExecutor?
IWebDriver driver;
IJavaScriptExecutor jsExecutor = (IJavaScriptExecutor)driver;
jsExecutor.ExecuteScript('yourShadowDom.func()');

Selenium Xpath Not Matching Items

I am trying to use Selenium's Xpath ability to be able to find an set of elements. I have used FirePath on FireFox to create and test the Xpath that I have come up with and that is working just fine but when I use the Xpath in my c# test with Selenium nothing is returned.
var MiElements = this._driver.FindElements(By.XPath("//div[#class='context-menu-item' and descendant::div[text()='Action Selected Jobs']]"));
and the Html looks like this:-
Can Anyone please point me right as everything that I have read the web says to me that this Xpath is correct.
Thanking you all in-advance.
Please post the actual HTML, so we can simply "drop it in" into a HTML file and try it ourselves but I noticed that there is a trailing space at the end of the class name:
<div title="Actions Selected Jobs." class="context-menu-item " .....
So force XPath to strip the trailing spaces first:
var MiElements = this._driver.FindElements(By.XPath("//div[normalize-space(#class)='context-menu-item' and descendant::div[text()='Action Selected Jobs']]"));
Perhaps you don't take into consideration the time that the elements need to load and you look for them when they aren't yet "searchable". UPDATE I skipped examples regarding this issue. See Slanec's comment.
Anyway, Selenium recommends to avoid searching by xpath whenever it is possible, because of being slower and more "fragile".
You could find your element like this:
//see the method code below
WebElement div = findDivByTitle("Action Selected Jobs");
//example of searching for one (first found) element
if (div != null) {
WebElement myElement = div.findElement(By.className("context-menu-item"));
}
......
//example of searching for all the elements
if (div != null) {
WebElement myElement = div.findElements(By.className("context-menu-item-inner"));
}
//try to wrap the code above in convenient method/s with expressive names
//and separate it from test code
......
WebElement findDivByTitle(final String divTitle) {
List<WebElement> foundDivs = this._driver.findElements(By.tagName("div"));
for (WebElement div : foundDivs) {
if (element.getAttribute("title").equals(divTitle)) {
return element;
}
}
return null;
}
This is approximate code (based on your explanation), you should adapt it better to your purposes. Again, remember to take the load time into account and to separate your utility code from the test code.
Hope it helps.

How to verify links

How to verify whether links are present or not?
eg.
I have 10 links in a page, I want to verify the particular link
Is it possible?
I am using selenium with Java.
Does i can write inside the selenium code
eg
selenium.click("searchimage-size");
selenium.waitForPopUp("dataitem", "3000");
selenium.selectWindow("name=dataitem");
foreach(var link in getMyLinkTextsToTest())
{
var elementToTest = driver.findElement(By.linkText(link));
Assert.IsNotNull(elementToTest);
}
What you can do is find all links on the page like this:
var anchorTags driver.findElement(By.TagName("a"));
and then iterate through the anchorTags collection to make you you've got what you're looking for.
Or if you have a list of the link texts you can do something like this:
foreach(var link in getMyLinkTextsToTest())
{
var elementToTest = driver.findElement(By.linkText(link));
Assert.IsNotNull(elementToTest);
}
This code is all untested and right off the top of my head so you might need to do some slight modification but it should be close to usable.
if you are using Selenium 1.x you can use this code.
String xpath = "//<xpath till your anchor tag>a/#herf";
String href = selenium.getAttribute(xpath);
String expectedLink = "your link";
assertEquals(href,expectedLink);
I hope this may help you...
List<WebElement> links = driver.findElements(By.tagName("a"));
for(WebElement we : links) {
if("Specific link text".equals(we.getText("Specific link text"))) {
we.click();
}
}
I'm taking all links to List variable 'links' and iterating it. Then checking condition, for the specific text we looking in the link is presenting in the list or not. If it found out, it'll click on it
If you're looking to verify each specific for the content of href, you can use javascript to return the outerHTML for a specific Webelement which you can identify however you like; in the example below I use By.cssSelector:
WebElement Element = driver.findElement(By.cssSelector("..."));
String sourceContents = (String)((JavascriptExecutor)driver).executeScript("return arguments[0].outerHTML;", element);
assertEquals(sourceContents, "Learn More");
If you want to make it a tad more elegant you can shave the undesired elements off of the string, but this is the general case as of Selenium-java: 2.53.1 / Selenium-api: 2.47.1 as I can observe.
Best approach would be to use getText() method
List<WebElement> allLinks = driver.findElements(By.tagName("a"));
for(WebElement specificlink : allLinks ) {
if(specificlink.getText().equals("link Text"){
//SOPL("Link found");
break;
}
}