python-3.xselenium-webdrivershadow-root

How to work with shadow root with selenium in Python?


I would like to upload file at quick-actions.express.adobe.com, so I do the following:

driver.get("https://quick-actions.express.adobe.com/remove-background")
WebDriverWait(driver, 60).until(EC.presence_of_element_located((By.TAG_NAME, "body")))
shadow_host = driver.find_element(By.TAG_NAME, "qa-standalone-app")
shadow_root = shadow_host.shadow_root
file_input = shadow_root.find_element(By.TAG_NAME, "input")

But it says selenium.common.exceptions.InvalidArgumentException: Message: invalid argument: invalid locator.

I tried to access the element directly, but it doesn't work:

file_input = WebDriverWait(driver, 10).until(
     EC.presence_of_element_located((By.XPATH, '//input[@type="file"]'))
)
file_input.send_keys(file_path)

Is there any other way to upload the file there?

Upd. enter image description here

It fails when multiple roots are used:

shadow_root1 = driver.find_element(By.CSS_SELECTOR, "qa-standalone-app").shadow_root
shadow_root2 = shadow_root1.find_element(By.CSS_SELECTOR, "standalone-quick-action").shadow_root
shadow_root3 = shadow_root2.find_element(By.CSS_SELECTOR, "qa-app-root").shadow_root
shadow_root4 = shadow_root3.find_element(By.TAG_NAME, "qa-app").shadow_root # fails here
shadow_root5 = shadow_root4.find_element(By.CSS_SELECTOR, "qa-remove-background-editor").shadow_root
shadow_root6 = shadow_root5.find_element(By.CSS_SELECTOR, "qa-workspace").shadow_root
shadow_root7 = shadow_root6.find_element(By.CSS_SELECTOR, "qa-file-upload").shadow_root

Solution

  • The problem is that there are multiple levels of nested shadow-doms on the page that contain your desired INPUT.

    Here's a couple levels of the pattern that you can follow,

    from selenium import webdriver
    from selenium.webdriver.common.by import By
    
    driver = webdriver.Chrome()
    driver.get("https://quick-actions.express.adobe.com/remove-background")
    
    shadow_root1 = driver.find_element(By.CSS_SELECTOR, "qa-standalone-app").shadow_root
    shadow_root2 = shadow_root1.find_element(By.CSS_SELECTOR, "standalone-quick-action").shadow_root
    

    Just keep adding levels of shadow-root until you get to the level that has the desired INPUT and go from there...