Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Shadow dom elements are not clickable in Safari 10.13.1 #5792

Closed
davidchunhoney opened this issue Apr 18, 2018 · 14 comments
Closed

Shadow dom elements are not clickable in Safari 10.13.1 #5792

davidchunhoney opened this issue Apr 18, 2018 · 14 comments

Comments

@davidchunhoney
Copy link

Meta -

OS: OSX

Selenium Version: 3.8.1

Browser: Safari

Browser Version: 10.13.1

Expected Behavior - Allow clicking of buttons in extensions using shadow DOM on Safari (10+)

Actual Behavior - Upon grabbing a shadow dom element and attempting to click, the follow error message is presented: An unknown server side error occurred while processing the command.

Steps to reproduce -

  1. Install an extension that utilizes the shadow dom on Safari 10+ (i.e. Honey)
  2. Use selenium to grab any clickable element located within the shadow DOM (we use a selenium wrapper class to interact with these elements)
  3. Use <element>.click()
  4. View the error
@p0deje
Copy link
Member

p0deje commented Apr 18, 2018

Please provide concise reproducible test case so that we could act on this issue.

See CONTRIBUTING.md

@davidchunhoney
Copy link
Author

Cool. First, ensure you have an extension installed that uses the shadow DOM on safari. I've used Honey : https://safari-extensions.apple.com/details/?id=forge.safari.honey985c8d42048c4cbeb0bed522bd235ee7-4NREU46PA6

You may need to show shadow DOM nodes before running this as well. To do that, refer to this: https://stackoverflow.com/questions/43270022/does-ios-safari-support-shadow-dom/43270104

from selenium import webdriver

driver = webdriver.Safari()
# Pops up the extension
driver.get('https://www.macys.com/bag/index.ognc?cm_sp=navigation-_-top_nav-_-bag')

# Gets the shadow dom
shadow_root = driver.execute_script('return document.querySelector("#honeyContainer").shadowRoot')

# Click the big orange apply coupons button
shadow_root.find_element_by_id('cta-cash-coupon')

We are seeing this interaction throw an unknown server side error. Please let me know if you see the same

@p0deje
Copy link
Member

p0deje commented Apr 20, 2018

@davidchunhoney Thank you for test case. I've installed Honey extension but I don't see it popping up after I visit https://www.macys.com/bag/index.ognc?cm_sp=navigation-_-top_nav-_-bag URL. I also cannot click the extension button as SafariDriver prevents any interaction with window. Since extension doesn't popup, there are no Honey elements on the page:

shadow_root = driver.execute_script('return document.querySelector("#honeyContainer")')
=> nil

Do you know how to pop it up or maybe you have a different example to try?

@davidchunhoney
Copy link
Author

@p0deje that's odd. Another instance of it popping up automatically should be https://www.walmart.com/cart. Please let me know if you can reach that!

@p0deje
Copy link
Member

p0deje commented Apr 24, 2018

@davidchunhoney Thank you, I can now reproduce the problem. According to the output, Selenium sends a correct request to SafariDriver and something goes wrong inside it:

shadow_root.find_element(id: 'cta-cash-nocoupon').click

