ShadowDOM support request
See original GitHub issueSeems that ShadowDOM support is still missing:
Background
I am working with some Polymer 2 components which implements ShadowDOM v1 spec and I need to select elements inside their shadowRoot
s to run e2e tests. deepCss
might be a solution but it doesn’t work for me. As far as I can see, by.deepCss
is nothing special difference with by.css
but appending * /deep/
at the beginning of the given CSS selector, however, /deep/
seems deprecated on the browser.
I am working with the following versions:
- Node Version:
v6.10.3
- Protractor Version:
v5.1.2
- Angular Version:
v4.2.4
- Browser(s):
Chrome
- Operating System and Version:
Ubuntu v16.04.2 AMD64 LTS Xenial
I think I checked all relevant articles including the followings and I couldn’t get any satisfied answer:
Workaround
Anyway, I can select inner elements of ShadowDOM elements by adding a custom locator. Here is my workaround:
/**
* Usage:
* O element(by.css_sr('#parentElement #innerElement')) <=> $('#parentElement #innerElement')
* O element(by.css_sr('#parentElement::sr #innerElement')) <=> $('#parentElement').shadowRoot.$('#innerElement')
* O element.all(by.css_sr('#parentElement .inner-element')) <=> $$('#parentElement .inner-element')
* O element.all(by.css_sr('#parentElement::sr .inner-element')) <=> $$('#parentElement').shadowRoot.$$('.inner-element')
* O parentElement.element(by.css_sr('#innerElement')) <=> parentElement.$('#innerElement')
* O parentElement.element(by.css_sr('::sr #innerElement')) <=> parentElement.shadowRoot.$('#innerElement')
* O parentElement.all(by.css_sr('.inner-element')) <=> parentElement.$$('.inner-element')
* O parentElement.all(by.css_sr('::sr .inner-element')) <=> parentElement.shadowRoot.$$('.inner-element')
*/
by.addLocator('css_sr', (cssSelector: string, opt_parentElement, opt_rootSelector) => {
let selectors = cssSelector.split('::sr');
if (selectors.length === 0) {
return [];
}
let shadowDomInUse = (document.head.createShadowRoot || document.head.attachShadow);
let getShadowRoot = (el) => ((el && shadowDomInUse) ? el.shadowRoot : el);
let findAllMatches = (selector: string, targets: any[], firstTry: boolean) => {
let using, i, matches = [];
for (i = 0; i < targets.length; ++i) {
using = (firstTry) ? targets[i] : getShadowRoot(targets[i]);
if (using) {
if (selector === '') {
matches.push(using);
} else {
Array.prototype.push.apply(matches, using.querySelectorAll(selector));
}
}
}
return matches;
};
let matches = findAllMatches(selectors.shift().trim(), [opt_parentElement || document], true);
while (selectors.length > 0 && matches.length > 0) {
matches = findAllMatches(selectors.shift().trim(), matches, false);
}
return matches;
});
Conclusion
Since the workaround works on my side, so I am asking~ is there anything I missed or I misused the background principle of Protractor in my workaround? I am politely saying … if I don’t violate your certain rules too much, is it possible to add ShadowDOM support something like that into the next update of Protractor?
Thank you.
Issue Analytics
- State:
- Created 6 years ago
- Reactions:23
- Comments:58 (5 by maintainers)
Top GitHub Comments
What is the status on this? We would like to be able to use the by.shadowRoot function.
@wswebcreation I just created a PR #4392.