How to find element in nested span using Selenium WebDriver? - selenium-webdriver

I am trying to click on 'New Trade' link which is in span n6 which is a child element of span n2. I am able to reach till n2 but its not identifying 'n6'.
Please help I am new to Selenium WebDriver
Here I am posting the html and my code.
Trading
New
Trade
Trade
Explorer
I want to click on New Trade
HTML source code
My code which went till span 'n2':
driver.switchTo().frame(driver.findElement(By.name("treeFrame")));
WebElement allFormChildElements = driver.findElement(By.name("the_form"));
allFormChildElements.findElement(By.linkText("Trading")).click();
WebElement modalDialog = allFormChildElements.findElement(By.className("border"));
WebElement newmodalDialog = modalDialog.findElement(By.className("formScrollableMenuContent"));
System.out.println(newmodalDialog.findElements(By.tagName("a")).size()); // ans 5
WebElement newDialog= newmodalDialog.findElement(By.id("n2"));
System.out.println(newDialog.findElements(By.id("n3")).size()); // ans 0

With the image I can't test but, if you are able to reach the element <span id="n2">, from there you could use the following xpath in order to click the element with the text "New Trade":
newDialog.findElement(By.xpath(".//span[#id='n6']/a[#name='A6' and text()='New Trade']")).click();
EDIT
If the id value change, try in this way:
newDialog.findElement(By.xpath(".//span/a[#name='A6' and text()='New Trade']")).click();

Could you please try below xpath
//a[contains(text(),"New Trade")]

Related

Not able to get the locate the element by using xpath or css selector