2018-04-24 10:11:39 INFO Selenium -> POST session/51E2BE77-2F06-4EFC-9A1F-C2A78ABBDED8/element/node-E799B4E6-CF92-4174-AD3B-1B49F15CDD5B/click
2018-04-24 10:11:39 INFO Selenium <- {"status":13,"sessionId":"51E2BE77-2F06-4EFC-9A1F-C2A78ABBDED8","value":{"message":"An unknown server-side error occurred while processing the command."}}
Selenium::WebDriver::Error::UnknownError: An unknown server-side error occurred while processing the command.
	from /Users/p0deje/Development/selenium/rb/lib/selenium/webdriver/remote/response.rb:69:in `assert_ok'
	from /Users/p0deje/Development/selenium/rb/lib/selenium/webdriver/remote/response.rb:32:in `initialize'
	from /Users/p0deje/Development/selenium/rb/lib/selenium/webdriver/remote/http/common.rb:84:in `new'
	from /Users/p0deje/Development/selenium/rb/lib/selenium/webdriver/remote/http/common.rb:84:in `create_response'
	from /Users/p0deje/Development/selenium/rb/lib/selenium/webdriver/remote/http/default.rb:104:in `request'
	from /Users/p0deje/Development/selenium/rb/lib/selenium/webdriver/remote/http/common.rb:62:in `call'
	from /Users/p0deje/Development/selenium/rb/lib/selenium/webdriver/remote/bridge.rb:164:in `execute'
	from /Users/p0deje/Development/selenium/rb/lib/selenium/webdriver/remote/oss/bridge.rb:579:in `execute'
	from /Users/p0deje/Development/selenium/rb/lib/selenium/webdriver/remote/oss/bridge.rb:326:in `click_element'
	from /Users/p0deje/Development/selenium/rb/lib/selenium/webdriver/common/element.rb:72:in `click'
	from (irb):16
	from /Users/p0deje/.rbenv/versions/2.4.3/bin/irb:11:in `<top (required)>'
	from /Users/p0deje/.rbenv/versions/2.4.3/lib/ruby/gems/2.4.0/gems/bundler-1.16.1/lib/bundler/cli/exec.rb:75:in `load'
	from /Users/p0deje/.rbenv/versions/2.4.3/lib/ruby/gems/2.4.0/gems/bundler-1.16.1/lib/bundler/cli/exec.rb:75:in `kernel_load'
	from /Users/p0deje/.rbenv/versions/2.4.3/lib/ruby/gems/2.4.0/gems/bundler-1.16.1/lib/bundler/cli/exec.rb:28:in `run'
	from /Users/p0deje/.rbenv/versions/2.4.3/lib/ruby/gems/2.4.0/gems/bundler-1.16.1/lib/bundler/cli.rb:424:in `exec'
	from /Users/p0deje/.rbenv/versions/2.4.3/lib/ruby/gems/2.4.0/gems/bundler-1.16.1/lib/bundler/vendor/thor/lib/thor/command.rb:27:in `run'
	from /Users/p0deje/.rbenv/versions/2.4.3/lib/ruby/gems/2.4.0/gems/bundler-1.16.1/lib/bundler/vendor/thor/lib/thor/invocation.rb:126:in `invoke_command'
	from /Users/p0deje/.rbenv/versions/2.4.3/lib/ruby/gems/2.4.0/gems/bundler-1.16.1/lib/bundler/vendor/thor/lib/thor.rb:387:in `dispatch'
	from /Users/p0deje/.rbenv/versions/2.4.3/lib/ruby/gems/2.4.0/gems/bundler-1.16.1/lib/bundler/cli.rb:27:in `dispatch'
	from /Users/p0deje/.rbenv/versions/2.4.3/lib/ruby/gems/2.4.0/gems/bundler-1.16.1/lib/bundler/vendor/thor/lib/thor/base.rb:466:in `start'
	from /Users/p0deje/.rbenv/versions/2.4.3/lib/ruby/gems/2.4.0/gems/bundler-1.16.1/lib/bundler/cli.rb:18:in `start'
	from /Users/p0deje/.rbenv/versions/2.4.3/lib/ruby/gems/2.4.0/gems/bundler-1.16.1/exe/bundle:30:in `block in <top (required)>'
	from /Users/p0deje/.rbenv/versions/2.4.3/lib/ruby/gems/2.4.0/gems/bundler-1.16.1/lib/bundler/friendly_errors.rb:122:in `with_friendly_errors'
	from /Users/p0deje/.rbenv/versions/2.4.3/lib/ruby/gems/2.4.0/gems/bundler-1.16.1/exe/bundle:22:in `<top (required)>'
	from /Users/p0deje/.rbenv/versions/2.4.3/bin/bundle:23:in `load'
	from /Users/p0deje/.rbenv/versions/2.4.3/bin/bundle:23:in `<main>'

I've also tried to test a "normal" shadow DOM assuming Safari extensions have special APIs or permissions and attempts to click elements inside shadow root don't fail with such an error (though they do fail with element visibility checks).

