2020-10-10

Web Components Selenium test automation

The one of strengths of Web Components is shadow DOM. It allows to insulate the css rules scoping to own content, allows efficient memory use by sharing DOM, etc... But for QA folks it could make a challenge as usual CSS and XPath selectors would not work anymore. There is a way around.

Elements in Shadow DOM are not available via direct CSS or XPath. Instead you could use JS selector via "Copy JS path":

In this case the full selector is

full selector
document.querySelector("#container-a593f6c588 > div > div > div > div > div > shopping-list")
.shadowRoot.querySelector("div.padded > vaadin-combo-box")
.shadowRoot.querySelector("#input")
.shadowRoot.querySelector("#vaadin-text-field-label-0")

which could be shortened to 

trimmed selector
document.querySelector("shopping-list")
.shadowRoot.querySelector("vaadin-combo-box")
.shadowRoot.querySelector("#input")
.shadowRoot.querySelector("#vaadin-text-field-label-0")


For simplification in styles tables the series of CSS selectors and shadowRoot could be swapped with :shadow-root pseudoselector. CSS handler in this case should convert the string bello to JS above:

pseudo selector :shadow-root
jkp-shop-plans :shadow-root vaadin-combo-box :shadow-root #input :shadow-root #vaadin-text-field-label-0

the "Element locator" css should sniff for ":shadow-root" sub-string and replace with JS sequence above returning JS object. WebDriver has a By.js locator only in JS webdriver implementation. In Java you have to simulate it yourself. Fortunately that is easy via js Executor:

  1. String javascript = "document.querySelector('vaadin-combo-box').shadowRoot.querySelector('#input').shadowRoot.querySelector('#vaadin-text-field-label-0')";  
  2. JavascriptExecutor jsExecutor = (JavascriptExecutor) driver;  
  3. WebElement element = (WebElement) jsExecutor.executeScript(javascript);