mirror of
https://github.com/puppeteer/puppeteer
synced 2024-06-14 14:02:48 +00:00
feat(queryhandler): add built-in pierce handler (#6509)
Adds a handler 'pierce' that pierces shadow roots while querying.
This commit is contained in:
parent
f04bec5a15
commit
8fabe32800
@ -112,7 +112,60 @@ const _defaultHandler = makeQueryHandler({
|
|||||||
element.querySelectorAll(selector),
|
element.querySelectorAll(selector),
|
||||||
});
|
});
|
||||||
|
|
||||||
const _builtInHandlers = new Map([['aria', ariaHandler]]);
|
const pierceHandler = makeQueryHandler({
|
||||||
|
queryOne: (element, selector) => {
|
||||||
|
let found: Element | null = null;
|
||||||
|
const search = (root: Element | ShadowRoot) => {
|
||||||
|
const iter = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT);
|
||||||
|
do {
|
||||||
|
const currentNode = iter.currentNode as HTMLElement;
|
||||||
|
if (currentNode.shadowRoot) {
|
||||||
|
search(currentNode.shadowRoot);
|
||||||
|
}
|
||||||
|
if (currentNode instanceof ShadowRoot) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!found && currentNode.matches(selector)) {
|
||||||
|
found = currentNode;
|
||||||
|
}
|
||||||
|
} while (!found && iter.nextNode());
|
||||||
|
};
|
||||||
|
if (element instanceof Document) {
|
||||||
|
element = element.documentElement;
|
||||||
|
}
|
||||||
|
search(element);
|
||||||
|
return found;
|
||||||
|
},
|
||||||
|
|
||||||
|
queryAll: (element, selector) => {
|
||||||
|
const result: Element[] = [];
|
||||||
|
const collect = (root: Element | ShadowRoot) => {
|
||||||
|
const iter = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT);
|
||||||
|
do {
|
||||||
|
const currentNode = iter.currentNode as HTMLElement;
|
||||||
|
if (currentNode.shadowRoot) {
|
||||||
|
collect(currentNode.shadowRoot);
|
||||||
|
}
|
||||||
|
if (currentNode instanceof ShadowRoot) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (currentNode.matches(selector)) {
|
||||||
|
result.push(currentNode);
|
||||||
|
}
|
||||||
|
} while (iter.nextNode());
|
||||||
|
};
|
||||||
|
if (element instanceof Document) {
|
||||||
|
element = element.documentElement;
|
||||||
|
}
|
||||||
|
collect(element);
|
||||||
|
return result;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const _builtInHandlers = new Map([
|
||||||
|
['aria', ariaHandler],
|
||||||
|
['pierce', pierceHandler],
|
||||||
|
]);
|
||||||
const _queryHandlers = new Map(_builtInHandlers);
|
const _queryHandlers = new Map(_builtInHandlers);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -68,6 +68,45 @@ describe('querySelector', function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('pierceHandler', function () {
|
||||||
|
beforeEach(async () => {
|
||||||
|
const { page } = getTestState();
|
||||||
|
await page.setContent(
|
||||||
|
`<script>
|
||||||
|
const div = document.createElement('div');
|
||||||
|
const shadowRoot = div.attachShadow({mode: 'open'});
|
||||||
|
const div1 = document.createElement('div');
|
||||||
|
div1.textContent = 'Hello';
|
||||||
|
div1.className = 'foo';
|
||||||
|
const div2 = document.createElement('div');
|
||||||
|
div2.textContent = 'World';
|
||||||
|
div2.className = 'foo';
|
||||||
|
shadowRoot.appendChild(div1);
|
||||||
|
shadowRoot.appendChild(div2);
|
||||||
|
document.documentElement.appendChild(div);
|
||||||
|
</script>`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it('should find first element in shadow', async () => {
|
||||||
|
const { page } = getTestState();
|
||||||
|
const div = await page.$('pierce/.foo');
|
||||||
|
const text = await div.evaluate(
|
||||||
|
(element: Element) => element.textContent
|
||||||
|
);
|
||||||
|
expect(text).toBe('Hello');
|
||||||
|
});
|
||||||
|
it('should find all elements in shadow', async () => {
|
||||||
|
const { page } = getTestState();
|
||||||
|
const divs = await page.$$('pierce/.foo');
|
||||||
|
const text = await Promise.all(
|
||||||
|
divs.map((div) =>
|
||||||
|
div.evaluate((element: Element) => element.textContent)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
expect(text.join(' ')).toBe('Hello World');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
// The tests for $$eval are repeated later in this file in the test group 'QueryAll'.
|
// The tests for $$eval are repeated later in this file in the test group 'QueryAll'.
|
||||||
// This is done to also test a query handler where QueryAll returns an Element[]
|
// This is done to also test a query handler where QueryAll returns an Element[]
|
||||||
// as opposed to NodeListOf<Element>.
|
// as opposed to NodeListOf<Element>.
|
||||||
|
Loading…
Reference in New Issue
Block a user