-
Notifications
You must be signed in to change notification settings - Fork 9.6k
core(driver): wait for Page.frameNavigated for about:blank #6446
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -496,6 +496,16 @@ class Driver { | |
| }); | ||
| } | ||
|
|
||
| /** | ||
| * Returns a promise that resolve when a frame has been navigated. | ||
| * Used for detecting that our about:blank reset has been completed. | ||
| */ | ||
| _waitForFrameNavigated() { | ||
| return new Promise(resolve => { | ||
| this.once('Page.frameNavigated', resolve); | ||
| }); | ||
| } | ||
|
|
||
| /** | ||
| * Returns a promise that resolves when the network has been idle (after DCL) for | ||
| * `networkQuietThresholdMs` ms and a method to cancel internal network listeners/timeout. | ||
|
|
@@ -824,14 +834,19 @@ class Driver { | |
| * possible workaround. | ||
| * Resolves on the url of the loaded page, taking into account any redirects. | ||
| * @param {string} url | ||
| * @param {{waitForLoad?: boolean, passContext?: LH.Gatherer.PassContext}} options | ||
| * @param {{waitForLoad?: boolean, waitForNavigated?: boolean, passContext?: LH.Gatherer.PassContext}} options | ||
| * @return {Promise<string>} | ||
| */ | ||
| async gotoURL(url, options = {}) { | ||
| const waitForNavigated = options.waitForNavigated || false; | ||
| const waitForLoad = options.waitForLoad || false; | ||
| const passContext = /** @type {Partial<LH.Gatherer.PassContext>} */ (options.passContext || {}); | ||
| const disableJS = passContext.disableJavaScript || false; | ||
|
|
||
| if (waitForNavigated && waitForLoad) { | ||
| throw new Error('Cannot use both waitForNavigated and waitForLoad, pick just one'); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 😆 |
||
| } | ||
|
|
||
| await this._beginNetworkStatusMonitoring(url); | ||
| await this._clearIsolatedContextId(); | ||
|
|
||
|
|
@@ -843,6 +858,10 @@ class Driver { | |
| this.setNextProtocolTimeout(30 * 1000); | ||
| this.sendCommand('Page.navigate', {url}); | ||
|
|
||
| if (waitForNavigated) { | ||
| await this._waitForFrameNavigated(); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. any concerns about racing here? i.e. should we get the promise before
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. also, any concerns about delaying
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. dgozman convinced me that so long as the listener is attached synchronously (which it is inside Longer explanation was that the earliest possible resolution of the promise would be the next microtask and because the listener is installed before that microtask is executed there's no way to miss the event
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
definitely, they should not be used together I'll add a throw
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
yeahhhh, good point. As long as no one sticks an |
||
| } | ||
|
|
||
| if (waitForLoad) { | ||
| const passConfig = /** @type {Partial<LH.Config.Pass>} */ (passContext.passConfig || {}); | ||
| let {pauseAfterLoadMs, networkQuietThresholdMs, cpuQuietThresholdMs} = passConfig; | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -68,18 +68,12 @@ class GatherRunner { | |
| * never fired on it. | ||
| * @param {Driver} driver | ||
| * @param {string=} url | ||
| * @param {number=} duration | ||
| * @return {Promise<void>} | ||
| */ | ||
| static async loadBlank( | ||
| driver, | ||
| url = constants.defaultPassConfig.blankPage, | ||
| duration = constants.defaultPassConfig.blankDuration | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I forget when we've actually used a different
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. tests and once upon a time WPT used it for video recording, but for past year or so he's just run LH straight outta the box |
||
| ) { | ||
| static async loadBlank(driver, url = constants.defaultPassConfig.blankPage) { | ||
| const status = {msg: 'Resetting state with about:blank', id: 'lh:gather:loadBlank'}; | ||
| log.time(status); | ||
| await driver.gotoURL(url); | ||
| await new Promise(resolve => setTimeout(resolve, duration)); | ||
| await driver.gotoURL(url, {waitForNavigated: true}); | ||
| log.timeEnd(status); | ||
| } | ||
|
|
||
|
|
@@ -458,7 +452,7 @@ class GatherRunner { | |
| await driver.setThrottling(options.settings, passConfig); | ||
| if (!isFirstPass) { | ||
| // Already on blank page if driver was just set up. | ||
| await GatherRunner.loadBlank(driver, passConfig.blankPage, passConfig.blankDuration); | ||
| await GatherRunner.loadBlank(driver, passConfig.blankPage); | ||
| } | ||
| await GatherRunner.beforePass(passContext, gathererResults); | ||
| await GatherRunner.pass(passContext, gathererResults); | ||
|
|
||
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.
at some point we should add a driver method that wraps
oncewith a promise. Seems like a lot of our uses of it end up like this