mirror of
https://github.com/puppeteer/puppeteer
synced 2024-06-14 14:02:48 +00:00
fix: parse empty options in <select> (#8489)
This commit is contained in:
parent
f64ec2051b
commit
b30f3f44cd
@ -263,8 +263,8 @@ export class JSHandle<HandleObjectType = unknown> {
|
|||||||
*/
|
*/
|
||||||
asElement(): ElementHandle | null {
|
asElement(): ElementHandle | null {
|
||||||
/* This always returns null, but subclasses can override this and return an
|
/* This always returns null, but subclasses can override this and return an
|
||||||
ElementHandle.
|
ElementHandle.
|
||||||
*/
|
*/
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -766,7 +766,7 @@ export class ElementHandle<
|
|||||||
* one is taken into account.
|
* one is taken into account.
|
||||||
*/
|
*/
|
||||||
async select(...values: string[]): Promise<string[]> {
|
async select(...values: string[]): Promise<string[]> {
|
||||||
for (const value of values)
|
for (const value of values) {
|
||||||
assert(
|
assert(
|
||||||
helper.isString(value),
|
helper.isString(value),
|
||||||
'Values must be strings. Found value "' +
|
'Values must be strings. Found value "' +
|
||||||
@ -775,26 +775,38 @@ export class ElementHandle<
|
|||||||
typeof value +
|
typeof value +
|
||||||
'"'
|
'"'
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return this.evaluate<(element: Element, values: string[]) => string[]>(
|
return this.evaluate((element: Element, vals: string[]): string[] => {
|
||||||
(element, values) => {
|
const values = new Set(vals);
|
||||||
if (!(element instanceof HTMLSelectElement))
|
if (!(element instanceof HTMLSelectElement)) {
|
||||||
throw new Error('Element is not a <select> element.');
|
throw new Error('Element is not a <select> element.');
|
||||||
|
}
|
||||||
|
|
||||||
const options = Array.from(element.options);
|
const selectedValues = new Set<string>();
|
||||||
element.value = '';
|
if (!element.multiple) {
|
||||||
for (const option of options) {
|
for (const option of element.options) {
|
||||||
option.selected = values.includes(option.value);
|
option.selected = false;
|
||||||
if (option.selected && !element.multiple) break;
|
|
||||||
}
|
}
|
||||||
element.dispatchEvent(new Event('input', { bubbles: true }));
|
for (const option of element.options) {
|
||||||
element.dispatchEvent(new Event('change', { bubbles: true }));
|
if (values.has(option.value)) {
|
||||||
return options
|
option.selected = true;
|
||||||
.filter((option) => option.selected)
|
selectedValues.add(option.value);
|
||||||
.map((option) => option.value);
|
break;
|
||||||
},
|
}
|
||||||
values
|
}
|
||||||
);
|
} else {
|
||||||
|
for (const option of element.options) {
|
||||||
|
option.selected = values.has(option.value);
|
||||||
|
if (option.selected) {
|
||||||
|
selectedValues.add(option.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
element.dispatchEvent(new Event('input', { bubbles: true }));
|
||||||
|
element.dispatchEvent(new Event('change', { bubbles: true }));
|
||||||
|
return [...selectedValues.values()];
|
||||||
|
}, values);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -845,9 +857,9 @@ export class ElementHandle<
|
|||||||
const { backendNodeId } = node;
|
const { backendNodeId } = node;
|
||||||
|
|
||||||
/* The zero-length array is a special case, it seems that
|
/* The zero-length array is a special case, it seems that
|
||||||
DOM.setFileInputFiles does not actually update the files in that case,
|
DOM.setFileInputFiles does not actually update the files in that case,
|
||||||
so the solution is to eval the element value to a new FileList directly.
|
so the solution is to eval the element value to a new FileList directly.
|
||||||
*/
|
*/
|
||||||
if (files.length === 0) {
|
if (files.length === 0) {
|
||||||
await (this as ElementHandle<HTMLInputElement>).evaluate((element) => {
|
await (this as ElementHandle<HTMLInputElement>).evaluate((element) => {
|
||||||
element.files = new DataTransfer().files;
|
element.files = new DataTransfer().files;
|
||||||
@ -1300,8 +1312,8 @@ export interface Point {
|
|||||||
|
|
||||||
function computeQuadArea(quad: Point[]): number {
|
function computeQuadArea(quad: Point[]): number {
|
||||||
/* Compute sum of all directed areas of adjacent triangles
|
/* Compute sum of all directed areas of adjacent triangles
|
||||||
https://en.wikipedia.org/wiki/Polygon#Simple_polygons
|
https://en.wikipedia.org/wiki/Polygon#Simple_polygons
|
||||||
*/
|
*/
|
||||||
let area = 0;
|
let area = 0;
|
||||||
for (let i = 0; i < quad.length; ++i) {
|
for (let i = 0; i < quad.length; ++i) {
|
||||||
const p1 = quad[i]!;
|
const p1 = quad[i]!;
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<select>
|
<select>
|
||||||
|
<option value="">Empty</option>
|
||||||
<option value="black">Black</option>
|
<option value="black">Black</option>
|
||||||
<option value="blue">Blue</option>
|
<option value="blue">Blue</option>
|
||||||
<option value="brown">Brown</option>
|
<option value="brown">Brown</option>
|
||||||
|
@ -1887,12 +1887,13 @@ describe('Page', function () {
|
|||||||
await page.select('select', 'blue', 'black', 'magenta');
|
await page.select('select', 'blue', 'black', 'magenta');
|
||||||
await page.select('select');
|
await page.select('select');
|
||||||
expect(
|
expect(
|
||||||
await page.$eval('select', (select: HTMLSelectElement) =>
|
await page.$eval(
|
||||||
Array.from(select.options).every(
|
'select',
|
||||||
(option: HTMLOptionElement) => !option.selected
|
(select: HTMLSelectElement) =>
|
||||||
)
|
Array.from(select.options).filter((option) => option.selected)[0]
|
||||||
|
.value
|
||||||
)
|
)
|
||||||
).toEqual(true);
|
).toEqual('');
|
||||||
});
|
});
|
||||||
it('should throw if passed in non-strings', async () => {
|
it('should throw if passed in non-strings', async () => {
|
||||||
const { page } = getTestState();
|
const { page } = getTestState();
|
||||||
|
Loading…
Reference in New Issue
Block a user