querySelector that can pierce Shadow DOM roots without knowing the path through nested shadow roots. Useful for automated testing of Web Components e.g. with Selenium, Puppeteer.
// available as an ES6 module for importing in Browser environments
import { querySelectorAllDeep, querySelectorDeep } from 'query-selector-shadow-dom';
/**
* @name get list of links which may be in the shadow dom
*
*/
const puppeteer = require('puppeteer');
const path = require('path');
(async() => {
try {
const browser = await puppeteer.launch()
const page = await browser.newPage()
await page.goto('https://www.polymer-project.org/2.0/docs/upgrade')
await page.addScriptTag({
path: path.join(__dirname, 'node_modules/query-selector-shadow-dom/dist/querySelectorShadowDom.js')
});
// execute standard javascript in the context of the page.
const downloads = await page.evaluate(() => {
const anchors = Array.from(querySelectorShadowDom.querySelectorAllDeep('a'))
return anchors.map(anchor => anchor.href)
})
console.log(downloads)
await browser.close()
} catch (e) {
console.error(e);
}
})()
// query from another node
querySelectorShadowDom.querySelectorAllDeep('child', document.querySelector('#startNode'));
// query an iframe
querySelectorShadowDom.querySelectorAllDeep('child', iframe.contentDocument);
This library does not allow you to query across iframe boundaries, you will ned to get a reference to the iframe you want to interact with.
If your iframe is inside of a shadow root you could cuse querySelectorDeep
to find the iframe, then pass the contentDocument
into the 2nd argument of querySelectorDeep
or querySelectorAllDeep
.
In the below examples the components being searched for are nested within web components shadowRoots
.
// Download and Paste the lib code in dist into chrome://downloads console to try it out :)
console.log(querySelectorShadowDom.querySelectorAllDeep('downloads-item:nth-child(4) #remove'));
console.log(querySelectorShadowDom.querySelectorAllDeep('#downloads-list .is-active a[href^="https://"]'));
console.log(querySelectorShadowDom.querySelectorDeep('#downloads-list div#title-area + a'));
If using the polyfills and shady DOM, this library will still work.
- Shipped as an ES6 module to be included using a bundler of your choice (or not).
- ES5 version bundled ontop the window as
window.querySelectorShadowDom
available for easy include into a test framework
npm install
npm test
npm run watch
npm run build