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

Functions bound with page.exposeFunction() produce unhandled promise rejections #3549

Closed
mnmkng opened this issue Nov 15, 2018 · 2 comments
Closed

Comments

@mnmkng
Copy link
Contributor

mnmkng commented Nov 15, 2018

Hello everyone,

this may or may not be an issue, we're using page.exposeFunction() to expose certain APIs to the browser context and from our observations, any error thrown within the APIs turns into an unhandled promise rejection. This is due to the implementation of the .onBindingCalled() handler in Page.

See https://github.com/GoogleChrome/puppeteer/blob/c185eeef6119141ebc07f07d46ae0dcb16a555f3/lib/Page.js#L514

From my observation, exceptions thrown within the _pageBindings function call are not handled in any way and since the .onBindingCalled() function is used as a callback, the resulting rejected promises cannot be handled.

Is this a bug or intended behavior?

Steps to reproduce

Tell us about your environment:

  • Puppeteer version: 1.9.0
  • Platform / OS version: MacOS 10.14 locally; node:8-slim (Debian Jessie) remotely;
  • Node.js version: 8.12.0

What steps will reproduce the problem?

The very minimal reproduction code looks like this:

const puppeteer = require('puppeteer');

puppeteer.launch()
.then(async browser => {
  const page = await browser.newPage();
  await page.exposeFunction('func', async () => {
    throw new Error('err');
  });
  await page.evaluate(async () => {
    const content = await window.func();
  });
  await browser.close();
}).catch(err => console.log('does not get called'));

The same issue would also manifest in the page.exposeFunction() examples, where a rejection of the readFile Promise would produce an unhandled rejection.

const puppeteer = require('puppeteer');
const fs = require('fs');

puppeteer.launch().then(async browser => {
  const page = await browser.newPage();
  page.on('console', msg => console.log(msg.text()));
  await page.exposeFunction('readfile', async filePath => {
    return new Promise((resolve, reject) => {
      fs.readFile(filePath, 'utf8', (err, text) => {
        if (err)
          reject(err);
        else
          resolve(text);
      });
    });
  });
  await page.evaluate(async () => {
    // use window.readfile to read contents of a file
    const content = await window.readfile('/etc/hosts');
    console.log(content);
  });
  await browser.close();
});

What is the expected result?
I would expect the exceptions thrown from the bound functions to be manageable in some way. Either by allowing a handler to be attached to the page.exposeFunction() call or by backpropagating the errors back to the Browser context so that the Promise there gets rejected with a representation of the exception thrown in Node context.

We implemented those two options manually in our code.

What happens instead?
An unhandled promise rejection is produced.

Thank you for your time.

@mnmkng mnmkng changed the title page.exposeFunction() bindings produce unhandled promise rejections Functions bound with page.exposeFunction() produce unhandled promise rejections Nov 15, 2018
aslushnikov added a commit to aslushnikov/puppeteer that referenced this issue Nov 15, 2018
Errors thrown on the node side of the `page.exposeFunction` callback
should be dispatched into the page.

Fixes puppeteer#3549
@aslushnikov
Copy link
Contributor

@mnmkng that's a bug. Errors should be dispatched into the page context; fix is on its way.

aslushnikov added a commit that referenced this issue Nov 15, 2018
Errors thrown on the node side of the `page.exposeFunction` callback
should be dispatched into the page.

Fixes #3549
@mnmkng
Copy link
Contributor Author

mnmkng commented Nov 16, 2018

@aslushnikov Thank you for the quick fix.

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

No branches or pull requests

2 participants