chore: do not use Array.from in injected script (#6876)
This method is most often overridden by some bad polyfill that does not work correctly and breaks `$eval` and `$$eval` methods. As a best-effort fix, use a `[...iterable]` throughout the code.
This commit is contained in:
parent
f2cc439d8b
commit
d4482f3ad3
|
|
@ -124,7 +124,7 @@ export class InjectedScript {
|
||||||
}
|
}
|
||||||
set = newSet;
|
set = newSet;
|
||||||
}
|
}
|
||||||
let result = Array.from(set) as Element[];
|
let result = [...set] as Element[];
|
||||||
if (partsToCheckOne.length) {
|
if (partsToCheckOne.length) {
|
||||||
const partial = { parts: partsToCheckOne };
|
const partial = { parts: partsToCheckOne };
|
||||||
result = result.filter(e => !!this._querySelectorRecursively(e, partial, 0));
|
result = result.filter(e => !!this._querySelectorRecursively(e, partial, 0));
|
||||||
|
|
@ -448,7 +448,7 @@ export class InjectedScript {
|
||||||
if (element.nodeName.toLowerCase() !== 'select')
|
if (element.nodeName.toLowerCase() !== 'select')
|
||||||
return 'error:notselect';
|
return 'error:notselect';
|
||||||
const select = element as HTMLSelectElement;
|
const select = element as HTMLSelectElement;
|
||||||
const options = Array.from(select.options);
|
const options = [...select.options];
|
||||||
const selectedOptions = [];
|
const selectedOptions = [];
|
||||||
let remainingOptionsToSelect = optionsToSelect.slice();
|
let remainingOptionsToSelect = optionsToSelect.slice();
|
||||||
for (let index = 0; index < options.length; index++) {
|
for (let index = 0; index < options.length; index++) {
|
||||||
|
|
|
||||||
|
|
@ -68,9 +68,9 @@ export class SelectorEvaluatorImpl implements SelectorEvaluator {
|
||||||
this._engines.set('near', createPositionEngine('near', boxNear));
|
this._engines.set('near', createPositionEngine('near', boxNear));
|
||||||
this._engines.set('nth-match', nthMatchEngine);
|
this._engines.set('nth-match', nthMatchEngine);
|
||||||
|
|
||||||
const allNames = Array.from(this._engines.keys());
|
const allNames = [...this._engines.keys()];
|
||||||
allNames.sort();
|
allNames.sort();
|
||||||
const parserNames = Array.from(customCSSNames).slice();
|
const parserNames = [...customCSSNames];
|
||||||
parserNames.sort();
|
parserNames.sort();
|
||||||
if (allNames.join('|') !== parserNames.join('|'))
|
if (allNames.join('|') !== parserNames.join('|'))
|
||||||
throw new Error(`Please keep customCSSNames in sync with evaluator engines: ${allNames.join('|')} vs ${parserNames.join('|')}`);
|
throw new Error(`Please keep customCSSNames in sync with evaluator engines: ${allNames.join('|')} vs ${parserNames.join('|')}`);
|
||||||
|
|
|
||||||
|
|
@ -245,7 +245,7 @@ function cssFallback(injectedScript: InjectedScript, targetElement: Element): Se
|
||||||
const parent = element.parentNode as (Element | ShadowRoot);
|
const parent = element.parentNode as (Element | ShadowRoot);
|
||||||
|
|
||||||
// Combine class names until unique.
|
// Combine class names until unique.
|
||||||
const classes = Array.from(element.classList);
|
const classes = [...element.classList];
|
||||||
for (let i = 0; i < classes.length; ++i) {
|
for (let i = 0; i < classes.length; ++i) {
|
||||||
const token = '.' + classes.slice(0, i + 1).join('.');
|
const token = '.' + classes.slice(0, i + 1).join('.');
|
||||||
const selector = uniqueCSSSelector(token);
|
const selector = uniqueCSSSelector(token);
|
||||||
|
|
@ -261,7 +261,7 @@ function cssFallback(injectedScript: InjectedScript, targetElement: Element): Se
|
||||||
|
|
||||||
// Ordinal is the weakest signal.
|
// Ordinal is the weakest signal.
|
||||||
if (parent) {
|
if (parent) {
|
||||||
const siblings = Array.from(parent.children);
|
const siblings = [...parent.children];
|
||||||
const sameTagSiblings = siblings.filter(sibling => (sibling).nodeName.toLowerCase() === nodeName);
|
const sameTagSiblings = siblings.filter(sibling => (sibling).nodeName.toLowerCase() === nodeName);
|
||||||
const token = sameTagSiblings.indexOf(element) === 0 ? nodeName : `${nodeName}:nth-child(${1 + siblings.indexOf(element)})`;
|
const token = sameTagSiblings.indexOf(element) === 0 ? nodeName : `${nodeName}:nth-child(${1 + siblings.indexOf(element)})`;
|
||||||
const selector = uniqueCSSSelector(token);
|
const selector = uniqueCSSSelector(token);
|
||||||
|
|
|
||||||
|
|
@ -74,3 +74,12 @@ it('should return complex values', async ({page, server}) => {
|
||||||
const texts = await page.$$eval('css=div', divs => divs.map(div => div.textContent));
|
const texts = await page.$$eval('css=div', divs => divs.map(div => div.textContent));
|
||||||
expect(texts).toEqual(['hello', 'beautiful', 'world!']);
|
expect(texts).toEqual(['hello', 'beautiful', 'world!']);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should work with bogus Array.from', async ({page, server}) => {
|
||||||
|
await page.setContent('<div>hello</div><div>beautiful</div><div>world!</div>');
|
||||||
|
await page.evaluate(() => {
|
||||||
|
Array.from = () => [];
|
||||||
|
});
|
||||||
|
const divsCount = await page.$$eval('css=div', divs => divs.length);
|
||||||
|
expect(divsCount).toBe(3);
|
||||||
|
});
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue