Selenium Get first shadow root element inside parents shadow root - selenium

Currently, I am trying to make my progressive web apps Testing automation using selenium.As All my element I get from different shadow room.
Like
//This function will return the element inside shadow root
public WebElement GetShadowRoot(WebElement host) {
WebElement shadowRoot = (WebElement) ((JavascriptExecutor) driver).executeScript("return arguments[0].shadowRoot", host);
return shadowRoot;
}
WebElement MainHost = driver.findElement(By.cssSelector("vrs-
app[page='refine']"));
WebElement shadow1 = GetShadowRoot(MainHost);
WebElement host2 = shadow1.findElement(By.cssSelector("vrs-refine"));
WebElement shadow2 = GetShadowRoot(host2);
System.out.println(shadow2);
WebElement host3 = shadow2.findElement(By.cssSelector("vrs-list-
generator"));
WebElement shadow3 = GetShadowRoot(host3);
System.out.println(shadow3);
WebElement host4 = shadow3.findElement(By.cssSelector("vrs-single-property-tile:first-child"));
WebElement shadow4 = GetShadowRoot(host4);
Using This method I get my HTML element through cssSelector.
Here I am getting the issue of CSS selector vrs-single-property-tile:first-child" I have several shadow root at same name only id is different.And ID change dynamically.
Here I want to take this single propery tiles and print the property title and price
Here is my temporary URL so that you can get an idea
My goal is to access this element shadow3.findElements(By.cssSelector("#gtmTitle > h3"));
Any type of help will be appreciated.

Related

Unable to switch to iframe using Selenium Webdriver

I am trying to learn the feature drag and drop in the webpage
Link
The Section Books is inside the iframe.
But i am unable to access the iframe I am getting below error
no such element: Unable to locate element:
Below are the Xpath i tried
// WebElement frame =driver.findElement(By.xpath("//div[#id='root']//iframe[#class='st-preview-body']"));
// WebElement frame =driver.findElement(By.tagName("iframe"));
WebElement frame =driver.findElement(By.xpath("//iframe[#src='https://snippet.webixcode.com/snippet.html?0.0.3']"));
driver.switchTo().frame(frame);
I also tried using by.id and also xpath using id and class name
What will be the mistake i am doing? To my knowledge there is only one iframe present
The code for drag and drop. will this work?
WebElement fromdrag=driver.findElement(By.xpath("//span[#class='dhx_tree-list-item__text'][normalize-space()='Lawrence Block']"));
WebElement todrop=driver.findElement(By.id("treeTarget"));
Actions act=new Actions(driver);
act.dragAndDrop(fromdrag, todrop).build().perform();
Its a Nested iframe. We need to switch to those iframes one by one to access Elements from All Books.
The page takes time to load, better apply Explicit waits to find the Elements. And you also need to driver.switchTo().defaultContent(); to come out of the iframe and find Elements outside the iframe
public void iframequestion() {
System.setProperty("webdriver.chrome.driver","C:\\expediaproject\\Chromedriver\\chromedriver.exe");
driver = new ChromeDriver();
driver.manage().window().maximize();
driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
JavascriptExecutor js = (JavascriptExecutor)driver;
driver.get("https://dhtmlx.com/docs/products/dhtmlxTree/");
WebElement frame1 = driver.findElement(By.xpath("//iframe[#src='https://snippet.dhtmlx.com/3e0b5r57?mode=mobile']"));
js.executeScript("arguments[0].scrollIntoView(true);", frame1);
driver.switchTo().frame(frame1);
WebElement frame2 = driver.findElement(By.xpath("//iframe[#class='st-preview-body']"));
driver.switchTo().frame(frame2);
WebElement frame3 = driver.findElement(By.id("content"));
driver.switchTo().frame(frame3);
WebElement ele1 = driver.findElement(By.xpath("//span[text()='Fiction & Fantasy']"));
System.out.println(ele1.getText());
driver.switchTo().defaultContent();
WebElement ele2 = driver.findElement(By.xpath("//a[text()='View more demos']"));
System.out.println(ele2.getText());
driver.quit();
}
Fiction & Fantasy
View more demos

How to find a webelement that has 'checked' attribute in list of child WebElements through Selenium using Katalon Studio

I have radio buttons that when either radio button is selected, it gets a checked attribute.
This is how the HTML looks:
My implementation of getting the descendant that has a checked attribute:
public TestObject getCheckedTestObjectFromParent(String parentID){
WebDriver driver = DriverFactory.getWebDriver()
WebElement parentWebElement = driver.findElement(By.id(parentID))
List<WebElement> children = parentWebElement.findElements(By.xpath(".//*"))
println(children.size())
for(int i = 0; i < children.size(); i++){
TestObject childTestObject = getTestObjectFromWebElement(children[i])
if(WebUI.verifyElementHasAttribute(childTestObject, 'checked', 10, FailureHandling.OPTIONAL)){
return childTestObject
}
}
}
This is the helper method that I use for converting a WebElement to a TestObject :
public TestObject getTestObjectFromWebElement(WebElement element) {
TestObject object = new TestObject()
object.addProperty("xpath", ConditionType.CONTAINS, getXPathFromElement(element))
return object
}
Helper for getting xpath from WebElement :
protected String getXPathFromElement(WebElement element) {
String elementDescription = element.toString();
return elementDescription.substring(elementDescription.lastIndexOf("-> xpath: ") + 10, elementDescription.lastIndexOf("]"));
}
Am I missing something here or is there something wrong with the WebElement -> TestObject conversion? Also is this possible using only TestObject or only WebElement? If I could get child TestObjects containing certain attributes from a parent TestObject then I wouldn't need to make a mess using WebElements.
Edit
Another image of the HTML, this time with the first radio button checked. As you can see the second radio button no longer has the 'checked' attribute.
To retrieve the WebElement that is currently checked you can use either of the following Locator Strategies:
cssSelector:
WebElement elem = new WebDriverWait(driver, 20).until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("div.a-toggle.a-toggle--anycase#config-src-laserunits div[id^='config-src-laserunits-']>input.a-toggle__radio[checked]")));
xpath:
WebElement elem = new WebDriverWait(driver, 20).until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//div[#class='a-toggle a-toggle--anycase' and #id='config-src-laserunits']//div[starts-with(#id, 'config-src-laserunits-')]/input[#class='a-toggle__radio' and #checked]")));
I was able to fix this by changing (".//*") to (".//*[#checked='checked']")
parentWebElement.findElement(By.xpath(".//*[#checked='checked']")
will find the element that has the attribute checked = 'checked'
Notice that a list is no longer needed as there can only be 1 checked radio button at a time.
Implementation
public TestObject getCheckedTestObjectFromParent(String parentID){
WebDriver driver = DriverFactory.getWebDriver()
WebElement parentWebElement = driver.findElement(By.id(parentID))
//there is only 1 checked child at a time, so there is no need for a list
WebElement checkedChild = parentWebElement.findElement(By.xpath(".//*[#checked='checked']"))
//convert the WebElement to a TestObject and return
return getTestObjectFromWebElement(checkedChild)
}
Try this Xpath
"//input[#id='config-src-laserunits-wavnmradio' and #checked='checked']"
Example:
List<WebElement> children = driver.findElements(By.xpath("//input[#id='config-src-laserunits-wavnmradio' and #checked='checked']"))
It should return size 1
EDIT
List<WebElement> children = driver.findElements(By.xpath("//input[#id='config-src-laserunits-wavnmradio']"));
for (int i=0;i<children.size();i++)
{
if(children.get(i).getAttribute("checked")!=null)
{
System.out.println("radio button is checked");
}
}

Getting value from tooltip when hover on svg element on the graph created with highcharts

I want to get text/value from the tooltip which appears when hover on svg element on the graph created with highcharts.
Below is the snippet:
Tried below code:
List<WebElement> Volumelist=driver.findElements(By.xpath("//*[name()='svg']//*[name()='g'][5]//*[name()='g'][2]//*[name()='path']"));
System.out.println("Got the list!");
new Actions(driver).moveToElement(Volumelist.get(1)).clickAndHold().build().perform();
WebElement toolTip=wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//*[#class='highcharts-halo highcharts-color-3'][#visibility='visible']")));
System.out.println("toolTip text= "+toolTip.getText());
First hover on the element on which tooltip appears and then execute :
String tooltipText = driver.findElement(By.cssSelector("g.highcharts-tooltip text tspan")).getAttribute("textContent");
You can ping me at sandpdangi13#gmail.com if that does not work for you.
Try to hover to tooltip element using this method if normal Actions hover is not working :
public static void mouseHoverJScript(WebDriver driver, WebElement element) {
String mouseOverScript = "if(document.createEvent){var evObj = document.createEvent('MouseEvents');evObj.initEvent('mouseover', true, false);"
+ " arguments[0].dispatchEvent(evObj);} else if(document.createEventObject) { arguments[0].fireEvent('onmouseover');}";
((JavascriptExecutor) driver).executeScript(mouseOverScript,
element);
I found over their examples page the values with this XPath:
driver.findElement(By.xpath(.//*[name()="g" and contains(#class,"highcharts-label")]//*[name()="tspan" and #style='font-weight:bold'])).getText();
The first step is move the mouse over one point, for example with this XPath, move to the first point:
WebElement elem = DriverUtils.driver.findElement(By.xpath(.//*[name()='path' and contains(#class, 'highcharts-point highcharts-color')][1]));
new Actions(driver).moveToElement(elem).clickAndHold().build().perform();
I used the Selenium 3.9.0, with previous 3.4.0 version doesn't work for me.
So, solution that worked for me:
WebElement elem = driver.findElement(By.xpath("//[name()='svg']//[name()='g'][5]//[name()='g'][2]//[name()='path'][1]"));
new Actions(driver).moveToElement(elem).clickAndHold().moveByOffset(1, 1).pause(1000).perform();
String text=driver.findElement(By.xpath("//[name()='svg']//[name()='g'][9]//[name()='text'][1]//[name()='tspan'][3]")).getText();

Accessing parent Shadow DOM elements using child elements

Shadow Dom structure:
In the above shadow dom structure we are able to access the individual elements using the selenium and javascript as below in chrome:
In Firefox:
//div[#class='style-scope rock-tabs' and not(#hidden)]//div/span[contains(text(),'"+AttrName+"')]/../preceding-sibling::div/paper-icon-button[1]/iron-icon[1]
In Chrome:
We are using the below to navigate to the iron-icon
WebElement Attrbuttona1=Button2.findElement(By.id("contentViewManager"));
WebElement eAttrbutton1=expandRootElement(Attrbuttona1);
WebElement Attrbutton2=eAttrbutton1.findElement(By.id("contentViewManager"));
WebElement Attrbutton2a=Attrbutton2.findElement(By.xpath("rock-content-view[#name='entity-manage']"));
WebElement eAttrbutton2=expandRootElement(Attrbutton2a);
WebElement Attrbutton3=eAttrbutton2.findElement(By.id("content-view-container"));
WebElement Attrbuttona3=Attrbutton3.findElement(By.id("component"));
WebElement eAttrbutton3=expandRootElement(Attrbuttona3);
WebElement Attrbutton4=eAttrbutton3.findElement(By.className("content"));
WebElement AttrTagName2=Attrbutton4.findElement(By.tagName("rock-tabs"));
WebElement eaAttrbutton4=expandRootElement(AttrTagName2);
WebElement Attrbutton5=eaAttrbutton4.findElement(By.id(attrType));
WebElement eAttr1=expandRootElement(Attrbutton5);
WebElement Attr2=eAttr1.findElement(By.className("group-container"));
WebElement Attr3=Attr2.findElement(By.tagName("rock-attribute"));
WebElement eAttr3=expandRootElement(Attr3);
WebElement Attri4=eAttr3.findElement(By.className("attribute-icons"));
WebElement Attr4=Attri4.findElement(By.tagName("paper-icon-button"));
WebElement eAttr4=expandRootElement(Attr4);
WebElement Attr5=eAttr4.findElement(By.tagName("iron-icon"));
((JavascriptExecutor) driver).executeScript("arguments[0].click();",Attr5);
public WebElement expandRootElement(WebElement element) {
WebElement ele = (WebElement) ((JavascriptExecutor) driver)
.executeScript("return arguments[0].shadowRoot",element);
return ele;
}
Now i want to click on iron icon for attribute where div/span[text()='Product Name']
Taking the child element as a base and i need to traverse back to shadow element and get the icon related to only that particular attribute.
How can i proceed in clicking the element based on a different element and traverse back, which should be supported in all browsers(chrome and firefox)?
In JavaScript, if you want to "traverse back" from an element called element1:
To get a parent element, use its parentElement attribute. You can do it recursively if the element you want is higher in the tree.
element1.parentElement
To get the Shadow DOM element, invoke getRootNode() to get the Shadow DOM root and use its host attribute to get its host element.
element1.getRootNode().host
Note: Since it's JavaScript code, it should be executed in Selenium's executeScript() method.

Modify innerHTML using Selenium

I have this element:
WebElement element = ...
string val = element.getAttribute("innerHTML");
All I want to do is to change this innerHTML on my web page.
Is it possible?
Try this:
WebElement element = ...
((JavascriptExecutor)driver).executeScript(
"var ele=arguments[0]; ele.innerHTML = 'my new content';", element);
Selenium WebDriver does not have any direct methods to do so to change the DOM itself. However we can use JavascriptExecutor to use javascript to modify the DOM.
check this example to change the background color. You will get an idea to change the innerHTML as well.
in python use this :
element = driver.find_element_by_id("some_id")
driver.execute_script("arguments[0].innerText = 'what_you_want_to_show'", element)