fix: update file chooser events (#11057)

This commit is contained in:
jrandolf 2023-10-06 08:28:19 +02:00 committed by GitHub
parent eb99509a3a
commit 317f82055b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 30 additions and 18 deletions

View File

@ -10,10 +10,10 @@ Closes the file chooser without selecting any files.
```typescript ```typescript
class FileChooser { class FileChooser {
cancel(): void; cancel(): Promise<void>;
} }
``` ```
**Returns:** **Returns:**
void Promise&lt;void&gt;

View File

@ -133,31 +133,38 @@ export class CdpElementHandle<
return path.resolve(filePath); return path.resolve(filePath);
} }
}); });
const {node} = await this.client.send('DOM.describeNode', {
objectId: this.id,
});
const {backendNodeId} = node;
/* The zero-length array is a special case, it seems that /**
DOM.setFileInputFiles does not actually update the files in that case, * The zero-length array is a special case, it seems that
so the solution is to eval the element value to a new FileList directly. * 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.
*/ */
if (files.length === 0) { if (files.length === 0) {
// XXX: These events should converted to trusted events. Perhaps do this
// in `DOM.setFileInputFiles`?
await this.evaluate(element => { await this.evaluate(element => {
element.files = new DataTransfer().files; element.files = new DataTransfer().files;
// Dispatch events for this case because it should behave akin to a user action. // Dispatch events for this case because it should behave akin to a user action.
element.dispatchEvent(new Event('input', {bubbles: true})); element.dispatchEvent(
new Event('input', {bubbles: true, composed: true})
);
element.dispatchEvent(new Event('change', {bubbles: true})); element.dispatchEvent(new Event('change', {bubbles: true}));
}); });
} else { return;
}
const {
node: {backendNodeId},
} = await this.client.send('DOM.describeNode', {
objectId: this.id,
});
await this.client.send('DOM.setFileInputFiles', { await this.client.send('DOM.setFileInputFiles', {
objectId: this.id, objectId: this.id,
files, files,
backendNodeId, backendNodeId,
}); });
} }
}
@throwIfDisposed() @throwIfDisposed()
override async autofill(data: AutofillData): Promise<void> { override async autofill(data: AutofillData): Promise<void> {

View File

@ -87,11 +87,16 @@ export class FileChooser {
/** /**
* Closes the file chooser without selecting any files. * Closes the file chooser without selecting any files.
*/ */
cancel(): void { async cancel(): Promise<void> {
assert( assert(
!this.#handled, !this.#handled,
'Cannot cancel FileChooser which is already handled!' 'Cannot cancel FileChooser which is already handled!'
); );
this.#handled = true; this.#handled = true;
// XXX: These events should converted to trusted events. Perhaps do this
// in `DOM.setFileInputFiles`?
await this.#element.evaluate(element => {
element.dispatchEvent(new Event('cancel', {bubbles: true}));
});
} }
} }

View File

@ -358,7 +358,7 @@ describe('input tests', function () {
let error!: Error; let error!: Error;
try { try {
fileChooser.cancel(); await fileChooser.cancel();
} catch (error_) { } catch (error_) {
error = error_ as Error; error = error_ as Error;
} }