Accessing parent Shadow DOM elements using child elements - selenium

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.

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

#FindBy annotations cannot find the element, when element state is not visible

#FindBy annotation cannot find the element, when element state is not visible. We are writing some SEO tests those elements are not visible on webpage.
For example following is not working;
#CacheLookup
#FindBy(xpath = "//meta[#name='description']")
public WebElementFacade metaDescription;
But that works;
WebElement metaV2 = getDriver().findElement(By.xpath("//meta[#name='description']"));
It gives an error like;
org.openqa.selenium.ElementNotVisibleException: Timed out after 15 seconds. Element not available
Any idea ?
Thank you
WebElementFacade expects an element to be visible before interacting with it (as do many of the standard WebElement methods). If you want to check an invisible element, use a WebElement or avoid #FindBy entirely, e.g.
By META_V2 = By.xpath("//meta[#name='description']")
.
.
.
$(META_V2).shouldBePresent();

Selenium how to click/ access an a tag with a href that has a javascript function

I have searched but havent found something similar to what Im trying to do. I'm using java by the way, I'm trying to click/access an a tag with selenium. The issue is that I'm not sure how to go about it. There seems to be a function/event that I need to set off but not quite sure how to. I tried a few ways as get text and clicking but I knew that wasn't going to work. Also I seen there are ways of using JavascriptExecutor but not sure how to use it for my case. I will post the tag below and alsothe function signature, that might help. If theres a similar question please post the link.
<a name="DERIVED_SSS_SCL_SSS_ENRL_CART$276$" id="DERIVED_SSS_SCL_SSS_ENRL_CART$276$" ptlinktgt="pt_peoplecode" tabindex="203" onclick="javascript:cancelBubble(event);" href="javascript:submitAction_win0(document.win0,'DERIVED_SSS_SCL_SSS_ENRL_CART$276$');" class="SSSHYPERLINKBOLDSMALL">Enrollment Shopping Cart</a>
the signature
function submitAction_win0(form, id, event)
You don't need any JS. Just use this xpath:
"//a[contains(#onclick,'javascript:cancelBubble(event);')]"
Be sure the element is clickable, see
import org.openqa.selenium.support.ui.ExpectedConditions;
for the case of more matches:
List<WebElement> elements = driver.findElements(By.xpath("//a[contains(#onclick,'javascript:cancelBubble(event);')]"));
int elementIndex = 0; // 0 to get first of the 33 mathes, 32 to get the last one
WebElement element = elements.get(elementIndex);
element.click();
EDIT:
You should use WebDriverWait to avoid NoSuchElementException this way the driver will wait until the element is clickable... it will wait up to 10 seconds you can tell it to wait more if needed...
WebDriverWait wait = new WebDriverWait(driver, 10);
WebElement element = wait.until(ExpectedConditions.elementToBeClickable(By.partialLinkText("Student Center")));
element.click();
Using click():
WebElement element = driver.findElement(By.cssSelector("a[class='SSSHYPERLINKBOLDSMALL']"));
element.click();
Using JavascriptExecutor (Not recommended):
WebElement element = driver.findElement(By.cssSelector("a[class='SSSHYPERLINKBOLDSMALL']"));
JavascriptExecutor executor = (JavascriptExecutor)driver;
executor.executeScript("arguments[0].click();", element);
You can use other locators too... like linkText:
WebElement element = driver.findElement(By.linkText("Enrollment Shopping Cart"));
Or partialLinkText:
WebElement element = driver.findElement(By.partialLinkText("Shopping Cart"));

Selenium Get first shadow root element inside parents shadow root

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.

Getting time out exception when trying to identify the webelemnt

Below is the Code:
WebElement Username=d1.findElement(By.xpath("//*[#id='username']"));
Username.sendKeys("aadmin");
WebElement Password=d1.findElement(By.xpath("//*[#id='login_form']/tbody/tr/td/table/tbody/tr[12]/td[2]/input"));
Password.sendKeys("admin");
WebElement signin=d1.findElement(By.xpath("//*[#id='submit_']"));
signin.click();
System.out.println("User admin has logged in "+ d1.getTitle());
w1.until(ExpectedConditions.elementToBeClickable(By.xpath("//*[#id='spaces-menu']/ul/li[1]"))).click();
System.out.println("User Admin clicks on Record button");
//Thread.sleep(5000);
d1.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
//Switching the control
int size2=d1.findElements(By.tagName("iframe")).size();
System.out.println("iframe size is---" + size2);
WebDriverWait w2= new WebDriverWait (d1, 15);
//w2.until(ExpectedConditions.frameToBeAvailableAndSwitchToIt(0));
w2.until(ExpectedConditions.frameToBeAvailableAndSwitchToIt(By.tagName("iframe")));
System.out.println("Page title is "+d1.getTitle());
//d1.switchTo().frame("iframe-page-container");
//d1.switchTo().frame(d1.findElement(By.tagName("iframe")));
WebDriverWait w3= new WebDriverWait (d1,30);
WebElement New=w3.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//div[#id='capTypePopup']")));
//WebElement New=w3.until(ExpectedConditions.visibilityOfElementLocated(By.className("menu-middle-normal-button")));
//WebElement New=w3.until(ExpectedConditions.visibilityOfElementLocated(By.id("menuButtonContain-6")));
//New.click();
//d1.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
//JavascriptExecutor js = (JavascriptExecutor) d1;
//WebElement element = d1.findElement(By.id("menuButtonContain-6"));
//js.executeScript("arguments[0].setAttribute('type', '')",element);
//System.out.println(d1.findElement(By.id("menuButtonContain-6")).getAttribute("value"));
//Actions a1= new Actions(d1);
//a1.moveToElement(New).click(New).build().perform();
//d1.findElement(By.xpath("//*[#id='tr_menubar']/td"));
//d1.findElement(By.xpath("//*[#id='capTypePopup']")).click();
//w1.until(ExpectedConditions.elementToBeClickable(By.className("portlet-menu-item"))).click();
//w2.until(ExpectedConditions.elementToBeClickable(By.xpath("//*[#id='capTypePopup']/font"))).click();
System.out.println("Click on the new button");
Below is the DOM of the page, i am trying to click on New button which inside the iframe.
enter image description here
The xpath:
//div[#id='capTypePopup']
you used will find more than one elements,selenium will use the first find element, which may be not the one your expected.
From your screenshot, i noticed there are already two, I guess there should be another one ahead of the div your desired and it's not visible.
Use Dev tool to test the //div[#id='capTypePopup'], and confirm the first found div is visible or not.
If not visible, use more strict xpath which can find the div you desired. After that your problem should gone.