Automating Shadow DOM with Selenium WebDriver

How to drive web elements inside a shadow root on a web page

An Example

The task: Add a new list item to the Editable List of the demo Fiddle site.

Screenshot of Luigi Demo Page which we are about to test
# add new list element
driver.find_element(:xpath, "//input[@class='add-new-list-item-input']").send_keys("Buy milk and eggs")
driver.find_element(:xpath, "//button[@class='add-new-list-item-input']").click# verify new element is there
expect(page_text).to include("Buy milk and eggs")

Finding the Shadow DOM

Open Inspect Element in Chrome (or equivalent for other browsers).

Testing in a Shadow DOM

The approach:

# regex this if you wish
shadow_element_wrapper_tag = "luigi-wc-2f77632f6c6973742e6a73"
elem = driver.find_element(:tag_name, shadow_element_wrapper_tag)
# get the shadow root using Javascript
shadow_root = driver.execute_script("return arguments[0].shadowRoot", elem)
input_elem = shadow_root.find_element(:tag_name, "input")
input_elem.send_keys("Mario here I come!")
shadow_root.find_elements(:tag_name, "button").last.click
expect(driver.find_element(:tag, "body").text).to include("...")

Complete Test Script

 # retrieve using regex for a dynamic shadow root
def retrieve_shadow_root
elem = driver.find_elements(:xpath, "//div[contains(@class, 'wcContainer svelte-')]").first
puts "ELEM: #{elem}"

elem_html = driver.execute_script("return arguments[0].outerHTML;", elem)
puts elem_html
if elem_html =~ /<luigi-wc-([\d\w]+)>/
shadow_element_wrapper_tag_name = "luigi-wc-" + $1
elem = driver.find_element(:xpath, "//div[contains(@class, 'wcContainer svelte-')]/#{shadow_element_wrapper_tag_name}")
@shadow_root = driver.execute_script("return arguments[0].shadowRoot", elem)
end
end
shadow_root = retrieve_shadow_root()input_elem = shadow_root.find_element(:tag_name, "input") input_elem.send_keys("Mario, here I come")button_elems = shadow_root.find_elements(:tag_name, "button") add_button = button_elems.last
add_button.click

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store