Shadow DOM element access in Selenium Java - Build an Automation Script
import org.openqa.selenium.By; import org.openqa.selenium.JavascriptExecutor; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.chrome.ChromeDriver; import org.openqa.selenium.support.ui.ExpectedConditions; import org.openqa.selenium.support.ui.WebDriverWait; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; import java.time.Duration; public class ShadowDomTest { private WebDriver driver; private WebDriverWait wait; @BeforeEach public void setUp() { driver = new ChromeDriver(); wait = new WebDriverWait(driver, Duration.ofSeconds(10)); driver.get("https://example.com/shadowdompage"); // Replace with actual URL } @Test public void testShadowDomText() { // Wait for shadow host element to be present WebElement shadowHost = wait.until(ExpectedConditions.presenceOfElementLocated(By.id("shadow-host"))); // Use JavaScriptExecutor to get shadow root JavascriptExecutor js = (JavascriptExecutor) driver; WebElement shadowRoot = (WebElement) js.executeScript("return arguments[0].shadowRoot", shadowHost); // Find the span inside shadow root WebElement shadowText = shadowRoot.findElement(By.cssSelector("span.shadow-text")); // Assert the text content String actualText = shadowText.getText(); assertEquals("Hello Shadow DOM", actualText, "Shadow DOM text should match expected value"); } @AfterEach public void tearDown() { if (driver != null) { driver.quit(); } } }
The test starts by opening the browser and navigating to the page with the Shadow DOM.
We wait explicitly for the shadow host element with id 'shadow-host' to be present to avoid timing issues.
Since Selenium does not support Shadow DOM directly, we use JavascriptExecutor to get the shadow root of the host element.
Inside the shadow root, we locate the span element with class 'shadow-text' using a CSS selector.
We then get the text of this span and assert it equals the expected string 'Hello Shadow DOM'.
Finally, the browser is closed in the tearDown method to clean up.
Now add data-driven testing to verify shadow DOM text for 3 different shadow hosts with ids 'shadow-host1', 'shadow-host2', 'shadow-host3' and their expected texts.
Practice
Solution
Step 1: Understand Shadow DOM structure
Shadow DOM creates a separate DOM tree inside a host element, hiding its internals from the main DOM.Step 2: Recognize access limitation
Normal Selenium methods cannot directly access elements inside this hidden tree, so special methods are needed.Final Answer:
Because Shadow DOM elements are hidden inside a separate DOM tree and not directly accessible. -> Option AQuick Check:
Shadow DOM hides elements = Need special access [OK]
- Thinking Shadow DOM uses a different language
- Assuming Shadow DOM elements are deprecated
- Believing Shadow DOM is only for mobile
Solution
Step 1: Find the shadow host element
Usedriver.findElement(By.id("shadowHost"))to get the host element.Step 2: Access the shadow root and find the button
CallgetShadowRoot()on the host, then find the button inside the shadow root.Final Answer:
Use getShadowRoot() on host, then findElement inside shadow root. -> Option BQuick Check:
Shadow root access = getShadowRoot() then findElement [OK]
- Trying to find shadow elements directly from driver
- Calling getShadowRoot() on driver instead of host
- Using nested findElement without shadow root
WebElement host = driver.findElement(By.id("shadowHost"));
WebElement shadowRoot = host.getShadowRoot();
WebElement button = shadowRoot.findElement(By.cssSelector("button"));
System.out.println(button.getText());Solution
Step 1: Access shadow host and shadow root
The code correctly finds the shadow host and callsgetShadowRoot()to access the Shadow DOM.Step 2: Find button and get its text
The button inside the Shadow DOM is found by CSS selector andgetText()returns its visible text 'Click Me'.Final Answer:
Click Me -> Option AQuick Check:
Correct shadow DOM access = button text output [OK]
- Expecting NoSuchElementException without shadow root access
- Assuming getText() returns null
- Confusing shadow host text with shadow element text
WebElement button = driver.findElement(By.cssSelector("#shadowHost button"));
button.click();Solution
Step 1: Analyze element access method
The code tries to find the button inside Shadow DOM directly from driver using a combined CSS selector.Step 2: Identify Shadow DOM access requirement
Shadow DOM elements require accessing the shadow root viagetShadowRoot()on the host element before finding inner elements.Final Answer:
It tries to find the button directly without accessing the shadow root first. -> Option DQuick Check:
Shadow DOM needs getShadowRoot() before findElement [OK]
- Using combined CSS selector ignoring shadow root
- Thinking CSS selector alone works inside Shadow DOM
- Assuming button cannot be clicked inside Shadow DOM
Solution
Step 1: Access outer shadow root
Find the outer host by id and callgetShadowRoot()to access its Shadow DOM.Step 2: Access inner shadow root
Inside the outer shadow root, find the inner host element, then callgetShadowRoot()again to access the inner Shadow DOM.Step 3: Find and click the button
Inside the inner shadow root, find the button and callclick()on it.Final Answer:
Access each shadow root step-by-step before finding nested elements. -> Option CQuick Check:
Nested Shadow DOM requires chained getShadowRoot() calls [OK]
- Trying to find nested shadow elements directly from driver
- Skipping inner shadow root access
- Using combined CSS selectors ignoring Shadow DOM
Ready to prove it?
Pass the test and this pattern moves unknown