In any event, since this happens somewhere inside SafariDriver and there is no way to get the logs from it for further debugging, I'll have to ask to post this bug to Apple bugtracker. Let's keep this issue open for other people facing this problem.

// cc @burg as one of SafariDriver developers

@goodbomb
Copy link

If anyone is interested, all of www.ea.com is using Polymer, so it has Shadow DOM throughout. We're encountering this error as well in Safari.

@burg
Copy link
Contributor

burg commented Oct 25, 2018

Hi folks, is there a test case that doesn't require installing extensions?

@goodbomb
Copy link

We're using the Page Object model.

// Home.page.js
export default class HomePage {

    get eaLogo() { return browser.shadowDomElement(['ea-local-nav', 'a.eapl-local-nav__shelf-home-link']); }

    constructor() {
        this.title = 'Electronic Arts Home Page - Official EA Site';
    }

    open(path = '', locale = '') {
        browser.windowHandleMaximize();
        browser.url(locale ? `${locale}/${path}` : path);
    }
}

export default new HomePage();
// HomePage.spec.js
import { HomePage } from '../pages';

describe('Verify that the Shadow DOM can be accessed and interacted with', () => {
    it('should navigate to the Home Page when clicked', () => {
        HomePage.open();
        HomePage.eaLogo.click();

        expect(browser.getTitle()).toBe('Electronic Arts Home Page - Official EA Site');
    });
});

And we have a shadow dom custom command that's attached to the browser object.

/**
 * This function runs in the browser context
 * @param {string|Array<string>} selectors
 * @return {?Element}
 */
function findInShadowDom(selectors) {
    if (!Array.isArray(selectors)) {
        selectors = [selectors];
    }

    function findElement(selectors) {
        let currentElement = document;

        for (let i = 0; i < selectors.length; i++) {
            if (i > 0) {
                currentElement = currentElement.shadowRoot;
            }

            if (currentElement) {
                currentElement = currentElement.querySelector(selectors[i]);
            }

            if (!currentElement) {
                break;
            }
        }

        return currentElement;
    }

    if (!(document.body.createShadowRoot || document.body.attachShadow)) {
        selectors = [selectors.join(' ')];
    }

    return findElement(selectors);
}

module.exports = (function() {
    /**
     * Add a command to return an element within a shadow dom.
     * The command takes an array of selectors. Each subsequent
     * array member is within the preceding element's shadow dom.
     *
     * Example:
     *
     *     const elem = browser.shadowDomElement(['foo-bar', 'bar-baz', 'baz-foo']);
     *
     * Browsers which do not have native ShadowDOM support assume each selector is a direct
     * descendant of the parent.
     */
    browser.addCommand('shadowDomElement', function(selectors) {
        return this.execute(findInShadowDom, selectors);
    });

})();

@burg
Copy link
Contributor

burg commented Oct 29, 2018

The W3C specification does not currently provide a way to find elements within a shadow root. Exposing shadow roots to normal Find Element command is not going to work. I don't think this is fixable until we have resolution in the spec.

@p0deje
Copy link
Member

p0deje commented Oct 30, 2018

FYI There is a proposal to add Shadow DOM to spec: w3c/webdriver#1320

@msn-pixel
Copy link

Did this ever work or any work around for this? I am facing the same issue. I implemented the Shadow DOM using Java script executor and works perfectly fine in chrome, but does not work in Safari. It just doesn't click the element in Safari.

@burg
Copy link
Contributor

burg commented Aug 28, 2020 via email

@coemans
Copy link

coemans commented Oct 29, 2020

@burg is there already an update for this issue or do you have an idea when you expect it?

I bump into the issue below when I click an element inside shadow DOM, but it is probably related:

WebDriverError: An unknown error occurred: A JavaScript exception occured: Argument 1 ('element') to Window.getComputedStyle must be an instance of Element

@diemol
Copy link
Member

diemol commented Mar 24, 2021

Shadow DOM is now part of the spec, but some time will pass until all browser vendors have implemented it. I will close this issue just to consolidate all Shadow DOM issues into #5869

@diemol diemol closed this as completed Mar 24, 2021
@github-actions github-actions bot locked and limited conversation to collaborators Sep 5, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

7 participants