-
Notifications
You must be signed in to change notification settings - Fork 9.4k
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
core(tsc): add type checking to remote protocol commands #4914
Conversation
@@ -656,11 +637,9 @@ class Driver { | |||
return this._isolatedExecutionContextId; | |||
} | |||
|
|||
/** @type {LH.Crdp.Page.GetResourceTreeResponse} */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typed responses lets us get rid of a lot of these explicit types :)
lighthouse-core/lib/emulation.js
Outdated
@@ -86,7 +86,7 @@ function enableNexus5X(driver) { | |||
// Network.enable must be called for UA overriding to work | |||
driver.sendCommand('Network.enable'), | |||
driver.sendCommand('Network.setUserAgentOverride', NEXUS5X_USERAGENT), | |||
driver.sendCommand('Emulation.setTouchEmulationEnabled', { | |||
driver.sendCommand('Page.setTouchEmulationEnabled', { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
first real bug caught with type checks? Haven't confirmed that it was a problem, but there is both Emulation.setTouchEmulationEnabled
and Page.setTouchEmulationEnabled
, but only the Page
one takes these params
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ha! yeah I think this might have been a small bug that normally didn't matter.
I think we want Emulation.setEmitTouchEventsForMouse
instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
seems like you're fixing this in a separate PR?
can you write up the list of changes that are on their way?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sorry, I can fix this :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
coool beans 😎
* params object. | ||
*/ | ||
export type SendCommand = { | ||
<C extends VoidParamsKeys>(method: C, params?: void, cmdOpts?: {silent?: boolean}): Promise<CrdpCommands[C]['returnType']>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
a little unfortunate that types make us do an extends
and we can't do in
lighthouse-core/gather/driver.js
Outdated
@@ -809,11 +785,9 @@ class Driver { | |||
* @return {Promise<Array<Element>>} The found elements, or [], resolved in a promise | |||
*/ | |||
async querySelectorAll(selector) { | |||
/** @type {LH.Crdp.DOM.GetDocumentResponse} */ | |||
const documentResponse = await this.sendCommand('DOM.getDocument'); | |||
const documentResponse = await this.sendCommand('DOM.getDocument', {}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought the | void
would let us omit the parameters if they're all optional?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
whoops, yes, those were from an earlier version of the PR
@@ -111,7 +98,7 @@ class Connection { | |||
// just log these occurrences. | |||
const error = object.error && object.error.message; | |||
log.formatProtocol(`disowned method <= browser ${error ? 'ERR' : 'OK'}`, | |||
{method: object.method, params: error || object.result}, 'verbose'); | |||
{method: 'UNKNOWN', params: error || object.result}, 'verbose'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do we not get back a method from disowned messages? seems like || 'UNKOWN'
would work if we do :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do we not get back a method from disowned messages?
we can check on the Chrome side if it's possible, but I did a bunch of runs watching the properties of all messages sent back over the protocol and never got a method
on a non-event response
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the .d.ts is now in the devtools-protocol
package: https://cdn.jsdelivr.net/npm/devtools-protocol@0.0.547074/types/protocol.d.ts
want to switch to that and off of vscode-chrome-debug-core?
lighthouse-core/lib/emulation.js
Outdated
@@ -86,7 +86,7 @@ function enableNexus5X(driver) { | |||
// Network.enable must be called for UA overriding to work | |||
driver.sendCommand('Network.enable'), | |||
driver.sendCommand('Network.setUserAgentOverride', NEXUS5X_USERAGENT), | |||
driver.sendCommand('Emulation.setTouchEmulationEnabled', { | |||
driver.sendCommand('Page.setTouchEmulationEnabled', { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ha! yeah I think this might have been a small bug that normally didn't matter.
I think we want Emulation.setEmitTouchEventsForMouse
instead.
* @param {string} domainName | ||
* @return {Map<string, {paramsType: string, returnType: string}>} | ||
*/ | ||
function getCommandMap(sourceRoot, domainName) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do you want to upstream all this into devtools-protocol
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do you want to upstream all this into devtools-protocol?
the event map (just 'Domain.eventName': Crdp.EventPayloadType
) I think could easily live upstream, it's so simple. The command map seems more specialized to our use case, so I'm not sure. We could propose it to everyone involved in ChromeDevTools/devtools-protocol#90 and see what they think
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cc @@JoelEinbinder whatchu think homeboy
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
he sounded 👍 for upstreaming (if not for using in pptr)
yeah, it was just going to require changes to this and the previous event stuff because they changed the structure a bit. I was going to do that in a quick follow up PR. |
yah? |
lighthouse-core/lib/emulation.js
Outdated
@@ -86,7 +86,7 @@ function enableNexus5X(driver) { | |||
// Network.enable must be called for UA overriding to work | |||
driver.sendCommand('Network.enable'), | |||
driver.sendCommand('Network.setUserAgentOverride', NEXUS5X_USERAGENT), | |||
driver.sendCommand('Emulation.setTouchEmulationEnabled', { | |||
driver.sendCommand('Page.setTouchEmulationEnabled', { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
seems like you're fixing this in a separate PR?
can you write up the list of changes that are on their way?
I believe the only (direct) next steps are to
|
@patrickhulce also gave the 👍 |
This PR adds type checking/inference for
Driver.sendCommand
(to go along with typing events in #4886).Like #4886, this PR has changes to
scripts/extract-crdp-mapping.js
to extract all the protocol commands which are then written totypings/crdp-mapping.d.ts
. Again, hopefully most of this can be upstreamed intodevtools-protocol
. This time the types need both the optionsparams
object (if any) associated with the command but also the command's return type (if any).The other set of changes are in
Driver
,Connection
, andExtensionConnection
(everything else is just minor fixes for any type errors that popped up after all the above changes). This timesendCommand
is pulled out of the class bodies for stricter typing. Getting the typing correct is a little harder than it was for the events because this time we aren't tying together an event name and payload type, but two function parameters and a return type.Typescript types (in typescript or jsdoc) can express that one property of an object is defined only for certain values of a different property (or similarly, for an event payload in a callback and an event name), but typescript can't yet express that a function parameter is not to be provided depending on the value of another parameter (there's a proposal to enable this, which is now on the typescript roadmap, but under the "Future" heading with no planned implementation schedule).
As a result, the solution is a little more awkward, but not too bad. The function is defined with somewhat loose argument types, but when added to the class prototype it's cast to a much stricter type as the external interface. This allows casting with an overloaded type signature, which can create a one argument version (for commands like
DOM.enable
) or a two argument version so options can be passed (for e.g.DOM.querySelector
), depending on the first argument (the command string).One last wrinkle: for commands that have all optional options that we don't use, we have often just dropped the second argument when calling (e.g. for
Network.enable
). I've addedvoid
as one option for theparams
object for those commands, so they actually show up in both the one and two argument versions ofsendCommand