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

feat(executioncontext): warn on nested js handle #3591

Merged
merged 6 commits into from Jan 14, 2019

Conversation

bgschiller
Copy link
Contributor

ExecutionContext.evaluateHandle accepts arguments that are either
serializable, or JSHandles. A potential confusion is that it does not
accept arguments that contain JSHandles.

This patch adds a log message warning when it encounters that situation.

Fixes #3562

ExecutionContext.evaluateHandle accepts arguments that are either
serializable, or JSHandles. A potential confusion is that it *does not*
accept arguments that *contain* JSHandles.

This patch adds a log message warning when it encounters that situation.

Fixes puppeteer#3562
@SimonSchick
Copy link

I don't know if that's a good thing to do, if anything this should re-throw as another error, emitting warnings on incorrect usage that should result in errors doesn't make much sense.

I think it would be sufficient to alter the error message eg. err.message += ' Are you passing a nested JSHandle?'

@aslushnikov
Copy link
Contributor

I like @SimonSchick suggestion - that's the right amount of code/effort for the problem we're having.

@bgschiller
Copy link
Contributor Author

Sounds good, I'll make that change and push an update

remove the code checking if args contain a nested JSHandle, and
instead simply suggest the possibility.
Copy link

@SimonSchick SimonSchick left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is better but I'm still unsure if this sort of validation is the right way to do at all.
There are probably hundreds possible ways to pass bad data into puppeteer and make it give obscure errors, that's (to some degree) due to the nature of JS.

If you want actual type safety, you want to go with something like TypeScript.

userGesture: true
});
} catch (err) {
err.message += ' Are you passing a nested JSHandle?';

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You do want to check if it's a TypeError still.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, right. I'll add that back.

@bgschiller
Copy link
Contributor Author

@SimonSchick, I'd absolutely prefer to lean on the type system for this. I actually am using Typescript, but I don't get an error in this case. Looking at puppeteer/index.d.ts, I see the following definition:

evaluateHandle(
  fn: EvaluateFn,
  ...args: any[]
): Promise<JSHandle>;

Even though args is documented as being Serializable | JSHandle, the type definitions don't include that information.

I'm pretty new to Typescript, but I'm not aware of a way to specify that arguments be serializable. Maybe you can point me in the right direction? Is there a built-in type I'm missing, or would it involve a definition something like this?

type Serializable = number | boolean | string | { [key: string]: Serializable } | Serializable[];

Copy link
Contributor

@aslushnikov aslushnikov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks; can you please also add a test?

userGesture: true
});
} catch (err) {
if (err instanceof TypeError && err.message === 'Converting circular structure to JSON')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this error happens due to convertArgument call. Let's scope it down to this:

try {
  args = args.map(convertArgument.bind(this));
} catch (err) {
  if (err instanceof TypeError && err.message === 'Converting circular structure to JSON')
    err.message += ' Are you passing a nested JSHandle?';
  throw err;
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately, the error actually happens after convertArgument, in CDPSession.send. It looks like convertArgument prepares the args for serialization, but the call to JSON.stringify is later on.

@@ -162,6 +169,7 @@ class ExecutionContext {
throw new Error('Execution context was destroyed, most likely because of a navigation.');
throw error;
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: stray line

@bgschiller
Copy link
Contributor Author

As far as I can tell, test failures are either unrelated (1) Browser Page Workers Page.workers (worker.spec.js:8:5)) or due to linting in files I haven't edited. Do I need to rebase/merge a more recent commit?

Also, I learned how to write a "Serializable" type, so I'm intending to submit a PR to DefinitelyTyped as well.

Copy link
Contributor

@aslushnikov aslushnikov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome, thanks!

@aslushnikov aslushnikov changed the title feat(ExecutionContext): warn on nested js handle feat(executioncontext): warn on nested js handle Jan 14, 2019
@aslushnikov aslushnikov merged commit 7fabf32 into puppeteer:master Jan 14, 2019
PranavSenthilnathan pushed a commit to DefinitelyTyped/DefinitelyTyped that referenced this pull request Jan 31, 2019
page.evaluate and similar functions are currently typed as if
they accept 'any' args, but they will throw exceptions unless
the args are either Serializable (with JSON.stringify) or JSHandles.

In puppeteer/puppeteer#3591, @SimonSchick recommended that tighter
type definitions was a preferable way to address this rather than
runtime error checking.

I've been using these updated types in my project for the last couple of
months without problem.

I suspect that some of the X1, X2 type parameters should also
be changed to reflect that they can only be SerializableOrJSHandle,
but I wasn't sure how to change the existing UnwrapElementHandle<X1>
types.
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

Successfully merging this pull request may close these issues.

None yet

3 participants