Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

waitForFileChooser + click race #6040

Closed
EmielM opened this issue Jun 18, 2020 · 4 comments · Fixed by #8905 or #8904
Closed

waitForFileChooser + click race #6040

EmielM opened this issue Jun 18, 2020 · 4 comments · Fixed by #8905 or #8904

Comments

@EmielM
Copy link

EmielM commented Jun 18, 2020

When "doing a tap and waiting for a file chooser", the docs suggest the following approach of using waitForFileChooser:

const [fileChooser] = await Promise.all([
  page.waitForFileChooser(),
  page.click('#upload-file-button'), // some button that triggers file selection
]);
await fileChooser.accept(['/tmp/myfile.pdf']);

This is very racy, as the click might basically happen before the Page.setInterceptFileChooserDialog call (setting up browser to track file chooser) to the browser is done.

Also the alternative form:

const fileChosen = page.waitForFileChooser();
await page.click('something');
await fileChosen;

suffers from the same. Again, the Page.setInterceptFileChooserDialog call might not be complete before sending over the click data.

The right order of things would be:

await page._client.send('Page.setInterceptFileChooserDialog', {enabled: 1})
let resolve;
const p = new Promise( (r) => resolve = r );
this._fileChooserInterceptors.add(resolve);
await page.click('something');
await p;

This is rather incompatible with the current signature of waitForFileChooser, as it would have to return 2 promises (or Promise of Promise). The first indicating setup went alright, the second indicating the file chooser has been launched.

(In our testing setup, we workaround this issue by doing an extra race-less await page._client.send('Page.setInterceptFileChooserDialog', {enabled: 1}) before using waitForFileChooser)

@EmielM
Copy link
Author

EmielM commented Jun 18, 2020

Update: after considering this a bit more: if chrome is guaranteed execute the received javascript in order, it might be enough to change registering our callback with the fileChooserInterceptors, before we await the enable call:

  async waitForFileChooser(
    options: { timeout?: number } = {}
  ): Promise<FileChooser> {
    const { timeout = this._timeoutSettings.timeout() } = options;
    let callback;
    const promise = new Promise<FileChooser>((x) => (callback = x));
    this._fileChooserInterceptors.add(callback);
    if (this._fileChooserInterceptors.size === 1) {
        // we were the first!
        await this._client.send('Page.setInterceptFileChooserDialog', {
            enabled: true,
        });
    }
    return ...;

@xpader
Copy link

xpader commented Jun 15, 2022

Sometimes get TimeoutError: waiting for waiting for file chooser failed: timeout 10000ms exceeded, it this related to current issue?

@stale
Copy link

stale bot commented Aug 14, 2022

We're marking this issue as unconfirmed because it has not had recent activity and we weren't able to confirm it yet. It will be closed if no further activity occurs within the next 30 days.

@mohammed-a-hamdy
Copy link

Same

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
4 participants