How to access and interact with Shadow DOM using Watir?

后端 未结 2 1280
温柔的废话
温柔的废话 2021-01-23 22:26

I need to access this page chrome://downloads/ and check that a file has been downloaded but it\'s Shadow DOM.

I\'ve found this article how to access DOM Elements With S

相关标签:
2条回答
  • 2021-01-23 22:34

    As mentioned by titusfortner's deleted answer, Selenium Easy had a related article, "Working with Shadow DOM Elements using Webdriver". It turns out that you can get a shadow element via JavaScript and then interact with it's descendants as normal.

    However, due to the way Watir is written, I had to monkey-patch Watir::Browser to make it work. I'll see if I can get a more permanent fix, but for now, here's a working example:

    require 'watir'
    
    # Monkey-patch due to being unable to check the tag name of the shadow root
    class Watir::Browser
      def wrap_element(scope, element)
        Watir.element_class_for(element.tag_name.downcase).new(scope, element: element)
      rescue Selenium::WebDriver::Error::UnknownError # need a better rescue
        Watir::Element.new(scope, element: element)
      end
    end
    
    def expand_root_element(element, browser)
        browser.execute_script("return arguments[0].shadowRoot", element)
    end
    
    browser = Watir::Browser.new
    
    # Create a download item
    browser.goto('https://chromedriver.storage.googleapis.com/2.33/chromedriver_win32.zip')
    browser.goto('chrome://downloads')
    
    # Navigate the shadow DOM to the download items
    download_manager = browser.element(css: 'downloads-manager')
    shadow_download_manager = expand_root_element(download_manager, browser)
    
    download_items = shadow_download_manager.elements(css: '#downloads-list downloads-item')
    shadow_download_items = download_items.map { |s| expand_root_element(s, browser) }
    
    # Find a specific download item by file name
    expected_file = /chromedriver_win32/
    download = shadow_download_items.find { |s| s.span(id: 'name').text_content =~ expected_file }
    
    # Do something with the download - eg wait for the download to complete
    download.link(id: 'show').wait_until_present
    
    0 讨论(0)
  • 2021-01-23 22:44

    I wanted to let people know that this monkey patch no longer works and I do not know of a good work around.

    The initial problem that Justin solved was that a shadow dom attached to an element actually doesn't have a tag name. Hence his monkey patch. But with updates, that patch no longer works. The initial error is a change in JS errors (see bullet #1 below). The new problem is that shadow dom's are attached to real elements, but the shadowRoot itself is not a real element. It's like a quasi-element.

    • The error is now a Selenium::WebDriver::Error::JavascriptError, so your rescue line needs updated for the correct error.
    • Even if you fix that, you'll get more errors javascript error: Failed to execute 'getComputedStyle' on 'Window': parameter 1 is not of type 'Element' This is the result of an internal API call on the wire protocol. For example, I traced the error to selenium-webdriver-3.142.7/lib/selenium/webdriver/remote/http/default.rb:81 The API call returns an internal 500 error with a payload of "{"value":{"error":"javascript error","message":"javascript error: Failed to execute 'getComputedStyle' on 'Window': parameter 1 is not of type 'Element'.\n (Session info: chrome=87.0.4280.88)" I do not know how to get around this.
    0 讨论(0)
提交回复
热议问题