<div class="et_pb_button_module_wrapper et_pb_button_4_tb_header_wrapper et_pb_button_alignment_center et_pb_button_alignment_phone_center et_pb_module ">
<a class="et_pb_button et_pb_button_4_tb_header full-width-btn et_hover_enabled et_pb_bg_layout_light" href="https://pegramonline.com/compare-insurance-companies-charlotte-nc/">Get a Quote</a>
</div>
I tried to locate <a> element and still it could not locate it..any other suggestion please...the class name has a space
By.cssSelector(“a[class=’et_pb_button et_pb_button_4_tb_header full-width-btn et_hover_enabled et_pb_bg_layout_light’]”);
By.cssSelector(“a.et_pb_button.et_pb_button_4_tb_header.full-width-btn.et_hover_enabled.et_pb_bg_layout_light”);
By.xpath(“//a[contains(#class, ‘et_pb_button’) and contains(#class, ‘et_pb_button_4_tb_header') and contains(#class, ‘full-width-btn')
and contains(#class, ‘et_hover_enabled’) and contains(#class, ‘et_pb_bg_layout_light’)]”);
It is working fine if you try to put a property color or anything else in this CODE
a.et_pb_button.et_pb_button_4_tb_header.full-width-btn.et_hover_enabled.et_pb_bg_layout_light{
color:red;
}
Or
a[class=’et_pb_button et_pb_button_4_tb_header full-width-btn et_hover_enabled et_pb_bg_layout_light’]{
color:red;
}
then you can easily understand that it's working fine.
There are 4 ways to click in Selenium.
Use the below xpath
//a[contains(text(),'Get a Quote')]
Code trial 1 :
Thread.sleep(5);
driver.findElement(By.xpath("//a[contains(text(),'Get a Quote')]")).click();
Code trial 2 :
new WebDriverWait(driver, 20).until(ExpectedConditions.elementToBeClickable(By.xpath("//a[contains(text(),'Get a Quote')]"))).click();
Code trial 3 :
Thread.sleep(5);
WebElement button = driver.findElement(By.xpath("//a[contains(text(),'Get a Quote')]"));
((JavascriptExecutor)driver).executeScript("arguments[0].click();", button);
Code trial 4 :
Thread.sleep(5);
WebElement button = driver.findElement(By.xpath("//a[contains(text(),'Get a Quote')]"));
new Actions(driver).moveToElement(button).click().build().perform();
PS : Please check in the dev tools (Google chrome) if we have unique entry in HTML DOM or not.
Steps to check:
Press F12 in Chrome -> go to element section -> do a CTRL + F -> then paste the xpath and see, if your desired element is getting highlighted with 1/1 matching node.

Why this code showing error while the button near right after the pass-code field?

I have tried to locate the button and click on it by the code given below.Other method which I have used also comment on the bottom of the code.
Error saying that Submit button in the end of the code was not able to locate by the code.
Why these error showing while the button is able to locate and click?Please help me to find a solution for this..
WebElement unfield =driver.findElement(By.xpath("//input[#id='user-name']"));
Actions actions = new Actions(driver);
actions.moveToElement(unfield).click();
unfield.clear();
unfield.sendKeys("test");
driver.findElement(By.xpath("//input[#id='user-password']")).clear();
driver.findElement(By.xpath("//input[#id='user-password']")).sendKeys("test");
WebElement test = driver.findElement(By.xpath("(.//*[normalize-space(text()) and normalize-space(.)='SIGN IN'])[1]/following::button[1]"));
Actions actions_signinclick = new Actions(driver);
actions_signinclick .moveToElement(test).click().build().perform();
//this will display in next page
WebDriverWait wait = new WebDriverWait(driver, 10);
wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//*[#id='user-passcode']")));
driver.findElement(By.xpath("//*[#id='user-passcode']")).click();
driver.findElement(By.xpath("//*[#id='user-passcode']")).clear();
driver.findElement(By.xpath("//*[#id='user-passcode']")).sendKeys("1234");
WebDriverWait submit_button = new WebDriverWait(driver, 60);
submit_button.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//BUTTON[#_ngcontent-wks-c3=''][text()='SUBMIT']/self::BUTTON")));
driver.findElement(By.xpath("//BUTTON[#_ngcontent-wks-c3=''][text()='SUBMIT']/self::BUTTON")).click();
/*WebElement test1 = driver.findElement(By.xpath("//BUTTON[#_ngcontent-wks-c3=''][text()='SUBMIT']/self::BUTTON"));
Actions actions_submitclick = new Actions(driver);
actions_submitclick .moveToElement(test1).click().build().perform();*/
Error shows as follows,
org.openqa.selenium.TimeoutException: Expected condition failed: waiting for visibility of element located by By.xpath: //BUTTON[#_ngcontent-wks-c3=''][text()='SUBMIT']/self::BUTTON (tried for 60 second(s) with 500 milliseconds interval)
at org.openqa.selenium.support.ui.WebDriverWait.timeoutException(WebDriverWait.java:81)
submit_button.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//BUTTON[#_ngcontent-wks-c3=''][text()='SUBMIT']/self::BUTTON")));
driver.findElement(By.xpath("//BUTTON[#_ngcontent-wks-c3=''][text()='SUBMIT']/self::BUTTON")).click();
AFAIU you are looking for the difference of the above two lines,
In first line visibilityOfElementLocated is used to check whether element is present on the DOM and also check whether visibility.To check visibility, it makes sure that the element has a height and width greater than 0.
In your case maybe element is present on the DOM but no visibility, Hence you are getting the exception.
Refer
In second line, you are just clicking the element present on the DOM, so its getting passed.

Delete cookies from past 1hr in chrome || Acess the chrome://settings/clearBrowserData to delete the data [duplicate]

I had been following the discussion How to automate shadow DOM elements using selenium? to work with #shadow-root (open) elements.
While in the process of locating the Clear data button within the Clear browsing data popup, which appears while accessing the url chrome://settings/clearBrowserData through Selenium I am unable to locate the following element:
#shadow-root (open)
<settings-privacy-page>
Snapshot:
Using Selenium following are my code trials and the associated errors encountered:
Attempt 1:
WebElement root5 = shadow_root4.findElement(By.tagName("settings-privacy-page"));
Error:
Exception in thread "main" org.openqa.selenium.JavascriptException: javascript error: b.getElementsByTagName is not a function
Attempt 2:
WebElement root5 = shadow_root4.findElement(By.cssSelector("settings-privacy-page"));
Error:
Exception in thread "main" org.openqa.selenium.NoSuchElementException: no such element: Unable to locate element: {"method":"css selector","selector":"settings-privacy-page"}
Attempt 3:
WebElement root5 = (WebElement)((JavascriptExecutor)shadow_root4).executeScript("return document.getElementsByTagName('settings-privacy-page')[0]");
Error:
Exception in thread "main" java.lang.ClassCastException: org.openqa.selenium.remote.RemoteWebElement cannot be cast to org.openqa.selenium.JavascriptExecutor
Incase if it is helpful the initial code block (till the above line) works perfect:
driver.get("chrome://settings/clearBrowserData");
WebElement root1 = driver.findElement(By.tagName("settings-ui"));
WebElement shadow_root1 = expand_shadow_element(root1);
WebElement root2 = shadow_root1.findElement(By.cssSelector("settings-main#main"));
WebElement shadow_root2 = expand_shadow_element(root2);
WebElement root3 = shadow_root2.findElement(By.cssSelector("settings-basic-page[role='main']"));
WebElement shadow_root3 = expand_shadow_element(root3);
WebElement root4 = shadow_root3.findElement(By.cssSelector("settings-section[page-title='Privacy and security']"));
WebElement shadow_root4 = expand_shadow_element(root4);
PS: expand_shadow_element() works flawless.
If you are trying to get 'Clear Data' element then you can use the below js to get the element and then perform.
return document.querySelector('settings-ui').shadowRoot.querySelector('settings-main').shadowRoot.querySelector('settings-basic-page').shadowRoot.querySelector('settings-section > settings-privacy-page').shadowRoot.querySelector('settings-clear-browsing-data-dialog').shadowRoot.querySelector('#clearBrowsingDataDialog').querySelector('#clearBrowsingDataConfirm')
Here is the sample script.
driver.get("chrome://settings/clearBrowserData");
driver.manage().window().maximize();
JavascriptExecutor js = (JavascriptExecutor) driver;
WebElement clearData = (WebElement) js.executeScript("return document.querySelector('settings-ui').shadowRoot.querySelector('settings-main').shadowRoot.querySelector('settings-basic-page').shadowRoot.querySelector('settings-section > settings-privacy-page').shadowRoot.querySelector('settings-clear-browsing-data-dialog').shadowRoot.querySelector('#clearBrowsingDataDialog').querySelector('#clearBrowsingDataConfirm')");
// now you can click on clear data button
clearData.click();
Edit 2: Explanation
Problem: Selenium does not provide explicit support to work with Shadow DOM elements, as they are not in the current dom. That's the reason why we will get NoSuchElementException exception when try to access the elements in the shadow dom.
Shadow DOM:
Note: We will be referring to the terms shown in the picture. So please go through the picture for better understanding.
Solution:
In order to work with shadow element first we have to find the shadow host to which the shadow dom is attached. Here is the simple method to get the shadow root based on the shadowHost.
private static WebElement getShadowRoot(WebDriver driver,WebElement shadowHost) {
JavascriptExecutor js = (JavascriptExecutor) driver;
return (WebElement) js.executeScript("return arguments[0].shadowRoot", shadowHost);
}
And then you can access the shadow tree element using the shadowRoot Element.
// get the shadowHost in the original dom using findElement
WebElement shadowHost = driver.findElement(By.cssSelector("shadowHost_CSS"));
// get the shadow root
WebElement shadowRoot = getShadowRoot(driver,shadowHost);
// access shadow tree element
WebElement shadowTreeElement = shadowRoot.findElement(By.cssSelector("shadow_tree_element_css"));
In order to simplify all the above steps created the below method.
public static WebElement getShadowElement(WebDriver driver,WebElement shadowHost, String cssOfShadowElement) {
WebElement shardowRoot = getShadowRoot(driver, shadowHost);
return shardowRoot.findElement(By.cssSelector(cssOfShadowElement));
}
Now you can get the shadowTree Element with single method call
WebElement shadowHost = driver.findElement(By.cssSelector("shadowHost_CSS_Goes_here));
WebElement shadowTreeElement = getShadowElement(driver,shadowHost,"shadow_tree_element_css");
And perform the operations as usual like .click(), .getText().
shadowTreeElement.click()
This Looks simple when you have only one level of shadow DOM. But here, in this case we have multiple levels of shadow doms. So we have to access the element by reaching each shadow host and root.
Below is the snippet using the methods that mentioned above (getShadowElement and getShadowRoot)
// Locate shadowHost on the current dom
WebElement shadowHostL1 = driver.findElement(By.cssSelector("settings-ui"));
// now locate the shadowElement by traversing all shadow levels
WebElement shadowElementL1 = getShadowElement(driver, shadowHostL1, "settings-main");
WebElement shadowElementL2 = getShadowElement(driver, shadowElementL1,"settings-basic-page");
WebElement shadowElementL3 = getShadowElement(driver, shadowElementL2,"settings-section > settings-privacy-page");
WebElement shadowElementL4 = getShadowElement(driver, shadowElementL3,"settings-clear-browsing-data-dialog");
WebElement shadowElementL5 = getShadowElement(driver, shadowElementL4,"#clearBrowsingDataDialog");
WebElement clearData = shadowElementL5.findElement(By.cssSelector("#clearBrowsingDataConfirm"));
System.out.println(clearData.getText());
clearData.click();
You can achieve all the above steps in single js call as at mentioned at the beginning of the answer (added below just to reduce the confusion).
WebElement clearData = (WebElement) js.executeScript("return document.querySelector('settings-ui').shadowRoot.querySelector('settings-main').shadowRoot.querySelector('settings-basic-page').shadowRoot.querySelector('settings-section > settings-privacy-page').shadowRoot.querySelector('settings-clear-browsing-data-dialog').shadowRoot.querySelector('#clearBrowsingDataDialog').querySelector('#clearBrowsingDataConfirm')");
Screenshot:
I had to do a similar test which required clearing browsing the chrome history. A minor difference was that I was clearing the data after going to the advanced section of the pop-up. As you are struggling to click only the "Clear data" button, I'm quite sure that you've missed one or two hierarchy elements mistakenly. Or got confused between sibling and parent elements probably. As per seeing your code, I assume that you already know that to access a particular shadow DOM element you need proper sequencing and it has been explained also quite nicely above.
Coming right at your problem now, here is my code snippet which is working correctly. The code waits until the data is cleaned and then will proceed to your next action-
public WebElement expandRootElement(WebElement element) {
WebElement ele = (WebElement) ((JavascriptExecutor) driver).executeScript("return arguments[0].shadowRoot",
element);
return ele;
}
public void clearBrowsingHistory() throws Exception {
WebDriverWait wait = new WebDriverWait(driver, 15);
driver.get("chrome://settings/clearBrowserData");
// Get shadow root elements
WebElement shadowRoot1 = expandRootElement(driver.findElement(By.xpath("/html/body/settings-ui")));
WebElement root2 = shadowRoot1.findElement(By.cssSelector("settings-main"));
WebElement shadowRoot2 = expandRootElement(root2);
WebElement root3 = shadowRoot2.findElement(By.cssSelector("settings-basic-page"));
WebElement shadowRoot3 = expandRootElement(root3);
WebElement root4 = shadowRoot3
.findElement(By.cssSelector("#advancedPage > settings-section > settings-privacy-page"));
WebElement shadowRoot4 = expandRootElement(root4);
WebElement root5 = shadowRoot4.findElement(By.cssSelector("settings-clear-browsing-data-dialog"));
WebElement shadowRoot5 = expandRootElement(root5);
WebElement root6 = shadowRoot5
.findElement(By.cssSelector("cr-dialog div[slot ='button-container'] #clearBrowsingDataConfirm"));
root6.click();
wait.until(ExpectedConditions.invisibilityOf(root6));
}
It should work properly in your case too if you don't intend to change any of the options selected by default in the pop-up (In that case, you will have to add a few more codes regarding selecting those checkboxes). Please tell me if this solves your issue. Hope this is helpful
I've added a snapshot of the the screen here too-
image
The Locator Strategy in #supputuri's answer using document.querySelector() works perfect through google-chrome-devtools
However, as the desired element opens from the shadow-dom you need to induce WebDriverWait for the elementToBeClickable() and you can you the following solution:
Code Block:
driver.get("chrome://settings/clearBrowserData");
new WebDriverWait(driver, 5).until(ExpectedConditions.elementToBeClickable((WebElement) ((JavascriptExecutor)driver).executeScript("return document.querySelector('settings-ui').shadowRoot.querySelector('settings-main').shadowRoot.querySelector('settings-basic-page').shadowRoot.querySelector('settings-section > settings-privacy-page').shadowRoot.querySelector('settings-clear-browsing-data-dialog').shadowRoot.querySelector('#clearBrowsingDataDialog').querySelector('#clearBrowsingDataConfirm')"))).click();
System.out.println("Clear data Button Clicked");
Console Output:
Clear data Button Clicked
I was getting InvalidArgumentEXception when trying to identify shadowRoot element in DOM using Selenium 4.3.0 and Chrome Version 103.0.5060.134
The solution to this is
SearchContext se= driver.findElment(By.locator("...").getShadowRoot(); return type is SearchContext
in the above line try using locator as xpath
and secondly trying to locate element using SearchContext reference e.g.
WebElement we= se.findElement(By.locator("....."));
use locater as cssSelector
And boom it works like charm
Didn't find this solution available and took me half a day to figure out
Hope this helps!!!

I want to locate an element in linkedin DOM for add new education section (plus sign)

I want to find the Xpath of (plus sign) in linkedin profile in adding new education field as per screenshot
driver.findElement(By.xpath(".//*[contains(#aria-label,'Add new education')]")).click();
but an error massage found that:
Unable to locate element
Try with the below xpath.
driver.findElement(By.xpath(".//li-icon[#aria-label ='Add new education']")).click();
Note: if you are still not able to locate the element then probably you are trying to access the webelement even before it is loaded on the webpage.
In that case you need to use
//30 is the wait time in seconds.
WebDriverWait wait = new WebDriverWait(driver,30);
//This will wait for 30 seconds to locate the element before throwing an Exception.
wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath(".//li-icon[#aria-label ='Add new education']")));
Let me know if this works.
Welcome to SO. Here is the locator to identify the + in education.
Using CSS a[class$='add-education ember-view']
driver.findElement(By.cssSelector("a[class$='add-education ember-view']")).click();
xpath //a[contains(#class,'add-education ember-view')]
driver.findElement(By.xpath("//a[contains(#class,'add-education ember-view')]")).click();

org.openqa.selenium.support.ui.UnexpectedTagNameException: Element should have been “select” but was “span”

Selenium webdriver code is
WebElement element=driver.findElement(By.xpath(".//*[#id='css3menu1']/li[3]/a/span"));
Select se = new Select(element);
String S =se.getFirstSelectedOption().getText();
System.out.println(S);
List<WebElement> allOptions = se.getOptions();
for (WebElement webElement : allOptions)
{
System.out.println(webElement.getText());
}
}
Here i want to print all options ..Please help me to get rid of this error and print all child options .
org.openqa.selenium.support.ui.UnexpectedTagNameException: Element should have been “select” but was “span”
I can't post comments yet, but you're trying to create a select element from a WebElement of the wrong type. If you notice your xpath ends in span, that means the xpath is ultimately looking for a span element, not the select tag you want.
Try replacing this:
WebElement element = driver.findElement(By.xpath(".//*[#id='css3menu1']/li[3]/a/span"));
with this:
WebElement element = driver.findElement(By.xpath(".//*[#id='css3menu1']/li[3]/a/select"));
If that doesn't work, add the html around this selection so we can tell you the correct xpath you'll want to be using. Once you do I can help you get this sorted out.

Resources