Having issue with selecting drop down in selenium webriver - selenium-webdriver

I have a sample HTML source of the dropdown.
I have tried with all possibilities but I having
"Exception in thread "main"
org.openqa.selenium.ElementNotInteractableException: element not
interactable" error in selenium web driver.
Plz, give me a solution to select the dropdown values in the web driver. What should I use?[HTML source here][1]
WebElement clickclientdrpdown=driver.findElement(By.xpath("/html/body/div[5]/div[3]/div[1]/div/div[4]/div/form/div[1]/span/span[1]/span/span[1]"));
clickclientdrpdown.click();
WebElement selectclientdrpdown = driver.findElement(By.xpath("/html/body/div[5]/div[3]/div[1]/div/div[4]/div/form/div[1]/span/span[1]/span/span[1]"));
selectclientdrpdown.sendKeys("1 Private solution");

Your xpath is prone to breaking easily if the format of the HTML ever changes, just use findElement(By.Name), the name attribute is less likely to change as it is part of the Form and name is the parameter name passed to the server:
//Selenium method specific, prone to failure if element is disabled or not visible
WebElement selectclientdrpdown = driver.findElement(By.name("companyId"));
selectclientdrpdown.sendKeys("1 Private solution");
//Using the JavascriptExecutor
JavascriptExecutor js = (JavaScriptExecutor)driver;
js.ExecuteScript("document.querySelector("select[name='companyId'].value = '1 Private solution';");

Related

Find element by inner element text using selenium

I want to click an element by the text of a span who is the child of the element. How do I do this?
<button type="button" class="alert-button ion-focusable ion-activatable sc-ion-alert-md" tabindex="0"><span class="alert-button-inner sc-ion-alert-md">OK</span><ion-ripple-effect class="sc-ion-alert-md md hydrated" role="presentation"></ion-ripple-effect></button>
This is what I have tried but it didn't work.
#FindBy(css = "button[span:contains('OK')]")
Selenium doesn't supports the :contains pseudo-class anymore as #jari.bakken in their comment confirms:
AFAICT, the :contains pseudo-class isn't in the CSS spec and is not supported by either Firefox or Chrome (even outside WebDriver).
Further #dawagner in their comment also mentions:
contains isn't a valid CSS3 selector; because of this several browsers don't natively support contains, so Selenium (and WebDriver) don't claim to support it._
Solution
However you can still use the other attributes to construct a CssSelector to identify the element as follows:
#FindBy(css = "button.alert-button.ion-focusable.ion-activatable.sc-ion-alert-md span.alert-button-inner.sc-ion-alert-md")
As an alternative you can also use either of the following Xpath based locator strategies:
#FindBy(xpath = "//button[#class='alert-button ion-focusable ion-activatable sc-ion-alert-md']//span[#class='alert-button-inner sc-ion-alert-md']")
Using the innerText:
#FindBy(xpath = "//button[#class='alert-button ion-focusable ion-activatable sc-ion-alert-md']//span[#class='alert-button-inner sc-ion-alert-md' and text()='OK']")
or even:
#FindBy(xpath = "//span[#class='alert-button-inner sc-ion-alert-md' and text()='OK']")
even possibly:
#FindBy(xpath = "//span[text()='OK']")
CSS Selectors with Selenium do not support locating elements by their text content. Only XPath supports that.
Try this XPath:
//button//span[text()='OK']
or
//button//span[contains(.,'OK')]
or
//button//span[contains(text(),'OK')]
So the element could be defined as following
#FindBy(xpath= "//button//span[text()='OK']")
Or
#FindBy(xpath= "//button//span[contains(.,'OK')]")

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!!!

Selenium how do find and click this specific attribute

enter image description hereCode 1
button style="margin-left:0px" class="list_header_search_toggle icon-search btn btn-icon table-btn-lg">Search
Code 2
button style="margin-left:0px" class="list_header_search_toggle icon-search btn btn-icon table-btn-lg">
Please help me to find and click this specific element
I tried this but its not working
//WebElement checkSearchGlass = driver.findElement(By.xpath("//*[starts-with(#class,'list_header_search_toggle')"));
//WebElement checkSearchGlass = driver.findElement(By.xpath("//button[starts-with(#class,'list_header_search_toggle')"));
I see that your xpath doesn't have closing ] symbol try this:
driver.findElement(By.xpath("//button[starts-with(#class,'list_header_search_toggle')]"));
For a future reference: You may execute xpath in chrome dev tools using $x() command so you would avoid debugging your xpath in webdriver.
Try JavascriptExecutor to click the element,
Refer code,
WebElement element = driver.findElement(By.xpath("//button[starts-with(#class,'list_header_search_toggle')]"));
JavascriptExecutor executor = (JavascriptExecutor)driver;
executor.executeScript("arguments[0].click();", element);

How to handle Element is not visisble error in selenium while working with dropdown?

While creating automation scripts I encountered 'Element not visible' error while trying to select the option from drop-down list.
HTML code of drop down . Drop-down HTML Code
Here is a short example in Java (similar in other programming languages) using FirefoxDriver:
WebDriver driver = new FirefoxDriver();
WebElement we = driver.findElement(By.xpath("//select[#id='cfr_eventtype_i']"));
Select select = new Select(we);
select.selectByVisibleText("Meeting");

Purpose of findElement method in WebElement (Selenium)

I am learning Selenium WebDriver and I am facing some trouble.
I am unable to get the purpose of the methods findElement,findElements in WebElement when we already have them in WebDriver. What is the difference between the methods in WebElement and WebDriver?
WebDriver driver;
WebElement webObject;
driver.findElement() searches for the element/s on the entire web page while webObject.findElement() searches for the element/s within the webObject object.
Example:
webObject = driver.findElement('some webtable');
webObject.findElement('some cell') :: searches for the cell within that particular table.
driver.findElement('some cell') :: searches for the cell within the entire web page.
Say you have a
<div id="parent">
<a id="child">child</a>
</div>
You can do
WebElement div = driver.findElement(By.id("parent"));
WebElement a = div.findElement(By.id("child"));
so you're able to search inside the elements

Resources