Trying to have this automated on Chrome I came up with an inelegant solution of recursively searching through each shadow dom explicitly using:
driver.executeScript(scriptToRun, cssSelector);
Here's the javascript (passed as a string):
function recursiveSearch(element, target) {
let result = element.querySelector(target);
if (result) { return result; }
let subElements = element.querySelectorAll("*");
for (let i = 0; i < subElements.length; i++) {
let subElement = subElements[i];
if (subElement && subElement.shadowRoot) {
let result = recursiveSearch(subElement.shadowRoot, target);
if (result) return result;
}
}
}
return recursiveSearch(document, arguments[0]);
Since the contents of a shadowRoot
might be empty initially one can use driver.wait
and until.elementIsVisible
to avoid returning a null element.
Async example:
return await driver.wait(until.elementIsVisible(await driver.wait(async () => {
return await driver.executeScript(scriptToRun, cssSelector);
}, timeOut)));
Alternatively
My previous solution was to traverse the elements with shadowdoms explicitly, but is less autonomous. Same as above but with this script:
let element = document.querySelector(arguments[0][0]);
let selectors = arguments[0].slice(1);
for (i = 0; i < selectors.length; i++) {
if (!element || !element.shadowRoot) {return false;}
element = element.shadowRoot.querySelector(selectors[i]);
}
return element;
Where selectors
would be something like:
['parentElement1', 'parentElement2', 'targetElement']
Sidenote
I found that running my automation tests on Firefox Quantum 57.0 doesn't suffer from hidden shadow doms, and any element can be found with a simple:
driver.findElement(searchQuery);