pythonseleniumselenium-webdriverselenium-chromedrivershadow-dom

How to cancel a download at chrome://downloads with Selenium in Python 3


This question is very similar to Selenium webdriver can't find elements at chrome://downloads

I'm trying to use Selenium with Python (3) to get at the cancel button on the chrome://downloads page. My use case is that I have an obfuscated link for which a random token is generated every time a user clicks on it. If you don't click on it, you can't start the download (it seems to fire a piece of js that generates the token, but I haven't been successful in digging through the code to figure out how that happens).

For my test to pass, all I need is to verify that:

  1. The download starts (and doesn't give a 404), and
  2. The file it's trying to download is the right size.

The way that I'm trying to accomplish this is by triggering the download by clicking on the button element, then having Selenium open chrome://downloads, cancel the download, and capture the file size of the file that it attempted to download.

In theory this seems like it should work, the stumbling block is trying to access any elements in the #shadow-root tags on the chrome://downloads page. The solution to the other question which I linked above unfortunately no longer works:

driver = webdriver.Chrome("chromedriver.exe")
driver.get("chrome://downloads/")

manager = driver.find_element_by_css_selector('body/deep/downloads-manager')
item = manager.find_element_by_css_selector('body/deep/downloads-item')
shadow = driver.execute_script('return arguments[0].shadowRoot;', item)
link = shadow.find_element_by_css_selector('div#title-area>a')

file_url = link.get_attribute("href")

... as it fails on the item declaration line:

>>> item = manager.find_element_by_css_selector('body/deep/downloads-item')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/lib/python3.7/site-packages/selenium/webdriver/remote/webelement.py", line 430, in find_element_by_css_selector
    return self.find_element(by=By.CSS_SELECTOR, value=css_selector)
  File "/usr/local/lib/python3.7/site-packages/selenium/webdriver/remote/webelement.py", line 659, in find_element
    {"using": by, "value": value})['value']
  File "/usr/local/lib/python3.7/site-packages/selenium/webdriver/remote/webelement.py", line 633, in _execute
    return self._parent.execute(command, params)
  File "/usr/local/lib/python3.7/site-packages/selenium/webdriver/remote/webdriver.py", line 321, in execute
    self.error_handler.check_response(response)
  File "/usr/local/lib/python3.7/site-packages/selenium/webdriver/remote/errorhandler.py", line 242, in check_response
    raise exception_class(message, screen, stacktrace)
selenium.common.exceptions.NoSuchElementException: Message: no such element: Unable to locate element: {"method":"css selector","selector":"body/deep/downloads-item"}
  (Session info: chrome=80.0.3987.149)

This is out of my area of expertise, and any help in figuring out how to get at the cancel button would be greatly appreciated.


Solution

  • Please try the below.

    driver.execute_script("document.querySelector('downloads-manager').shadowRoot.querySelector('#downloadsList downloads-item').shadowRoot.querySelector("cr-button[focus-type='cancel']").click()")
    

    If you need more information how to work on the shadow-root elements, please refer here. And if you want to work on the downloads then you can refer to this and update the js as per your requirement.